using Meezi.Admin.API.Models;
using Meezi.Core.Platform;
using Meezi.Infrastructure.Services.Platform;
using Meezi.Core.Interfaces;
using Meezi.Core.Entities;
using Meezi.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;

namespace Meezi.Admin.API.Services;

public interface IPlatformIntegrationService
{
    Task<PlatformIntegrationsDto> GetIntegrationsAsync(CancellationToken ct = default);
    Task SaveIntegrationsAsync(UpdatePlatformIntegrationsRequest request, CancellationToken ct = default);
}

public class PlatformIntegrationService : IPlatformIntegrationService
{
    public const string KeyActiveGateway = "payment.activeGateway";
    public const string KeyKavenegarApi          = "integrations.kavenegar.apiKey";
    public const string KeyKavenegarOtpTemplate  = "integrations.kavenegar.otpTemplate";
    public const string KeyKavenegarEnabled      = "integrations.kavenegar.enabled";
    public const string KeyKavenegarSender       = "integrations.kavenegar.senderNumber";

    private static readonly (string Id, string NameFa, string Prefix)[] Gateways =
    [
        ("zarinpal", "زرین‌پال", "payment.zarinpal"),
        ("tara", "تارا", "payment.tara"),
        ("snapppay", "اسنپ‌پی", "payment.snapppay"),
        ("nextpay", "نکست‌پی", "payment.nextpay"),
        ("vandar", "وندار", "payment.vandar")
    ];

    private readonly AppDbContext _db;
    private readonly IPlatformCatalogService _catalog;
    private readonly IPlatformRuntimeConfig _runtime;

    public PlatformIntegrationService(
        AppDbContext db,
        IPlatformCatalogService catalog,
        IPlatformRuntimeConfig runtime)
    {
        _db = db;
        _catalog = catalog;
        _runtime = runtime;
    }

    public async Task<PlatformIntegrationsDto> GetIntegrationsAsync(CancellationToken ct = default)
    {
        var settings = await _db.PlatformSettings.AsNoTracking().ToListAsync(ct);
        var map = settings.ToDictionary(s => s.Key, s => s.Value, StringComparer.OrdinalIgnoreCase);

        var active = map.GetValueOrDefault(KeyActiveGateway) ?? "zarinpal";
        var gateways = Gateways.Select(g => MapGateway(g.Id, g.NameFa, g.Prefix, active, map)).ToList();

        var kavenegar = new KavenegarConfigDto(
            map.GetValueOrDefault(KeyKavenegarEnabled) is "true",
            MaskSecret(map.GetValueOrDefault(KeyKavenegarApi)),
            map.GetValueOrDefault(KeyKavenegarOtpTemplate) ?? "meeziotp",
            map.GetValueOrDefault(KeyKavenegarSender) ?? string.Empty,
            HasSecret(map, KeyKavenegarApi));

        var ai = new AiIntegrationsConfigDto(
            new OpenAiIntegrationConfigDto(
                map.GetValueOrDefault(PlatformIntegrationKeys.OpenAiEnabled) is not "false",
                MaskSecret(map.GetValueOrDefault(PlatformIntegrationKeys.OpenAiApiKey)),
                map.GetValueOrDefault(PlatformIntegrationKeys.OpenAiModel) ?? "gpt-4o-mini",
                map.GetValueOrDefault(PlatformIntegrationKeys.OpenAiCoffeeAdvisorEnabled) is not "false",
                HasSecret(map, PlatformIntegrationKeys.OpenAiApiKey)),
            new MeshyIntegrationConfigDto(
                map.GetValueOrDefault(PlatformIntegrationKeys.MeshyEnabled) is not "false",
                MaskSecret(map.GetValueOrDefault(PlatformIntegrationKeys.MeshyApiKey)),
                map.GetValueOrDefault(PlatformIntegrationKeys.MeshyMenu3dEnabled) is not "false",
                HasSecret(map, PlatformIntegrationKeys.MeshyApiKey)));

        return new PlatformIntegrationsDto(active, gateways, kavenegar, ai);
    }

