using adas_core.Application.Exceptions;
using adas_core.Application.Services.Interfaces;
using adas_core.Authentication.Attributes;
using adas_core.Domain.Enums;
using adas_core.Domain.Models.MongoModels;
using adas_core.Logging;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Bson;

namespace adas_core.Controllers;

[Route("admissions")]
[ApiController]
public class AdmissionController : ControllerBase
{
    private readonly IAdmissionService _admissionService;
    private readonly ILogger<AdmissionController> _logger;
    private readonly IPatientService _patientService;
    private readonly IUnitService _unitService;

    public AdmissionController(ILogger<AdmissionController> logger, IAdmissionService admissionService,
        IPatientService patientService, IUnitService unitService)
    {
        LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);

        _logger = logger;
        _admissionService = admissionService;
        _patientService = patientService;
        _unitService = unitService;
    }

    [HttpGet]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetAllAdmissions()
    {
        var admissions = await _admissionService.GetAdmissionsAsync();

        return Ok(admissions);
    }

    [HttpGet("{id}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetAdmissionbyId(string id)
    {
        if (!ObjectId.TryParse(id, out var admissionId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var admission = await _admissionService.GetAdmissionByIdAsync(admissionId);
        if (admission != null) return Ok(admission);

        _logger.LogDebug("Admission id: {id} not Found", id);

        throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing);
    }

    [HttpPost]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> CreateNewAdmission([FromBody] Admission admission)
    {
        if (admission == null || string.IsNullOrEmpty(admission.Nhc))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var newAdmission = await _admissionService.InsertAdmission(admission);
        return Ok(newAdmission);
    }

    [HttpPut]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateAdmission([FromBody] Admission admission)
    {
        if (string.IsNullOrEmpty(admission.Nhc))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        await _admissionService.UpdateAdmissionAsync(admission);
        return Ok();
    }

    [HttpDelete("{id}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> DeleteAdmissionById(string id)
    {
        if (!ObjectId.TryParse(id, out var admissionId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var admission = await _admissionService.GetAdmissionByIdAsync(admissionId);
        if (admission == null) throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing);
        await _admissionService.DeleteAdmissionAsync(admission);
        return Ok();
    }

    [HttpPost("{id}/admission")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> AdmitPatient(string id)
    {
        if (!ObjectId.TryParse(id, out var admissionId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var admission = await _admissionService.GetAdmissionByIdAsync(admissionId);
        if (admission == null) throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing);


        var unitConfig = await _unitService.FindById(admission.UnitId);
        switch (unitConfig)
        {
            case null:
                throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing);
            case { Configuration.ManualAdmit: false }:
                throw new ConflictException(HttpEnum.ErrorMessage.ServiceUnavailableCensusInAutomaticMode);
        }

        await _admissionService.AdmitPatient(admission);
        var patient = await _patientService.FindByPatientNumber(admission.Nhc) ??
                      throw new ConflictException(HttpEnum.ErrorMessage.ConflictOperationIncompleted);
        return Ok(patient);
    }

    [HttpPost("admit/new-patient")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> AdmitNewPatient(Admission admission)
    {
        if (admission == null) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestMissingParameters);
        await _admissionService.UpdateAdmissionAsync(admission);

        var unitConfig = await _unitService.FindById(admission.UnitId);
        switch (unitConfig)
        {
            case null:
                throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing);
            case { Configuration.ManualAdmit: false }:
                throw new ConflictException(HttpEnum.ErrorMessage.ServiceUnavailableCensusInAutomaticMode);
        }

        await _admissionService.AdmitPatient(admission);
        var patient = await _patientService.FindByPatientNumber(admission.Nhc) ??
                      throw new ConflictException(HttpEnum.ErrorMessage.ConflictOperationIncompleted);
        return Ok(patient);
    }

    [HttpPost("{id}/patient-to-admission")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> ReturnPatientToAdmission(string id)
    {
        if (!ObjectId.TryParse(id, out var patientId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var patient = await _patientService.FindById(patientId);
        var unitConfig = await _unitService.FindById(patient!.UnitId);
        switch (unitConfig)
        {
            case null:
                throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing);
            case { Configuration.ManualMove: false }:
                throw new ConflictException(HttpEnum.ErrorMessage.ServiceUnavailableCensusInAutomaticMode);
            default:
                await _admissionService.ReturnPatientToAdmissions(patient.Id);
                return Ok();
        }
    }

    [HttpPost("{id}/temporal-bed")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> ReturnToAdmissionFromTemporalBed([FromBody] Admission admission, string id)
    {
        if (!ObjectId.TryParse(id, out var patientId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var patient = await _patientService.FindById(patientId);
        await _admissionService.ReturnPatientToAdmissions(patient!.Id, admission);
        return Ok();
    }

    [HttpGet("{patientNumber}/{unitId}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> ReturnPatientToAdmission(string patientNumber, string unitId)
    {
        if (!ObjectId.TryParse(unitId, out var unitObjectId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        return Ok(await _admissionService.SearchByPatientNumberAndDistinctUnit(patientNumber, unitObjectId));
    }
}