using Compare.Client;
using Hl7.Fhir.Model;
using Hl7.Fhir.Rest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Compare.Helpers;

internal static class MarkupExtensions
{
    public static string FormatCapabilities(this List<FhirSession> sessions)
    {
        var operationCapabilities = new string[] { "everything", "patient-everything", "export", "patient-export", "group-export", "anonymized-export" };
        var builder = new StringBuilder();

        builder.AppendLine();
        builder.AppendLine("Zijn de FHIR-servers beschikbaar in lokaal netwerk?");
        builder.AppendLine();

        builder.AddHeader(30, "Server", "Beschikbaar");
        foreach (var session in sessions)
        {
            bool isActive = session.Server.Enabled && session.IsAvailable && session.Metadata?.Status == PublicationStatus.Active;
            builder.AddRow(30, session.Server.Name, isActive ? "online" : "");
        }

        builder.AppendLine();
        builder.AppendLine();

        foreach (var session in sessions)
        {
            bool isActive = session.Server.Enabled && session.IsAvailable && session.Metadata?.Status == PublicationStatus.Active;
            if (isActive)
            {
                builder.AddHeader(25, $"Capabilities {session.Server.Name}", "Beschikbaar");
                foreach (var capability in operationCapabilities)
                {
                    bool hasCapability =
                    
                        // STU3
                        session.Metadata?.Rest
                            .SelectMany(rest => rest.Operation)
                            .Any(operation => operation.Name == capability) == true ||

                        session.Metadata?.Rest
                            .SelectMany(rest => rest.SearchParam)
                            .Any(searchparam => searchparam.Name == capability) == true ||

                        // R4
                        session.Metadata?.Rest
                            .SelectMany(rest => rest.Resource)
                            .Where(resource => resource.Type == ResourceType.Patient.ToString())
                            .SelectMany(resource => resource.Operation)
                            .Any(operation => operation.Name == capability) == true;

                    builder.AddRow(25, capability, hasCapability ? "beschikbaar" : "");
                }
                builder.AppendLine();
            }
        }
        builder.AppendLine();
        return builder.ToString();
    }

    public static string FormatOperations(this List<FhirSession> sessions)
    {
        var builder = new StringBuilder();
        builder.AppendLine();
        builder.AppendLine("Wat geven de servers terug als we ze uitvragen?");
        builder.AppendLine();
        
        foreach (var session in sessions)
        {
            if (session.IsAvailable)
            {
                // Operation $everything
                builder.AddHeader(30, $"Operations {session.Server.Name}", "Resources");
                builder.AddRow(30, $" 1. {FhirQuery.Test1_PatientEverything.ShortName}", session.TestResults1?.Entry.Count.ToString() ?? "-"); // Total is sometimes returned, Count is reliable.
                builder.AddRow(30, $" 2. {FhirQuery.Test2_PatientEverythingWithPagination.ShortName}", session.TestResults2?.Entry.Count.ToString() ?? "-");
                builder.AddRow(30, $" 3. {FhirQuery.Test3_PatientIdEverything.ShortName}", session.TestResults3?.Entry.Count.ToString() ?? "-");
                builder.AddRow(30, $" 4. {FhirQuery.Test4_PatientIdEverythingWithPagination.ShortName}", session.TestResults4?.Entry.Count.ToString() ?? "-");

                // Operation $document
                builder.AddRow(30, $" 5. {FhirQuery.Test5_PatientExport.ShortName}", session.TestResults5?.Entry.Count.ToString() ?? "-");
                builder.AddRow(30, $" 6. {FhirQuery.Test6_PatientIdExport.ShortName}", session.TestResults6?.Entry.Count.ToString() ?? "-");

                // Operation $document
                builder.AddRow(30, $" 7. {FhirQuery.Test7_PatientDocument.ShortName}", session.TestResults7?.Entry.Count.ToString() ?? "-");
                builder.AddRow(30, $" 8. {FhirQuery.Test8_PatientIdDocument.ShortName}", session.TestResults8?.Entry.Count.ToString() ?? "-");

                // Operation $everything?_include=*
                builder.AddRow(30, $" 9. {FhirQuery.Test9_PatientIdEverythingWithInclude.ShortName}", session.TestResults9?.Entry.Count.ToString() ?? "-");
                builder.AddRow(30, $"10. {FhirQuery.Test10_PatientIdEverythingWithIncludes.ShortName}", session.TestResults10?.Entry.Count.ToString() ?? "-");
                builder.AddRow(30, $"11. {FhirQuery.Test11_PatientIdEverythingWithIncludeWildcard.ShortName}", session.TestResults11?.Entry.Count.ToString() ?? "-");

                // Operation $everything?_type=*
                builder.AddRow(30, $"12. {FhirQuery.Test12_PatientIdEverythingWithType.ShortName}", session.TestResults12?.Entry.Count.ToString() ?? "-");
                builder.AppendLine();
            }
        }

        builder.AppendLine();
        return builder.ToString();
    }


    public static StringBuilder AddHeader(this StringBuilder builder, int columnWidth, params string[] columns)
    {
        // | Column1  | Column2   | Column3   |
        builder.Append("| ");
        foreach (var column in columns)
        {
            builder.Append(column.PadRight(columnWidth));
            builder.Append(" | ");
        }
        builder.AppendLine();

        // | -------- | --------- | --------- |
        builder.Append("| ");
        foreach (var column in columns)
        {
            builder.Append('-', columnWidth);
            builder.Append(" | ");

        }
        builder.AppendLine();

        return builder;
    }

    public static StringBuilder AddRow(this StringBuilder builder, int columnWidth = 10, params string[] columns)
    {
        // | Value1 | Value2 | Value3 |
        builder.Append("| ");
        foreach (var column in columns)
        {
            builder.Append(column.PadRight(columnWidth));
            builder.Append(" | ");
        }
        builder.AppendLine();

        return builder;
    }

}