    public async Task SaveIntegrationsAsync(UpdatePlatformIntegrationsRequest request, CancellationToken ct = default)
    {
        var active = request.ActivePaymentGateway.Trim().ToLowerInvariant();
        if (!Gateways.Any(g => g.Id == active))
            active = "zarinpal";

        await UpsertAsync(KeyActiveGateway, active, "payment", "درگاه پیش‌فرض اشتراک", ct);

        foreach (var gw in request.PaymentGateways)
        {
            var meta = Gateways.FirstOrDefault(g => g.Id == gw.Id);
            if (string.IsNullOrEmpty(meta.Id)) continue;

            await UpsertAsync($"{meta.Prefix}.enabled", gw.IsEnabled ? "true" : "false", "payment", $"فعال {meta.NameFa}", ct);
            await UpsertAsync($"{meta.Prefix}.sandbox", gw.Sandbox ? "true" : "false", "payment", $"حالت تست {meta.NameFa}", ct);

            if (gw.Id == "zarinpal")
            {
                if (!string.IsNullOrWhiteSpace(gw.MerchantId))
                    await UpsertAsync($"{meta.Prefix}.merchantId", gw.MerchantId.Trim(), "payment", "مرچنت زرین‌پال", ct);
            }
            else if (gw.Id is "nextpay" or "vandar")
            {
                if (!string.IsNullOrWhiteSpace(gw.ApiKey) && !IsMaskedPlaceholder(gw.ApiKey))
                    await UpsertAsync($"{meta.Prefix}.apiKey", gw.ApiKey.Trim(), "payment", $"توکن {meta.NameFa}", ct);
            }

            if (gw.Credentials is not null)
                await SaveCredentialsAsync(meta.Prefix, gw.Id, gw.Credentials, ct);
        }

        await UpsertAsync(KeyKavenegarEnabled, request.Kavenegar.IsEnabled ? "true" : "false", "integrations", "فعال کاوه‌نگار", ct);
        await UpsertAsync(KeyKavenegarOtpTemplate, request.Kavenegar.OtpTemplate.Trim(), "integrations", "قالب OTP", ct);
        if (!string.IsNullOrWhiteSpace(request.Kavenegar.ApiKey) && !IsMaskedPlaceholder(request.Kavenegar.ApiKey))
            await UpsertAsync(KeyKavenegarApi, request.Kavenegar.ApiKey.Trim(), "integrations", "API Key کاوه‌نگار", ct);
        if (!string.IsNullOrWhiteSpace(request.Kavenegar.SenderNumber))
            await UpsertAsync(KeyKavenegarSender, request.Kavenegar.SenderNumber.Trim(), "integrations", "شماره فرستنده کاوه‌نگار", ct);

        await UpsertAsync(PlatformIntegrationKeys.OpenAiEnabled, request.Ai.OpenAi.IsEnabled ? "true" : "false", "integrations", "فعال OpenAI", ct);
        await UpsertAsync(PlatformIntegrationKeys.OpenAiModel, string.IsNullOrWhiteSpace(request.Ai.OpenAi.Model) ? "gpt-4o-mini" : request.Ai.OpenAi.Model.Trim(), "integrations", "مدل OpenAI", ct);
        await UpsertAsync(PlatformIntegrationKeys.OpenAiCoffeeAdvisorEnabled, request.Ai.OpenAi.CoffeeAdvisorEnabled ? "true" : "false", "integrations", "مشاور قهوه OpenAI", ct);
        if (!string.IsNullOrWhiteSpace(request.Ai.OpenAi.ApiKey) && !IsMaskedPlaceholder(request.Ai.OpenAi.ApiKey))
            await UpsertAsync(PlatformIntegrationKeys.OpenAiApiKey, request.Ai.OpenAi.ApiKey.Trim(), "integrations", "API Key OpenAI", ct);

        await UpsertAsync(PlatformIntegrationKeys.MeshyEnabled, request.Ai.Meshy.IsEnabled ? "true" : "false", "integrations", "فعال Meshy", ct);
        await UpsertAsync(PlatformIntegrationKeys.MeshyMenu3dEnabled, request.Ai.Meshy.Menu3dEnabled ? "true" : "false", "integrations", "ساخت ۳D منو با Meshy", ct);
        if (!string.IsNullOrWhiteSpace(request.Ai.Meshy.ApiKey) && !IsMaskedPlaceholder(request.Ai.Meshy.ApiKey))
            await UpsertAsync(PlatformIntegrationKeys.MeshyApiKey, request.Ai.Meshy.ApiKey.Trim(), "integrations", "API Key Meshy", ct);

        await _db.SaveChangesAsync(ct);
        _catalog.InvalidateCache();
        _runtime.InvalidateCache();
    }

