using Hl7.Fhir.Model;
using Microsoft.Extensions.Options;


public class EncounterFhirMapper
{
    private readonly FhirReferenceResolver _refs;
    private readonly FhirOptions _options;

    public EncounterFhirMapper(FhirReferenceResolver refs, IOptions<FhirOptions> options)
    {
        _refs = refs;
        _options = options.Value;
    }

    public async Task<FhirEncounterUpsertRequest> ToUpsertRequestAsync(Hl7.Fhir.Model.Encounter fhir)
    {
        var identifier = _refs.ExtractPrimaryIdentifier(fhir, _options.EncounterIdentifierSystems)
            ?? throw new FhirMappingException("Encounter must include at least one identifier.", "required");

        if (fhir.Subject is null)
            throw new FhirMappingException("Encounter subject is required.", "required");

        var patientId = await _refs.ResolvePatientReferenceAsync(fhir.Subject);

        var actCode = fhir.Class?.Code ?? "IMP";
        if (!_options.EncounterClassMap.TryGetValue(actCode, out var encounterTypeStr))
            encounterTypeStr = _options.DefaultEncounterType;

        var departmentStr = _options.DefaultDepartment;
        var locationCode = fhir.Location?.FirstOrDefault()?.Location?.Display;
        if (locationCode is not null)
        {
            foreach (var (key, value) in _options.DepartmentCodeMap)
            {
                if (locationCode.Contains(key, StringComparison.OrdinalIgnoreCase))
                {
                    departmentStr = value;
                    break;
                }
            }
        }

        var attending = fhir.Participant?
            .FirstOrDefault(p => p.Type?.Any(t =>
                t.Coding?.Any(c => c.Code == "ATND") == true) == true)
            ?.Individual?.Display ?? "Unknown";

        var targetStatus = fhir.Status switch
        {
            Hl7.Fhir.Model.Encounter.EncounterStatus.Finished => EncounterStatus.Discharged,
            Hl7.Fhir.Model.Encounter.EncounterStatus.Cancelled => EncounterStatus.Cancelled,
            _ => EncounterStatus.Active
        };

        return new FhirEncounterUpsertRequest(
            IdentifierSystem: identifier.System,
            IdentifierValue: identifier.Value,
            PatientId: patientId,
            EncounterType: EncounterTypeExtensions.FromDbString(encounterTypeStr),
            Department: DepartmentExtensions.FromDbString(departmentStr),
            AttendingPhysician: attending,
            TargetStatus: targetStatus,
            AdmittedAt: fhir.Period?.StartElement?.ToDateTimeOffset(TimeSpan.Zero),
            RoomBed: fhir.Location?.FirstOrDefault()?.Location?.Display,
            AdmissionReason: fhir.ReasonCode?.FirstOrDefault()?.Text);
    }

    public Hl7.Fhir.Model.Encounter ToFhirResponse(Encounter encounter, (string System, string Value)? hospitalId)
    {
        var resource = new Hl7.Fhir.Model.Encounter
        {
            Id = encounter.Id.ToString(),
            Status = encounter.Status switch
            {
                EncounterStatus.Active     => Hl7.Fhir.Model.Encounter.EncounterStatus.InProgress,
                EncounterStatus.Discharged => Hl7.Fhir.Model.Encounter.EncounterStatus.Finished,
                EncounterStatus.Cancelled  => Hl7.Fhir.Model.Encounter.EncounterStatus.Cancelled,
                _                          => Hl7.Fhir.Model.Encounter.EncounterStatus.Unknown
            },
            Class = new Coding("http://terminology.hl7.org/CodeSystem/v3-ActCode", "IMP"),
            Subject = new ResourceReference($"Patient/{encounter.PatientId}"),
            Identifier = new List<Identifier>()
        };

        if (hospitalId is not null)
        {
            resource.Identifier.Add(new Identifier
            {
                System = hospitalId.Value.System,
                Value = hospitalId.Value.Value
            });
        }

        resource.Identifier.Add(new Identifier
        {
            System = _options.InternalEncounterIdSystem,
            Value = encounter.Id.ToString()
        });

        return resource;
    }
}