using e_suite.Utilities.Pagination;
using eSuite.Core.MailService;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;
using e_suite.API.Common;
using e_suite.API.Common.exceptions;
using e_suite.API.Common.models;
using e_suite.API.Common.repository;
using e_suite.Database.Audit;
using eSuite.Core.Miscellaneous;
using e_suite.Database.Core.Tables.Mail;
using MockQueryable;

namespace e_suite.Modules.MailTemplatesManager;

public class MailTemplateManager : IMailTemplateManager
{
    private readonly IDomainRepository _domainRepository;
    private readonly IMailTemplatesManagerRepository _mailTemplatesManagerRepository;
    const long sunStrategyDomainId = 1;

    public MailTemplateManager(IMailTemplatesManagerRepository mailTemplatesManagerRepository, IDomainRepository domainRepository)
    {
        _mailTemplatesManagerRepository = mailTemplatesManagerRepository;
        _domainRepository = domainRepository;
    }

    public async Task<IPaginatedData<MailTemplateType>> GetMailTemplateTypes(Paging paging, CancellationToken cancellationToken)
    {
        var mailTemplateTypes = new List<MailTemplateType>();

        foreach (var mailtype in Enum.GetValues<MailType>())
        {
            mailTemplateTypes.Add( new MailTemplateType
            {
                MailType = mailtype,
                Description = GetEnumDisplayName(mailtype)
            });
        }

        var queriableMailTemplateTypes = mailTemplateTypes.BuildMock();

        var paginatedResult = await PaginatedData.Paginate(queriableMailTemplateTypes, paging, KeySelector, 
            cancellationToken);

        return paginatedResult;
    }

    private Expression<Func<MailTemplateType, object>> KeySelector(string? sortKey)
    {
        return sortKey?.ToLowerInvariant() switch
        {
            "description" => x => x.Description!,
            "mailtype" => x => x.MailType,
            _ => x => x.MailType
        };
    }

    public static string? GetEnumDisplayName(Enum value)
    {
        var fieldInfo = value.GetType().GetField(value.ToString());

        if (fieldInfo?.GetCustomAttributes(typeof(DisplayAttribute), false) is DisplayAttribute[] attributes && attributes.Length > 0)
        {
            return attributes.First().Name;
        }

        return value.ToString();
    }

    public async Task<GetMailTemplate> GetMailTemplate(IGeneralIdRef domainId, MailType mailType, CancellationToken cancellationToken)
    {
        var domain = await _domainRepository.GetDomainById(domainId, cancellationToken) ?? throw new NotFoundException($"Unable to find domain");

        var isOverridden = true;
        var mailTemplate = await _mailTemplatesManagerRepository.GetMailTemplate(domain.Id, mailType, cancellationToken);

        if (mailTemplate == null)
        {
            isOverridden = false;
            mailTemplate =
                await _mailTemplatesManagerRepository.GetMailTemplate(sunStrategyDomainId, mailType,
                    cancellationToken);
        }

        if (mailTemplate is null)
            throw new NotFoundException("Unable to find mail template");

        return new GetMailTemplate
        {
            IsOverridden = isOverridden,
            Subject = mailTemplate!.Subject,
            TemplateDefinition = mailTemplate.TemplateDefinition
        };
    }

    public async Task PostMailTemplate(PostMailTemplate mailTemplate, AuditUserDetails auditUserDetails, CancellationToken cancellationToken)
    {
        var domain = await _domainRepository.GetDomainById(mailTemplate.Domain, cancellationToken) ?? throw new NotFoundException($"Unable to find domain");

        var template = await _mailTemplatesManagerRepository.GetMailTemplate(domain.Id, mailTemplate.MailType, cancellationToken);
        if (template == null)
        {
            template = new MailTemplate
            {
                DomainId = domain.Id,
                MailType = mailTemplate.MailType,
                Subject = mailTemplate.Subject,
                TemplateDefinition = mailTemplate.TemplateDefinition
            };

            await _mailTemplatesManagerRepository.InsertMailTemplateAsync(template, auditUserDetails, cancellationToken);
        }
        else
        {
            template.Subject = mailTemplate.Subject;
            template.TemplateDefinition = mailTemplate.TemplateDefinition;

            await _mailTemplatesManagerRepository.UpdateMailTemplateAsync(template, auditUserDetails, cancellationToken);
        }
    }
}