using HoneyBox.Admin.Business.Models;
using HoneyBox.Admin.Business.Models.Config;
using HoneyBox.Admin.Business.Models.Upload;
using HoneyBox.Admin.Business.Services.Interfaces;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace HoneyBox.Admin.Business.Services;

/// <summary>
/// 上传服务实现
/// 负责文件验证、存储提供者选择和文件上传
/// </summary>
public class UploadService : IUploadService
{
    private readonly IAdminConfigService _configService;
    private readonly IEnumerable<IStorageProvider> _storageProviders;
    private readonly ILogger<UploadService> _logger;

    /// <summary>
    /// 允许的图片格式
    /// </summary>
    private static readonly HashSet<string> AllowedExtensions = new(StringComparer.OrdinalIgnoreCase)
    {
        ".jpg", ".jpeg", ".png", ".gif", ".webp"
    };

    /// <summary>
    /// 允许的MIME类型
    /// </summary>
    private static readonly HashSet<string> AllowedMimeTypes = new(StringComparer.OrdinalIgnoreCase)
    {
        "image/jpeg", "image/png", "image/gif", "image/webp"
    };

    /// <summary>
    /// 最大文件大小 (10MB)
    /// </summary>
    private const long MaxFileSize = 10 * 1024 * 1024;

    /// <summary>
    /// 默认存储类型 (本地存储)
    /// </summary>
    private const string DefaultStorageType = "1";

    public UploadService(
        IAdminConfigService configService,
        IEnumerable<IStorageProvider> storageProviders,
        ILogger<UploadService> logger)
    {
        _configService = configService;
        _storageProviders = storageProviders;
        _logger = logger;
    }

    /// <inheritdoc />
    public async Task<UploadResponse> UploadImageAsync(IFormFile file)
    {
        // 验证文件
        var validationError = ValidateFile(file);
        if (validationError != null)
        {
            throw new BusinessException(BusinessErrorCodes.ValidationFailed, validationError);
        }

        // 获取存储提供者
        var provider = await GetStorageProviderAsync();

        // 上传文件
        await using var stream = file.OpenReadStream();
        var result = await provider.UploadAsync(stream, file.FileName, file.ContentType);

        if (!result.Success)
        {
            throw new BusinessException(BusinessErrorCodes.OperationFailed, result.ErrorMessage ?? "上传失败");
        }

        return new UploadResponse
        {
            Url = result.Url!,
            FileName = file.FileName,
            FileSize = file.Length
        };
    }

    /// <inheritdoc />
    public async Task<List<UploadResponse>> UploadImagesAsync(List<IFormFile> files)
    {
        if (files == null || files.Count == 0)
        {
            throw new BusinessException(BusinessErrorCodes.ValidationFailed, "请选择要上传的文件");
        }

        var results = new List<UploadResponse>();
        foreach (var file in files)
        {
            var response = await UploadImageAsync(file);
            results.Add(response);
        }

        return results;
    }

