using Application.Abstractions.Messaging;
using Application.Abstractions.Data;
using Application.Abstractions.Cache;
using Domain.Entities.Common;
using SharedKernel.Storage;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;

namespace Application.Features.Config.Update;

public sealed class Handler(IAppDbContext db, IFileStorage storage, IEditorImageService editorImage, ICacheService cache) : ICommandHandler<Command>
{
    public async Task Handle(Command request, CancellationToken ct)
    {
        var config = await db.Config.OrderByDescending(x => x.ID).FirstOrDefaultAsync(ct);
        if (config is null)
        {
            config = Domain.Entities.Common.Config.Create();
            db.Config.Add(config);
        }

        var basic = new BasicConfig { };
        var images = new ImagesConfig { };
        var meta = new MetaConfig { };
        var company = new CompanyConfig { };
        var account = new AccountConfig { };
        var emailTemplate = new EmailTemplateConfig { };
        var external = new ExternalApiConfig { };
        var payment = new PaymentConfig { };

        if (request.Basic != null)
        {
            basic.SiteName = request.Basic.SiteName;
            basic.SiteURL = request.Basic.SiteURL;
            basic.RootID = request.Basic.RootID;
            basic.FromEmail = request.Basic.FromEmail;
            basic.FromName = request.Basic.FromName;
            basic.SmtpServer = request.Basic.SmtpServer;
            basic.SmtpPort = request.Basic.SmtpPort;
            basic.SmtpEnableSSL = request.Basic.SmtpEnableSSL;
            basic.SmtpUsername = request.Basic.SmtpUsername;
            basic.SmtpPassword = request.Basic.SmtpPassword;
            basic.AdminWhiteIPList = request.Basic.AdminWhiteIPList;
            basic.FrontWhiteIPList = request.Basic.FrontWhiteIPList;
            basic.BlockAlertTitle = request.Basic.BlockAlertTitle;
            basic.BlockAlertContent = await SaveBytesAsync(request.Basic.BlockAlertContent, UploadFolder.Basic, UploadAddition.BlockAlertContent, ct);
            basic.IsMaintenance = request.Basic.IsMaintenance;
            basic.MaintenanceContent = await SaveBytesAsync(request.Basic.MaintenanceContent, UploadFolder.Basic, UploadAddition.MaintenanceContent, ct);
        } else {
            basic = config.Basic;
        }

        if (request.Images != null)
        {
            var del = request.ImagesDelete ?? new Command.ImagesDeleteFlags();

            images.Favicon = await ApplyImageAsync(del.Favicon, config.Images.Favicon, request.Images.FaviconFile, [".ico"], ct);
            images.LogoSquare = await ApplyImageAsync(del.LogoSquare, config.Images.LogoSquare, request.Images.LogoSquareFile, [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"], ct);
            images.LogoHorizontal = await ApplyImageAsync(del.LogoHorizontal, config.Images.LogoHorizontal, request.Images.LogoHorizontalFile, [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"], ct);
            images.OgDefault = await ApplyImageAsync(del.OgDefault, config.Images.OgDefault, request.Images.OgDefaultFile, [".jpg", ".jpeg", ".png", ".gif", ".webp"], ct);
            images.TwitterImage = await ApplyImageAsync(del.TwitterImage, config.Images.TwitterImage, request.Images.TwitterImageFile, [".jpg", ".jpeg", ".png", ".gif", ".webp"], ct);
            images.AppleTouchIcon = await ApplyImageAsync(del.AppleTouchIcon, config.Images.AppleTouchIcon, request.Images.AppleTouchIconFile, [".jpg", ".jpeg", ".png", ".gif", ".webp"], ct);
            images.AppIcon_192 = await ApplyImageAsync(del.AppIcon192, config.Images.AppIcon_192, request.Images.AppIcon192File, [".jpg", ".jpeg", ".png", ".gif", ".webp"], ct);
            images.AppIcon_512 = await ApplyImageAsync(del.AppIcon512, config.Images.AppIcon_512, request.Images.AppIcon512File, [".jpg", ".jpeg", ".png", ".gif", ".webp"], ct);
        } else {
            images = config.Images;
        }

        if (request.Meta != null)
        {
            meta.Keywords = request.Meta.Keywords;
            meta.Description = request.Meta.Description;
            meta.Author = request.Meta.Author;
            meta.Viewport = request.Meta.Viewport;
            meta.ApplicationName = request.Meta.ApplicationName;
            meta.Generator = request.Meta.Generator;
            meta.Robots = request.Meta.Robots;
            meta.Adds = request.Meta.Adds;
        }
        else
        {
            meta = config.Meta;
        }

        if (request.Company != null)
        {
            company.Name = request.Company.Name;
            company.RegNo = request.Company.RegNo;
            company.Address = request.Company.Address;
            company.ZipCode = request.Company.ZipCode;
            company.Owner = request.Company.Owner;
            company.Tel = request.Company.Tel;
            company.Fax = request.Company.Fax;
            company.RetailSaleNo = request.Company.RetailSaleNo;
            company.AddedSaleNo = request.Company.AddedSaleNo;
            company.Hosting = request.Company.Hosting;
            company.AdminName = request.Company.AdminName;
            company.AdminEmail = request.Company.AdminEmail;
            company.SiteUrl = request.Company.SiteUrl;
            company.BankCode = request.Company.BankCode;
            company.BankOwner = request.Company.BankOwner;
            company.BankNumber = request.Company.BankNumber;
        } else {
            company = config.Company;
        }

        if (request.Account != null)
        {
            account.IsRegisterBlock = request.Account.IsRegisterBlock;
            account.IsRegisterEmailAuth = request.Account.IsRegisterEmailAuth;
            account.PasswordMinLength = request.Account.PasswordMinLength;
            account.PasswordUppercaseLength = request.Account.PasswordUppercaseLength;
            account.PasswordNumbersLength = request.Account.PasswordNumbersLength;
            account.PasswordSpecialcharsLength = request.Account.PasswordSpecialcharsLength;
            account.DeniedEmailList = request.Account.DeniedEmailList;
            account.DeniedNameList = request.Account.DeniedNameList;
            account.ChangeEmailDay = request.Account.ChangeEmailDay;
            account.ChangeNameDay = request.Account.ChangeNameDay;
            account.ChangeSummaryDay = request.Account.ChangeSummaryDay;
            account.ChangeIntroDay = request.Account.ChangeIntroDay;
            account.ChangePasswordDay = request.Account.ChangePasswordDay;
            account.IsLoginEmailVerifiedOnly = request.Account.IsLoginEmailVerifiedOnly;
            account.MaxLoginTryCount = request.Account.MaxLoginTryCount;
            account.MaxLoginTryLimitSecond = request.Account.MaxLoginTryLimitSecond;
        } else {
            account = config.Account;
        }

        if (request.EmailTemplate != null)
        {
            emailTemplate.RegisterEmailFormTitle = request.EmailTemplate.RegisterEmailFormTitle;
            emailTemplate.RegisterEmailFormContent = await SaveBytesAsync(request.EmailTemplate.RegisterEmailFormContent, UploadFolder.EmailTemplate, UploadAddition.RegisterEmailFormContent, ct);
            emailTemplate.RegistrationEmailFormTitle = request.EmailTemplate.RegistrationEmailFormTitle;
            emailTemplate.RegistrationEmailFormContent = await SaveBytesAsync(request.EmailTemplate.RegistrationEmailFormContent, UploadFolder.EmailTemplate, UploadAddition.RegistrationEmailFormContent, ct);
            emailTemplate.ResetPasswordEmailFormTitle = request.EmailTemplate.ResetPasswordEmailFormTitle;
            emailTemplate.ResetPasswordEmailFormContent = await SaveBytesAsync(request.EmailTemplate.ResetPasswordEmailFormContent, UploadFolder.EmailTemplate, UploadAddition.ResetPasswordEmailFormContent, ct);
            emailTemplate.ChangedPasswordEmailFormTitle = request.EmailTemplate.ChangedPasswordEmailFormTitle;
            emailTemplate.ChangedPasswordEmailFormContent = await SaveBytesAsync(request.EmailTemplate.ChangedPasswordEmailFormContent, UploadFolder.EmailTemplate, UploadAddition.ChangedPasswordEmailFormContent, ct);
            emailTemplate.WithdrawEmailFormTitle = request.EmailTemplate.WithdrawEmailFormTitle;
            emailTemplate.WithdrawEmailFormContent = await SaveBytesAsync(request.EmailTemplate.WithdrawEmailFormContent, UploadFolder.EmailTemplate, UploadAddition.WithdrawEmailFormContent, ct);
            emailTemplate.EmailVerifyFormTitle = request.EmailTemplate.EmailVerifyFormTitle;
            emailTemplate.EmailVerifyFormContent = await SaveBytesAsync(request.EmailTemplate.EmailVerifyFormContent, UploadFolder.EmailTemplate, UploadAddition.EmailVerifyFormContent, ct);
            emailTemplate.ChangedEmailFormTitle = request.EmailTemplate.ChangedEmailFormTitle;
            emailTemplate.ChangedEmailFormContent = await SaveBytesAsync(request.EmailTemplate.ChangedEmailFormContent, UploadFolder.EmailTemplate, UploadAddition.ChangedEmailFormContent, ct);
        } else {
            emailTemplate = config.EmailTemplate;
        }

        if (request.External != null)
        {
            external.YouTubeApiKeyEnc = request.External.YouTubeApiKeyEnc;
            external.YouTubeApiName = request.External.YouTubeApiName;
            external.GoogleClientId = request.External.GoogleClientId;
            external.GoogleClientSecretEnc = request.External.GoogleClientSecretEnc;
            external.GoogleAppId = request.External.GoogleAppId;
        } else {
            external = config.External;
        }

        if (request.Payment != null)
        {

        }

        config.Update(
            basic,
            images,
            meta,
            company,
            account,
            emailTemplate,
            external,
            payment,
            config.Crypto
        );

        await db.SaveChangesAsync(ct);
        await cache.RemoveAsync(CacheKeys.Config, ct);
    }

    private async Task<string?> ApplyImageAsync(bool deleteRequested, string? currentUrl, IFormFile? newFile, string[] allowedExtensions, CancellationToken ct)
    {
        if (deleteRequested)
        {
            storage.DeleteByUrl(currentUrl);
            return null;
        }

        var uploaded = await SaveFileAsync(newFile, allowedExtensions, ct);

        return uploaded ?? currentUrl;
    }

    private async Task<string?> SaveFileAsync(IFormFile? file, string[] allowedExtensions, CancellationToken ct)
    {
        var path = new FileStoragePath(UploadTarget.Upload, UploadFolder.Basic, null, null);
        var result = await storage.SaveFileAsync(file, path, allowedExtensions, ct);

        return result?.Url;
    }

    private async Task<string?> SaveBytesAsync(string? html, UploadFolder folder, UploadAddition? addition = null, CancellationToken ct = default)
    {
        var path = new FileStoragePath(UploadTarget.Editor, folder, null, addition);

        return await editorImage.UploadAsync(html, path, ct);
    }
}