using Hl7.Fhir.Model;

namespace Pgo.Backend.Models;

/// <summary>
/// Sterk vereenvoudigd viewmodel voor het tonen van een simulatie op levensloopdossier van een patiënt.
/// </summary>
public class DossierResponse
{
    public List<Patient> Patients { get; set; } = new();
    public List<AllergyIntolerance> AllergyIntolerances { get; set; } = new();
    public List<CarePlan> CarePlans { get; set; } = new();
    public List<CareTeam> CareTeams { get; set; } = new();
    public List<Composition> Compositions { get; set; } = new();
    public List<Condition> Conditions { get; set; } = new();
    public List<DiagnosticReport> DiagnosticReports { get; set; } = new();
    public List<DocumentManifest> DocumentManifests { get; set; } = new();
    public List<DocumentReference> DocumentReferences { get; set; } = new();
    public List<EpisodeOfCare> EpisodesOfCare { get; set; } = new();
    public List<Encounter> Encounters { get; set; } = new();
    public List<Flag> Flags { get; set; } = new();
    public List<Goal> Goals { get; set; } = new();
    public List<Immunization> Immunizations { get; set; } = new();
    public List<Medication> Medications { get; set; } = new();
    public List<MedicationAdministration> MedicationAdministrations { get; set; } = new();
    public List<MedicationDispense> MedicationDispenses { get; set; } = new();
    public List<MedicationRequest> MedicationRequests { get; set; } = new();
    public List<MedicationStatement> MedicationStatements { get; set; } = new();
    public List<Observation> Observations { get; set; } = new();
    public List<Organization> Organizations { get; set; } = new();
    public List<Practitioner> Practitioners { get; set; } = new();
    public List<Procedure> Procedures { get; set; } = new();
    public List<QuestionnaireResponse> QuestionnaireResponses { get; set; } = new();
    public List<OtherUnmapped> Others { get; set; } = new();