    /// <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(','))
            {
                // 格式: data:image/png;base64,xxxxx
                var parts = base64Image.Split(',');
                base64Data = parts[1];

                // 解析MIME类型
                var header = parts[0]; // data:image/png;base64
                if (header.Contains(':') && header.Contains(';'))
                {
                    var mimeType = header.Split(':')[1].Split(';')[0];
                    contentType = mimeType;
                    extension = mimeType switch
                    {
                        "image/jpeg" => ".jpg",
                        "image/jpg" => ".jpg",
                        "image/png" => ".png",
                        "image/gif" => ".gif",
                        "image/webp" => ".webp",
                        _ => ".png"
                    };
                }
            }
            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;
            }

            // 生成文件名
            var fileName = $"{fileNamePrefix}_{DateTime.UtcNow:yyyyMMddHHmmss}{extension}";

            // 获取存储提供者并上传
            var provider = await GetStorageProviderAsync();
            using var stream = new MemoryStream(imageBytes);
            var result = await provider.UploadAsync(stream, fileName, contentType);

            if (result.Success)
            {
                _logger.LogInformation("Base64图片上传成功: {Url}", result.Url);
                return result.Url;
            }
            else
            {
                _logger.LogWarning("Base64图片上传失败: {Error}", result.ErrorMessage);
                return null;
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Base64图片上传异常");
            return null;
        }
    }

    /// <summary>
    /// 验证文件
    /// </summary>
    /// <param name="file">上传的文件</param>
    /// <returns>错误信息，null表示验证通过</returns>
    public static string? ValidateFile(IFormFile? file)
    {
        // 检查文件是否为空
        if (file == null || file.Length == 0)
        {
            return "请选择要上传的文件";
        }

        // 检查文件大小
        if (file.Length > MaxFileSize)
        {
            return "文件大小不能超过10MB";
        }

        // 检查文件扩展名
        var extension = Path.GetExtension(file.FileName);
        if (string.IsNullOrEmpty(extension) || !AllowedExtensions.Contains(extension))
        {
            return "只支持 jpg、jpeg、png、gif、webp 格式的图片";
        }

        // 检查MIME类型
        if (!string.IsNullOrEmpty(file.ContentType) && !AllowedMimeTypes.Contains(file.ContentType))
        {
            return "只支持 jpg、jpeg、png、gif、webp 格式的图片";
        }

        return null;
    }

    /// <summary>
    /// 检查文件扩展名是否有效
    /// </summary>
    /// <param name="extension">文件扩展名（包含点号）</param>
    /// <returns>是否有效</returns>
    public static bool IsValidExtension(string? extension)
    {
        if (string.IsNullOrEmpty(extension))
        {
            return false;
        }
        return AllowedExtensions.Contains(extension);
    }

    /// <summary>
    /// 检查文件大小是否有效
    /// </summary>
    /// <param name="fileSize">文件大小（字节）</param>
    /// <returns>是否有效</returns>
    public static bool IsValidFileSize(long fileSize)
    {
        return fileSize > 0 && fileSize <= MaxFileSize;
    }

    /// <summary>
    /// 生成唯一文件名
    /// 格式: {timestamp}_{guid}{extension}
    /// </summary>
    /// <param name="originalFileName">原始文件名</param>
    /// <returns>唯一文件名</returns>
    public static string GenerateUniqueFileName(string originalFileName)
    {
        var extension = Path.GetExtension(originalFileName).ToLowerInvariant();
        var timestamp = DateTime.Now.ToString("yyyyMMddHHmmssfff");
        var guid = Guid.NewGuid().ToString("N")[..8]; // 取GUID前8位
        return $"{timestamp}_{guid}{extension}";
    }

    /// <summary>
    /// 获取存储提供者
    /// 根据配置选择存储提供者，如果配置无效则使用本地存储
    /// </summary>
    private async Task<IStorageProvider> GetStorageProviderAsync()
    {
        // 获取上传配置
        var uploadSetting = await _configService.GetConfigAsync<UploadSetting>(ConfigKeys.Uploads);
        var storageType = uploadSetting?.Type ?? DefaultStorageType;

        // 查找对应的存储提供者
        var provider = _storageProviders.FirstOrDefault(p => p.StorageType == storageType);

        // 如果找不到对应的提供者，使用本地存储作为降级
        if (provider == null)
        {
            _logger.LogWarning("未找到存储类型 {StorageType} 的提供者，使用本地存储", storageType);
            provider = _storageProviders.FirstOrDefault(p => p.StorageType == DefaultStorageType);
        }

        // 如果连本地存储都没有，抛出异常
        if (provider == null)
        {
            throw new BusinessException(BusinessErrorCodes.ConfigurationError, "存储配置无效，请检查上传配置");
        }

        _logger.LogDebug("使用存储提供者: {StorageType}", provider.StorageType);
        return provider;
    }

    /// <inheritdoc />
    public async Task<PresignedUrlResponse?> GetPresignedUploadUrlAsync(GetPresignedUrlRequest request)
    {
        // 验证请求参数
        if (string.IsNullOrWhiteSpace(request.FileName))
        {
            throw new BusinessException(BusinessErrorCodes.ValidationFailed, "文件名不能为空");
        }

        // 验证文件扩展名
        var extension = Path.GetExtension(request.FileName);
        if (!IsValidExtension(extension))
        {
            throw new BusinessException(BusinessErrorCodes.ValidationFailed, "只支持 jpg、jpeg、png、gif、webp 格式的图片");
        }

        // 验证文件大小
        if (request.FileSize > 0 && !IsValidFileSize(request.FileSize))
        {
            throw new BusinessException(BusinessErrorCodes.ValidationFailed, "文件大小不能超过10MB");
        }

        // 获取存储提供者
        var provider = await GetStorageProviderAsync();

        // 检查是否支持客户端直传
        if (!provider.SupportsDirectUpload)
        {
            _logger.LogDebug("当前存储提供者不支持客户端直传，将使用服务端上传");
            return null;
        }

        // 获取预签名URL
        var contentType = request.ContentType;
        if (string.IsNullOrWhiteSpace(contentType))
        {
            contentType = GetContentTypeByExtension(extension);
        }

        var result = await provider.GetPresignedUploadUrlAsync(request.FileName, contentType);
        if (result == null)
        {
            throw new BusinessException(BusinessErrorCodes.OperationFailed, "获取上传URL失败，请检查存储配置");
        }

        return result;
    }

    /// <summary>
    /// 根据扩展名获取ContentType
    /// </summary>
    private static string GetContentTypeByExtension(string extension)
    {
        return extension.ToLowerInvariant() switch
        {
            ".jpg" or ".jpeg" => "image/jpeg",
            ".png" => "image/png",
            ".gif" => "image/gif",
            ".webp" => "image/webp",
            _ => "application/octet-stream"
        };
    }
}
