using System.Text.Json;
using e_suite.API.Common;
using e_suite.API.Common.models;
using e_suite.API.Common.repository;
using e_suite.Database.Core.Extensions;
using e_suite.Database.Core.Models;
using e_suite.Database.Core.Tables.CustomFields;
using e_suite.Database.Core.Tables.Domain;
using e_suite.Database.Core.Tables.Forms;
using e_suite.Database.Core.Tables.Glossaries;
using eSuite.Core.CustomFields;
using eSuite.Core.Miscellaneous;

namespace e_suite.Modules.CustomFieldsManager;

public class CustomFieldHelper : ICustomFieldHelper
{
    private readonly ICustomFieldReferenceObjectRepository _customFieldReferenceObjectRepository;

    public CustomFieldHelper(ICustomFieldReferenceObjectRepository customFieldReferenceObjectRepository)
    {
        _customFieldReferenceObjectRepository = customFieldReferenceObjectRepository;
    }

    public async Task<CustomFieldDefinition> TranslateToCustomFieldDefinitionAsync(CustomField customField, CancellationToken cancellationToken)
    {
        GeneralIdRef? refElementId = null;
        string? parameters = null;
        switch (customField.FieldType)
        {
            case FieldType.Glossary:
                var glossaryRef =
                    await _customFieldReferenceObjectRepository.GetGlossaryReferenceAsync(customField.Id,
                        cancellationToken);
                refElementId = new GeneralIdRef
                {
                        Id = glossaryRef?.GlossaryId
                };

                var glossary =
                    await _customFieldReferenceObjectRepository.GetGlossaryByGeneralRefIdAsync(refElementId,
                        cancellationToken);

                refElementId.Guid = glossary?.Guid;
                break;
            case FieldType.Sequence:
                var sequenceRef =
                    await _customFieldReferenceObjectRepository.GetSequenceReferenceAsync(customField.Id,
                        cancellationToken);
                refElementId = new GeneralIdRef
                {
                    Id = sequenceRef?.SequenceId
                };

                    var sequence=
                    await _customFieldReferenceObjectRepository.GetSequenceByGeneralRefIdAsync(refElementId,
                        cancellationToken);

                refElementId.Guid = sequence?.Guid;
                break;
            case FieldType.Number:
                var numbersParameters = await _customFieldReferenceObjectRepository.GetNumbersParametersAsync(customField.Id, cancellationToken);
                var numbersParams = new NumberFieldParameters
                {
                    MinimumValue = numbersParameters!.MinimumValue?.ToString().TrimEnd('0').TrimEnd('.'),
                    MaximumValue = numbersParameters!.MaximumValue?.ToString().TrimEnd('0').TrimEnd('.'),
                    Step = numbersParameters!.Step?.ToString().TrimEnd('0').TrimEnd('.')
                };
                parameters = JsonSerializer.Serialize(numbersParams);
                break;
            case FieldType.Text:
                var textsParameters = await _customFieldReferenceObjectRepository.GetTextsParametersAsync(customField.Id, cancellationToken);
                var textsParams = new TextFieldParameters
                {
                    MultiLine = textsParameters != null && textsParameters.MultiLine!.Value
                };
                parameters = JsonSerializer.Serialize(textsParams);
                break;
        }

        return new CustomFieldDefinition
        {
            Id = customField.Id,
            Name = customField.Name,
            DefaultValue = customField.DefaultValue,
            Guid = customField.Guid,
            FieldType = customField.FieldType,
            MinEntries = customField.MinEntries,
            MaxEntries = customField.MaxEntries,
            RefElementId = refElementId,
            Parameters = parameters
        };
    }

    public async Task<FormTemplate?> GetFormTemplateByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken)
    {
        return await _customFieldReferenceObjectRepository.GetFormTemplateByGeneralRefIdAsync(idRef, cancellationToken);
    }

    public async Task<Glossary?> GetGlossaryByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken)
    {
        return await _customFieldReferenceObjectRepository.GetGlossaryByGeneralRefIdAsync(idRef, cancellationToken);
    }

    public async Task<Domain?> GetDomainByGeneralRefIdAsync(IGeneralIdRef idRef, CancellationToken cancellationToken)
    {
        return await _customFieldReferenceObjectRepository.GetDomainByGeneralRefIdAsync(idRef, cancellationToken);
    }

    public async Task<List<CustomFieldValues>> CustomFieldValuesList(
        IEnumerable<ICustomFieldValue> enumerableCustomFieldValues,
        CancellationToken cancellationToken
    )
    {
        var customFieldValues = new List<CustomFieldValues>();
        foreach (var customFieldValue in enumerableCustomFieldValues)
        {
            var customFieldValueItem = new CustomFieldValue
            {
                DisplayValue = customFieldValue.DisplayValue
            };

            switch (customFieldValue.CustomField.FieldType)
            {
                case FieldType.FormTemplate:
                    var templateRefId = (await GetFormTemplateByGeneralRefIdAsync(new GeneralIdRef
                    { Guid = Guid.Parse(customFieldValue.Value) },
                        cancellationToken
                    )).ToGeneralIdRef();

                    customFieldValueItem.Value = templateRefId!;
                    break;
                case FieldType.Glossary:
                    var glossaryRefId = new GeneralIdRef { Guid = Guid.Parse(customFieldValue.Value) };
                    var glossaryValue =
                        await GetGlossaryByGeneralRefIdAsync(glossaryRefId, cancellationToken);
                    var glossaryItemRefId = glossaryValue.ToGeneralIdRef();
                    customFieldValueItem.Value = glossaryItemRefId!;
                    break;
                case FieldType.Domain:
                    var domainRefId = new GeneralIdRef { Guid = Guid.Parse(customFieldValue.Value) };
                    var domainValue =
                        await GetDomainByGeneralRefIdAsync(domainRefId, cancellationToken);
                    var domainItemRefId = domainValue.ToGeneralIdRef();
                    customFieldValueItem.Value = domainItemRefId!;
                    break;
                default:
                    customFieldValueItem.Value = customFieldValue.Value;
                    break;
            }

            var customFieldValuesItem = GetOrCreatecustomFieldValueItem(customFieldValues, customFieldValue.CustomField.ToGeneralIdRef()!);
            customFieldValuesItem.Values.Add(customFieldValueItem);
        }

        return customFieldValues;
    }

    private static CustomFieldValues GetOrCreatecustomFieldValueItem(
        List<CustomFieldValues> customFieldValues,
        GeneralIdRef generalIdRef
    )
    {
        var customFieldValuesItem = customFieldValues.FirstOrDefault(x => x.Id.Equals(generalIdRef));

        if (customFieldValuesItem == null)
        {
            customFieldValuesItem = new CustomFieldValues
            {
                Id = generalIdRef,
                Values = []
            };

            customFieldValues.Add(customFieldValuesItem);
        }

        return customFieldValuesItem;
    }
}