    public static DossierResponse Map(List<Resource>? resources)
    {
        var dossier = new DossierResponse();
        if (resources == null || resources.Count == 0)
        {
            return dossier;
        }

        foreach (var resource in resources)
        {
            switch (resource)
            {
                case Hl7.Fhir.Model.Patient patient:
                    dossier.Patients.Add(Patient.Map(patient));
                    break;

                case Hl7.Fhir.Model.AllergyIntolerance allergyIntolerance:
                    dossier.AllergyIntolerances.Add(AllergyIntolerance.Map(allergyIntolerance));
                    break;

                case Hl7.Fhir.Model.CarePlan carePlan:
                    dossier.CarePlans.Add(CarePlan.Map(carePlan));
                    break;

                case Hl7.Fhir.Model.CareTeam careTeam:
                    dossier.CareTeams.Add(CareTeam.Map(careTeam));
                    break;

                case Hl7.Fhir.Model.Composition composition:
                    dossier.Compositions.Add(Composition.Map(composition));
                    break;

                case Hl7.Fhir.Model.Condition condition:
                    dossier.Conditions.Add(Condition.Map(condition));
                    break;

                case Hl7.Fhir.Model.DiagnosticReport diagnosticReport:
                    dossier.DiagnosticReports.Add(DiagnosticReport.Map(diagnosticReport));
                    break;

                case Hl7.Fhir.Model.DocumentManifest documentManifest:
                    dossier.DocumentManifests.Add(DocumentManifest.Map(documentManifest));
                    break;

                case Hl7.Fhir.Model.DocumentReference documentReference:
                    dossier.DocumentReferences.Add(DocumentReference.Map(documentReference));
                    break;

                case Hl7.Fhir.Model.EpisodeOfCare episodeOfCare:
                    dossier.EpisodesOfCare.Add(EpisodeOfCare.Map(episodeOfCare));
                    break;

                case Hl7.Fhir.Model.Encounter encounter:
                    dossier.Encounters.Add(Encounter.Map(encounter));
                    break;

                case Hl7.Fhir.Model.Flag flag:
                    dossier.Flags.Add(Flag.Map(flag));
                    break;

                case Hl7.Fhir.Model.Goal goal:
                    dossier.Goals.Add(Goal.Map(goal));
                    break;

                case Hl7.Fhir.Model.Immunization immunization:
                    dossier.Immunizations.Add(Immunization.Map(immunization));
                    break;

                case Hl7.Fhir.Model.Medication medication:
                    dossier.Medications.Add(Medication.Map(medication));
                    break;

                case Hl7.Fhir.Model.MedicationAdministration medicationAdministration:
                    dossier.MedicationAdministrations.Add(MedicationAdministration.Map(medicationAdministration));
                    break;

                case Hl7.Fhir.Model.MedicationDispense medicationDispense:
                    dossier.MedicationDispenses.Add(MedicationDispense.Map(medicationDispense));
                    break;

                case Hl7.Fhir.Model.MedicationRequest medicationRequest:
                    dossier.MedicationRequests.Add(MedicationRequest.Map(medicationRequest));
                    break;

                case Hl7.Fhir.Model.MedicationStatement medicationStatement:
                    dossier.MedicationStatements.Add(MedicationStatement.Map(medicationStatement));
                    break;

                case Hl7.Fhir.Model.Observation observation:
                    dossier.Observations.Add(Observation.Map(observation));
                    break;

                case Hl7.Fhir.Model.Organization organization:
                    dossier.Organizations.Add(Organization.Map(organization));
                    break;

                case Hl7.Fhir.Model.Practitioner practitioner:
                    dossier.Practitioners.Add(Practitioner.Map(practitioner));
                    break;

                case Hl7.Fhir.Model.Procedure procedure:
                    dossier.Procedures.Add(Procedure.Map(procedure));
                    break;

                case Hl7.Fhir.Model.QuestionnaireResponse questionnaireResponse:
                    dossier.QuestionnaireResponses.Add(QuestionnaireResponse.Map(questionnaireResponse));
                    break;

                default:
                    dossier.Others.Add(OtherUnmapped.Map(resource));
                    break;
            }
        }

        return dossier;
    }

    public class AllergyIntolerance
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(AllergyIntolerance);
        public string? ClinicalStatus { get; set; }
        public string? VerificationStatus { get; set; }