    private async Task SaveCredentialsAsync(
        string prefix,
        string gatewayId,
        UpdatePaymentGatewayCredentialsRequest creds,
        CancellationToken ct)
    {
        if (!string.IsNullOrWhiteSpace(creds.BaseUrl))
            await UpsertAsync($"{prefix}.baseUrl", creds.BaseUrl.Trim(), "payment", "آدرس API", ct);

        if (gatewayId == "tara")
        {
            if (!string.IsNullOrWhiteSpace(creds.Username))
                await UpsertAsync($"{prefix}.username", creds.Username.Trim(), "payment", "نام کاربری تارا", ct);
            if (!string.IsNullOrWhiteSpace(creds.Password) && !IsMaskedPlaceholder(creds.Password))
                await UpsertAsync($"{prefix}.password", creds.Password.Trim(), "payment", "رمز تارا", ct);
            if (!string.IsNullOrWhiteSpace(creds.BranchCode))
                await UpsertAsync($"{prefix}.branchCode", creds.BranchCode.Trim(), "payment", "کد شعبه تارا", ct);
            if (!string.IsNullOrWhiteSpace(creds.TerminalCode))
                await UpsertAsync($"{prefix}.terminalCode", creds.TerminalCode.Trim(), "payment", "ترمینال تارا", ct);
        }
        else if (gatewayId == "snapppay")
        {
            if (!string.IsNullOrWhiteSpace(creds.ClientId))
                await UpsertAsync($"{prefix}.clientId", creds.ClientId.Trim(), "payment", "Client ID اسنپ‌پی", ct);
            if (!string.IsNullOrWhiteSpace(creds.ClientSecret) && !IsMaskedPlaceholder(creds.ClientSecret))
                await UpsertAsync($"{prefix}.clientSecret", creds.ClientSecret.Trim(), "payment", "Client Secret اسنپ‌پی", ct);
            if (!string.IsNullOrWhiteSpace(creds.Username))
                await UpsertAsync($"{prefix}.username", creds.Username.Trim(), "payment", "نام کاربری اسنپ‌پی", ct);
            if (!string.IsNullOrWhiteSpace(creds.Password) && !IsMaskedPlaceholder(creds.Password))
                await UpsertAsync($"{prefix}.password", creds.Password.Trim(), "payment", "رمز اسنپ‌پی", ct);
        }
    }

    private async Task UpsertAsync(string key, string value, string category, string descFa, CancellationToken ct)
    {
        var row = await _db.PlatformSettings.FirstOrDefaultAsync(s => s.Key == key, ct);
        if (row is null)
        {
            _db.PlatformSettings.Add(new PlatformSetting
            {
                Key = key,
                Value = value,
                Category = category,
                DescriptionFa = descFa
            });
        }
        else
        {
            row.Value = value;
            row.UpdatedAt = DateTime.UtcNow;
        }
    }

    private static PaymentGatewayConfigDto MapGateway(
        string id,
        string nameFa,
        string prefix,
        string activeGateway,
        Dictionary<string, string> map)
    {
        var enabled = map.GetValueOrDefault($"{prefix}.enabled") is "true";
        var sandbox = map.GetValueOrDefault($"{prefix}.sandbox") is not "false";
        string? merchantId = null;
        string? apiKey = null;
        var hasSecret = false;
        GatewayCredentialsDto? credentials = null;

        if (id == "zarinpal")
        {
            merchantId = map.GetValueOrDefault($"{prefix}.merchantId");
            hasSecret = HasSecret(map, $"{prefix}.merchantId");
        }
        else if (id is "nextpay" or "vandar")
        {
            apiKey = MaskSecret(map.GetValueOrDefault($"{prefix}.apiKey"));
            hasSecret = HasSecret(map, $"{prefix}.apiKey");
        }
        else if (id == "tara")
        {
            credentials = new GatewayCredentialsDto(
                map.GetValueOrDefault($"{prefix}.username"),
                MaskSecret(map.GetValueOrDefault($"{prefix}.password")),
                map.GetValueOrDefault($"{prefix}.branchCode"),
                map.GetValueOrDefault($"{prefix}.terminalCode"),
                null,
                null,
                map.GetValueOrDefault($"{prefix}.baseUrl"),
                HasSecret(map, $"{prefix}.password"),
                false);
            hasSecret = credentials.HasStoredPassword;
        }
        else if (id == "snapppay")
        {
            credentials = new GatewayCredentialsDto(
                map.GetValueOrDefault($"{prefix}.username"),
                MaskSecret(map.GetValueOrDefault($"{prefix}.password")),
                null,
                null,
                map.GetValueOrDefault($"{prefix}.clientId"),
                MaskSecret(map.GetValueOrDefault($"{prefix}.clientSecret")),
                map.GetValueOrDefault($"{prefix}.baseUrl"),
                HasSecret(map, $"{prefix}.password"),
                HasSecret(map, $"{prefix}.clientSecret"));
            hasSecret = credentials.HasStoredPassword || credentials.HasStoredClientSecret;
        }

        return new PaymentGatewayConfigDto(
            id,
            nameFa,
            enabled,
            activeGateway == id,
            merchantId,
            apiKey,
            sandbox,
            hasSecret,
            credentials);
    }

    private static bool HasSecret(Dictionary<string, string> map, string key) =>
        !string.IsNullOrWhiteSpace(map.GetValueOrDefault(key));

    private static string? MaskSecret(string? value) =>
        string.IsNullOrWhiteSpace(value) ? null : "••••••••";

    private static bool IsMaskedPlaceholder(string? value) =>
        string.IsNullOrWhiteSpace(value) || value.Contains("••••", StringComparison.Ordinal);
}
