using COSXML;
using COSXML.Auth;
using COSXML.Model.Object;
using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace HoneyBox.Infrastructure.External.Storage;

/// <summary>
/// 腾讯云COS图片上传服务实现
/// </summary>
public class CosImageUploadService : IImageUploadService
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly ILogger<CosImageUploadService> _logger;
    private const string UploadBasePath = "uploads";

    public CosImageUploadService(
        HoneyBoxDbContext dbContext,
        ILogger<CosImageUploadService> logger)
    {
        _dbContext = dbContext;
        _logger = logger;
    }

    /// <inheritdoc />
    public async Task<string?> UploadBase64ImageAsync(string base64Image, string fileNamePrefix = "image")
    {
        try
        {
            if (string.IsNullOrWhiteSpace(base64Image))
            {
                _logger.LogWarning("Base64图片数据为空");
                return null;
            }

            // 解析Base64数据和MIME类型
            string base64Data;
            string contentType = "image/png";
            string extension = ".png";

            if (base64Image.Contains(','))
            {
                var parts = base64Image.Split(',');
                base64Data = parts[1];
                var header = parts[0];
                if (header.Contains(':') && header.Contains(';'))
                {
                    var mimeType = header.Split(':')[1].Split(';')[0];
                    contentType = mimeType;
                    extension = GetExtensionFromMimeType(mimeType);
                }
            }
            else
            {
                base64Data = base64Image;
            }

            // 解码Base64数据
            byte[] imageBytes;
            try
            {
                imageBytes = Convert.FromBase64String(base64Data);
            }
            catch (FormatException ex)
            {
                _logger.LogWarning(ex, "Base64解码失败");
                return null;
            }

            // 验证文件大小 (10MB)
            if (imageBytes.Length > 10 * 1024 * 1024)
            {
                _logger.LogWarning("Base64图片大小超过限制: {Size} bytes", imageBytes.Length);
                return null;
            }

            // 获取COS配置
            var setting = await GetCosSettingAsync();
            if (setting == null)
            {
                _logger.LogError("无法获取COS配置");
                return null;
            }

            // 生成日期目录路径
            var now = DateTime.Now;
            var datePath = $"{now.Year}/{now.Month:D2}/{now.Day:D2}";
            var uniqueFileName = $"{fileNamePrefix}_{now:yyyyMMddHHmmssfff}_{Guid.NewGuid():N}"[..32] + extension;
            var objectKey = $"{UploadBasePath}/{datePath}/{uniqueFileName}";

            // 创建COS客户端并上传
            var cosXml = CreateCosXmlServer(setting);
            var putObjectRequest = new PutObjectRequest(setting.Bucket!, objectKey, imageBytes);
            putObjectRequest.SetRequestHeader("Content-Type", contentType);

            var result = cosXml.PutObject(putObjectRequest);

            if (result.IsSuccessful())
            {
                var url = GenerateAccessUrl(setting.Domain!, objectKey);
                _logger.LogInformation("Base64图片上传成功: {Url}", url);
                return url;
            }
            else
            {
                _logger.LogError("COS上传失败: {Error}", result.httpMessage);
                return null;
            }
        }
        catch (COSXML.CosException.CosClientException clientEx)
        {
            _logger.LogError(clientEx, "COS客户端错误");
            return null;
        }
        catch (COSXML.CosException.CosServerException serverEx)
        {
            _logger.LogError(serverEx, "COS服务端错误: {Info}", serverEx.GetInfo());
            return null;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Base64图片上传异常");
            return null;
        }
    }

    /// <inheritdoc />
    public async Task<string?> UploadStreamAsync(Stream stream, string fileName, string contentType, string prefix = "uploads")
    {
        try
        {
            if (stream == null || stream.Length == 0)
            {
                _logger.LogWarning("上传文件流为空");
                return null;
            }

            // 验证文件大小 (20MB)
            if (stream.Length > 20 * 1024 * 1024)
            {
                _logger.LogWarning("文件大小超过限制: {Size} bytes", stream.Length);
                return null;
            }

            // 获取COS配置
            var setting = await GetCosSettingAsync();
            if (setting == null)
            {
                _logger.LogError("无法获取COS配置");
                return null;
            }

            // 获取文件扩展名
            var extension = Path.GetExtension(fileName);
            if (string.IsNullOrEmpty(extension))
            {
                extension = GetExtensionFromMimeType(contentType);
            }

            // 生成日期目录路径
            var now = DateTime.Now;
            var datePath = $"{now.Year}/{now.Month:D2}/{now.Day:D2}";
            var uniqueFileName = $"{now:yyyyMMddHHmmssfff}_{Guid.NewGuid():N}"[..32] + extension;
            var objectKey = $"{prefix}/{datePath}/{uniqueFileName}";

            // 读取流到字节数组
            using var memoryStream = new MemoryStream();
            await stream.CopyToAsync(memoryStream);
            var imageBytes = memoryStream.ToArray();

            // 创建COS客户端并上传
            var cosXml = CreateCosXmlServer(setting);
            var putObjectRequest = new PutObjectRequest(setting.Bucket!, objectKey, imageBytes);
            putObjectRequest.SetRequestHeader("Content-Type", contentType);

            var result = cosXml.PutObject(putObjectRequest);

            if (result.IsSuccessful())
            {
                var url = GenerateAccessUrl(setting.Domain!, objectKey);
                _logger.LogInformation("文件上传成功: {Url}", url);
                return url;
            }
            else
            {
                _logger.LogError("COS上传失败: {Error}", result.httpMessage);
                return null;
            }
        }
        catch (COSXML.CosException.CosClientException clientEx)
        {
            _logger.LogError(clientEx, "COS客户端错误");
            return null;
        }
        catch (COSXML.CosException.CosServerException serverEx)
        {
            _logger.LogError(serverEx, "COS服务端错误: {Info}", serverEx.GetInfo());
            return null;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "文件上传异常");
            return null;
        }
    }

    private static string GetExtensionFromMimeType(string mimeType)
    {
        return mimeType switch
        {
            "image/jpeg" => ".jpg",
            "image/jpg" => ".jpg",
            "image/png" => ".png",
            "image/gif" => ".gif",
            "image/webp" => ".webp",
            "image/avif" => ".avif",
            _ => ".png"
        };
    }

    private async Task<CosUploadSetting?> GetCosSettingAsync()
    {
        try
        {
            var config = await _dbContext.Configs
                .Where(c => c.ConfigKey == "uploads")
                .Select(c => c.ConfigValue)
                .FirstOrDefaultAsync();

            if (string.IsNullOrEmpty(config))
            {
                return null;
            }

            return JsonConvert.DeserializeObject<CosUploadSetting>(config);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取COS配置失败");
            return null;
        }
    }

    private static CosXml CreateCosXmlServer(CosUploadSetting setting)
    {
        var config = new CosXmlConfig.Builder()
            .IsHttps(true)
            .SetRegion(setting.Region!)
            .Build();

        var credentialProvider = new DefaultQCloudCredentialProvider(
            setting.AccessKeyId!,
            setting.AccessKeySecret!,
            600);

        return new CosXmlServer(config, credentialProvider);
    }

    private static string GenerateAccessUrl(string domain, string objectKey)
    {
        var normalizedDomain = domain.TrimEnd('/');
        if (!normalizedDomain.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
            !normalizedDomain.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
        {
            normalizedDomain = $"https://{normalizedDomain}";
        }
        var normalizedKey = objectKey.StartsWith('/') ? objectKey : $"/{objectKey}";
        return $"{normalizedDomain}{normalizedKey}";
    }

    private class CosUploadSetting
    {
        public string? Type { get; set; }
        public string? AppId { get; set; }
        public string? Bucket { get; set; }
        public string? Region { get; set; }
        public string? AccessKeyId { get; set; }
        public string? AccessKeySecret { get; set; }
        public string? Domain { get; set; }
    }
}