        public static AllergyIntolerance Map(Hl7.Fhir.Model.AllergyIntolerance resource)
        {
            var clinicalStatus = resource.ClinicalStatus switch
            {
                Hl7.Fhir.Model.AllergyIntolerance.AllergyIntoleranceClinicalStatus.Active => "actief",
                Hl7.Fhir.Model.AllergyIntolerance.AllergyIntoleranceClinicalStatus.Inactive => "inactief",
                Hl7.Fhir.Model.AllergyIntolerance.AllergyIntoleranceClinicalStatus.Resolved => "opgelost",
                _ => resource.ClinicalStatus.ToString()
            };

            var verificationStatus = resource.VerificationStatus switch
            {
                Hl7.Fhir.Model.AllergyIntolerance.AllergyIntoleranceVerificationStatus.Confirmed => "bevestigd",
                Hl7.Fhir.Model.AllergyIntolerance.AllergyIntoleranceVerificationStatus.Refuted => "weerlegd",
                Hl7.Fhir.Model.AllergyIntolerance.AllergyIntoleranceVerificationStatus.Unconfirmed => "onbevestigd",
                _ => resource.VerificationStatus.ToString()
            };

            return new()
            {
                Id = resource.Id,
                ClinicalStatus = clinicalStatus,
                VerificationStatus = verificationStatus
            };
        }
    }

    public class CarePlan
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(CarePlan);
        public string? Status { get; set; }
        public string? Intent { get; set; }

        public static CarePlan Map(Hl7.Fhir.Model.CarePlan resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.CarePlan.CarePlanStatus.Active => "actief",
                Hl7.Fhir.Model.CarePlan.CarePlanStatus.Suspended => "onderbroken",
                Hl7.Fhir.Model.CarePlan.CarePlanStatus.Completed => "voltooid",
                Hl7.Fhir.Model.CarePlan.CarePlanStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            var intent = resource.Intent switch
            {
                Hl7.Fhir.Model.CarePlan.CarePlanIntent.Proposal => "voorstel",
                Hl7.Fhir.Model.CarePlan.CarePlanIntent.Plan => "plan",
                Hl7.Fhir.Model.CarePlan.CarePlanIntent.Order => "opdracht",
                Hl7.Fhir.Model.CarePlan.CarePlanIntent.Option => "optie",
                _ => resource.Intent.ToString()
            };

            return new()
            {
                Id = resource.Id,
                Status = status,
                Intent = intent
            };
        }
    }

    public class CareTeam
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(CareTeam);
        public string? Status { get; set; }

        public static CareTeam Map(Hl7.Fhir.Model.CareTeam resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.CareTeam.CareTeamStatus.Active => "actief",
                Hl7.Fhir.Model.CareTeam.CareTeamStatus.Suspended => "onderbroken",
                Hl7.Fhir.Model.CareTeam.CareTeamStatus.Inactive => "inactief",
                _ => resource.Status.ToString()
            };
            return new()
            {
                Id = resource.Id,
                Status = status
            };
        }
    }

    public class Composition
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(Composition);
        public string? Status { get; set; }
        public string? Author { get; set; }
        public string? Title { get; set; }
        public string? Subjectief { get; set; }
        public string? Objectief { get; set; }
        public string? Evaluatie { get; set; }
        public string? Plan { get; set; }

        public static Composition Map(Hl7.Fhir.Model.Composition resource)
        {
            var status = resource.Status switch
            {
                CompositionStatus.Preliminary => "voorlopig",
                CompositionStatus.Final => "definitief",
                CompositionStatus.Amended => "aangepast",
                CompositionStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            var subjectief = resource.Section?
                .Where(section => section.Code?.Coding?.Any(coding => coding.Code == "S") == true)
                .SelectMany(section => section.Entry)
                .Select(entry => entry.Display)
                .Where(display => !string.IsNullOrEmpty(display))
                .DefaultIfEmpty(string.Empty)
                .Aggregate((current, next) => current + ", " + next);

            var objectief = resource.Section?
                .Where(section => section.Code?.Coding?.Any(coding => coding.Code == "O") == true)
                .SelectMany(section => section.Entry)
                .Select(entry => entry.Display)
                .Where(display => !string.IsNullOrEmpty(display))
                .DefaultIfEmpty(string.Empty)
                .Aggregate((current, next) => current + ", " + next);

            var evaluatie = resource.Section?
                .Where(section => section.Code?.Coding?.Any(coding => coding.Code == "A" || coding.Code == "E") == true)
                .SelectMany(section => section.Entry)
                .Select(entry => entry.Display)
                .Where(display => !string.IsNullOrEmpty(display))
                .DefaultIfEmpty(string.Empty)
                .Aggregate((current, next) => current + ", " + next);

            var plan = resource.Section?
                .Where(section => section.Code?.Coding?.Any(coding => coding.Code == "P") == true)
                .SelectMany(section => section.Entry)
                .Select(entry => entry.Display)
                .Where(display => !string.IsNullOrEmpty(display))
                .DefaultIfEmpty(string.Empty)
                .Aggregate((current, next) => current + ", " + next);

            return new()
            {
                Id = resource.Id,
                Status = status,
                Author = resource.Author?.FirstOrDefault()?.Display,
                Title = resource.Title,
                Subjectief = subjectief,
                Objectief = objectief,
                Evaluatie = evaluatie,
                Plan = plan
            };
        }
    }

    public class Condition
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(Condition);
        public string? ClinicalStatus { get; set; }
        public string? VerificationStatus { get; set; }

        public static Condition Map(Hl7.Fhir.Model.Condition resource)
        {
            var clinicalStatus = resource.ClinicalStatus switch
            {
                Hl7.Fhir.Model.Condition.ConditionClinicalStatusCodes.Active => "actief",
                Hl7.Fhir.Model.Condition.ConditionClinicalStatusCodes.Inactive => "inactief",
                Hl7.Fhir.Model.Condition.ConditionClinicalStatusCodes.Resolved => "opgelost",
                _ => resource.ClinicalStatus.ToString()
            };

            var verificationStatus = resource.VerificationStatus switch
            {
                Hl7.Fhir.Model.Condition.ConditionVerificationStatus.Confirmed => "bevestigd",
                Hl7.Fhir.Model.Condition.ConditionVerificationStatus.Differential => "differentieel",
                Hl7.Fhir.Model.Condition.ConditionVerificationStatus.Refuted => "weerlegd",
                Hl7.Fhir.Model.Condition.ConditionVerificationStatus.Provisional => "voorlopig",
                Hl7.Fhir.Model.Condition.ConditionVerificationStatus.Unknown => "onbekend",
                _ => resource.VerificationStatus.ToString()
            };
            return new()
            {
                Id = resource.Id,
                ClinicalStatus = clinicalStatus,
                VerificationStatus = verificationStatus
            };
        }
    }

    public class DiagnosticReport
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(DiagnosticReport);
        public string? Status { get; set; }
        public string? Code { get; set; }

        public static DiagnosticReport Map(Hl7.Fhir.Model.DiagnosticReport resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.DiagnosticReport.DiagnosticReportStatus.Registered => "geregistreerd",
                Hl7.Fhir.Model.DiagnosticReport.DiagnosticReportStatus.Preliminary => "voorlopig",
                Hl7.Fhir.Model.DiagnosticReport.DiagnosticReportStatus.Final => "definitief",
                Hl7.Fhir.Model.DiagnosticReport.DiagnosticReportStatus.Amended => "aangepast",
                Hl7.Fhir.Model.DiagnosticReport.DiagnosticReportStatus.Corrected => "gecorrigeerd",
                Hl7.Fhir.Model.DiagnosticReport.DiagnosticReportStatus.Appended => "toegevoegd",
                Hl7.Fhir.Model.DiagnosticReport.DiagnosticReportStatus.Cancelled => "geannuleerd",
                Hl7.Fhir.Model.DiagnosticReport.DiagnosticReportStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };
            return new()
            {
                Id = resource.Id,
                Status = status,
                Code = resource.Code?.Text
            };
        }
    }

    public class DocumentManifest
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(DocumentManifest);
        public string? Status { get; set; }

        public static DocumentManifest Map(Hl7.Fhir.Model.DocumentManifest resource)
        {
            var status = resource.Status switch
            {
                DocumentReferenceStatus.Current => "huidig",
                DocumentReferenceStatus.Superseded => "vervangen",
                DocumentReferenceStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            return new()
            {
                Id = resource.Id,
                Status = status
            };
        }
    }

    public class DocumentReference
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(DocumentReference);
        public string? Status { get; set; }
        public string? Author { get; set; }
        public string? Custodian { get; set; }
        public string? Content { get; set; }
        public string? Context { get; set; }
        public string? Code { get; set; }
        public string? Period { get; set; }

        public static DocumentReference Map(Hl7.Fhir.Model.DocumentReference resource)
        {
            var status = resource.Status switch
            {
                DocumentReferenceStatus.Current => "huidig",
                DocumentReferenceStatus.Superseded => "vervangen",
                DocumentReferenceStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            return new()
            {
                Id = resource.Id,
                Status = status,
                Author = resource.Author?.FirstOrDefault()?.Display,
                Custodian = resource.Custodian?.Display,
                Content = resource.Content?.FirstOrDefault()?.Attachment?.Title,
                //Context = resource.Context?.Encounter?.FirstOrDefault()?.Display,
                Code = resource.Type?.Text,
                Period = resource.Context?.Period?.StartElement?.ToDateTime()?.ToString() + " - " + resource.Context?.Period?.EndElement?.ToDateTime()?.ToString()
            };
        }
    }

    public class EpisodeOfCare
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(EpisodeOfCare);
        public string? Status { get; set; }
        public List<string> Diagnosis { get; set; } = new();
        public string? ManagingOrganization { get; set; }
        public string? Period { get; set; }
        public string? CareManager { get; set; }

        public static EpisodeOfCare Map(Hl7.Fhir.Model.EpisodeOfCare resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.EpisodeOfCare.EpisodeOfCareStatus.Planned => "gepland",
                Hl7.Fhir.Model.EpisodeOfCare.EpisodeOfCareStatus.Waitlist => "wachtlijst",
                Hl7.Fhir.Model.EpisodeOfCare.EpisodeOfCareStatus.Active => "actief",
                Hl7.Fhir.Model.EpisodeOfCare.EpisodeOfCareStatus.Onhold => "in afwachting",
                Hl7.Fhir.Model.EpisodeOfCare.EpisodeOfCareStatus.Finished => "voltooid",
                Hl7.Fhir.Model.EpisodeOfCare.EpisodeOfCareStatus.Cancelled => "geannuleerd",
                Hl7.Fhir.Model.EpisodeOfCare.EpisodeOfCareStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            var diagnosis = resource.Diagnosis?.Select(diagnose => diagnose.Condition?.Display).ToList();
            var managingOrganization = resource.ManagingOrganization?.Display;
            var period = resource.Period?.StartElement?.ToDateTime().ToString() + " - " + resource.Period?.EndElement?.ToDateTime().ToString();
            var careManager = resource.CareManager?.Display;

            return new()
            {
                Id = resource.Id,
                Status = status,
                Diagnosis = diagnosis,
                ManagingOrganization = managingOrganization,
                Period = period,
                CareManager = careManager
            };
        }
    }

    public class Encounter
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(Encounter);
        public string? Status { get; set; }

        public static Encounter Map(Hl7.Fhir.Model.Encounter resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.Encounter.EncounterStatus.Planned => "gepland",
                Hl7.Fhir.Model.Encounter.EncounterStatus.Arrived => "aangekomen",
                Hl7.Fhir.Model.Encounter.EncounterStatus.Triaged => "getriageerd",
                Hl7.Fhir.Model.Encounter.EncounterStatus.InProgress => "in behandeling",
                Hl7.Fhir.Model.Encounter.EncounterStatus.Onleave => "met verlof",
                Hl7.Fhir.Model.Encounter.EncounterStatus.Finished => "voltooid",
                Hl7.Fhir.Model.Encounter.EncounterStatus.Cancelled => "geannuleerd",
                Hl7.Fhir.Model.Encounter.EncounterStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };
            return new()
            {
                Id = resource.Id,
                Status = status
            };
        }
    }

    public class Flag
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(Flag);
        public string? Status { get; set; }



        public static Flag Map(Hl7.Fhir.Model.Flag resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.Flag.FlagStatus.Active => "actief",
                Hl7.Fhir.Model.Flag.FlagStatus.Inactive => "inactief",
                Hl7.Fhir.Model.Flag.FlagStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            return new()
            {
                Id = resource.Id,
                Status = status
            };
        }
    }

    public class Goal
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(Goal);
        public string? Status { get; set; }

        public static Goal Map(Hl7.Fhir.Model.Goal resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.Goal.GoalStatus.Proposed => "voorgesteld",
                Hl7.Fhir.Model.Goal.GoalStatus.Planned => "gepland",
                Hl7.Fhir.Model.Goal.GoalStatus.Accepted => "geaccepteerd",
                Hl7.Fhir.Model.Goal.GoalStatus.OnHold => "in afwachting",
                Hl7.Fhir.Model.Goal.GoalStatus.Cancelled => "geannuleerd",
                Hl7.Fhir.Model.Goal.GoalStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };
            return new()
            {
                Id = resource.Id,
                Status = status
            };
        }
    }

    public class Immunization
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(Immunization);
        public string? Status { get; set; }

        public static Immunization Map(Hl7.Fhir.Model.Immunization resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.Immunization.ImmunizationStatusCodes.Completed => "voltooid",
                Hl7.Fhir.Model.Immunization.ImmunizationStatusCodes.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            return new()
            {
                Id = resource.Id,
                Status = status
            };
        }
    }

    public class Medication
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(Medication);
        public string? Status { get; set; }

        public static Medication Map(Hl7.Fhir.Model.Medication resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.Medication.MedicationStatus.Active => "actief",
                Hl7.Fhir.Model.Medication.MedicationStatus.Inactive => "inactief",
                Hl7.Fhir.Model.Medication.MedicationStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            return new()
            {
                Id = resource.Id,
                Status = status
            };
        }
    }

    public class MedicationAdministration
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(MedicationAdministration);
        public string? Status { get; set; }

        public static MedicationAdministration Map(Hl7.Fhir.Model.MedicationAdministration resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.MedicationAdministration.MedicationAdministrationStatus.InProgress => "in behandeling",
                Hl7.Fhir.Model.MedicationAdministration.MedicationAdministrationStatus.OnHold => "in afwachting",
                Hl7.Fhir.Model.MedicationAdministration.MedicationAdministrationStatus.Completed => "voltooid",
                Hl7.Fhir.Model.MedicationAdministration.MedicationAdministrationStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            return new()
            {
                Id = resource.Id,
                Status = status
            };
        }
    }

    public class MedicationDispense
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(MedicationDispense);
        public string? Status { get; set; }

        public static MedicationDispense Map(Hl7.Fhir.Model.MedicationDispense resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.MedicationDispense.MedicationDispenseStatus.InProgress => "in behandeling",
                Hl7.Fhir.Model.MedicationDispense.MedicationDispenseStatus.OnHold => "in afwachting",
                Hl7.Fhir.Model.MedicationDispense.MedicationDispenseStatus.Completed => "voltooid",
                Hl7.Fhir.Model.MedicationDispense.MedicationDispenseStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };
            return new()
            {
                Id = resource.Id,
                Status = status
            };
        }
    }

    public class MedicationRequest
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(MedicationRequest);
        public string? Status { get; set; }
        public string? Requester { get; set; }
        public string? DosageInstruction { get; set; }

        public static MedicationRequest Map(Hl7.Fhir.Model.MedicationRequest resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.MedicationRequest.MedicationRequestStatus.Active => "actief",
                Hl7.Fhir.Model.MedicationRequest.MedicationRequestStatus.OnHold => "in afwachting",
                Hl7.Fhir.Model.MedicationRequest.MedicationRequestStatus.Completed => "voltooid",
                Hl7.Fhir.Model.MedicationRequest.MedicationRequestStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            return new()
            {
                Id = resource.Id,
                Status = status,
                Requester = resource.Requester?.Agent.Display,
                DosageInstruction = resource.DosageInstruction?.FirstOrDefault()?.Text
            };
        }
    }

    public class MedicationStatement
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(MedicationStatement);
        public string? Status { get; set; }

        public static MedicationStatement Map(Hl7.Fhir.Model.MedicationStatement resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.MedicationStatement.MedicationStatementStatus.Active => "actief",
                Hl7.Fhir.Model.MedicationStatement.MedicationStatementStatus.Completed => "voltooid",
                Hl7.Fhir.Model.MedicationStatement.MedicationStatementStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            return new()
            {
                Id = resource.Id,
                Status = status
            };
        }
    }

    public class Observation
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(Observation);
        public string? Status { get; set; }
        public string? Code { get; set; }

        public static Observation Map(Hl7.Fhir.Model.Observation resource)
        {
            var status = resource.Status switch
            {
                ObservationStatus.Final => "definitief",
                ObservationStatus.Amended => "aangepast",
                ObservationStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            return new()
            {
                Id = resource.Id,
                Status = status,
                Code = resource.Code?.Text
            };
        }
    }

    public class Organization
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(Organization);
        public required string Name { get; set; }

        public static Organization Map(Hl7.Fhir.Model.Organization resource)
        {
            return new()
            {
                Id = resource.Id,
                Name = resource.Name.ToString()
            };
        }
    }

    public class Patient
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(Patient);
        public string? Name { get; set; }
        public string? Gender { get; set; }
        public string? BirthDate { get; set; }
        public string? AddressLine { get; set; }
        public string? City { get; set; }
        public string? PostalCode { get; set; }
        public string? Country { get; set; }

        public static Patient Map(Hl7.Fhir.Model.Patient resource)
        {
            var address = resource.Address.FirstOrDefault();
            var genderExtension = resource.GenderElement?.Extension.FirstOrDefault().ToCodings().FirstOrDefault()?.Display;
            var gender = genderExtension ?? resource.Gender switch
            {
                AdministrativeGender.Male => "man",
                AdministrativeGender.Female => "vrouw",
                AdministrativeGender.Unknown => "onbekend",
                AdministrativeGender.Other => "",
                _ => ""
            };

            return new()
            {
                Id = resource.Id,
                Name = resource.Name.FirstOrDefault()?.ToString(),
                Gender = gender,
                BirthDate = resource.BirthDateElement?.ToDateTimeOffset()?.ToString("dd-MM-yyyy"),
                AddressLine = address?.Line.FirstOrDefault(),
                City = address?.City,
                PostalCode = address?.PostalCode,
                Country = address?.Country
            };
        }
    }

    public class Practitioner
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(Practitioner);
        public string? Name { get; set; }

        public static Practitioner Map(Hl7.Fhir.Model.Practitioner resource)
        {
            return new()
            {
                Id = resource.Id,
                Name = resource.Name.FirstOrDefault()?.ToString()
            };
        }
    }

    public class Procedure
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(Procedure);
        public string? Status { get; set; }
        public string? Code { get; set; }

        public static Procedure Map(Hl7.Fhir.Model.Procedure resource)
        {
            var status = resource.Status switch
            {
                EventStatus.InProgress => "in behandeling",
                EventStatus.Aborted => "afgebroken",
                EventStatus.Completed => "voltooid",
                EventStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            return new()
            {
                Id = resource.Id,
                Status = status,
                Code = resource.Code?.Text
            };
        }
    }

    public class QuestionnaireResponse
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = nameof(QuestionnaireResponse);
        public string? Status { get; set; }

        public static QuestionnaireResponse Map(Hl7.Fhir.Model.QuestionnaireResponse resource)
        {
            var status = resource.Status switch
            {
                Hl7.Fhir.Model.QuestionnaireResponse.QuestionnaireResponseStatus.InProgress => "in behandeling",
                Hl7.Fhir.Model.QuestionnaireResponse.QuestionnaireResponseStatus.Completed => "voltooid",
                Hl7.Fhir.Model.QuestionnaireResponse.QuestionnaireResponseStatus.EnteredInError => "foutief ingevoerd",
                _ => resource.Status.ToString()
            };

            return new()
            {
                Id = resource.Id,
                Status = status
            };
        }
    }

    public class OtherUnmapped
    {
        public required string Id { get; set; }
        public string ResourceType { get; set; } = "Unknown";

        public static OtherUnmapped Map(Resource resource)
        {
            return new()
            {
                Id = resource.Id,
                ResourceType = resource.TypeName
            };
        }
    }
}
