using Microsoft.Extensions.Caching.Memory;
using SkiaSharp;

namespace HoneyBox.Admin.Services;

/// <summary>
/// 验证码服务实现
/// </summary>
public class CaptchaService : ICaptchaService
{
    private readonly IMemoryCache _cache;
    private readonly Random _random = new();
    
    // 验证码字符集（排除容易混淆的字符如0,O,1,I,l）
    private const string CharSet = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz";
    
    // 验证码配置
    private const int MinLength = 4;
    private const int MaxLength = 6;
    private const int ImageWidth = 120;
    private const int ImageHeight = 40;
    private const int CaptchaExpirationMinutes = 5;
    private const string CacheKeyPrefix = "captcha:";

    public CaptchaService(IMemoryCache cache)
    {
        _cache = cache;
    }

    /// <inheritdoc />
    public CaptchaResult Generate()
    {
        // 生成随机验证码（4-6位）
        var length = _random.Next(MinLength, MaxLength + 1);
        var code = GenerateRandomCode(length);
        
        // 生成唯一Key
        var captchaKey = Guid.NewGuid().ToString("N");
        
        // 存储到缓存（5分钟过期）
        var cacheKey = CacheKeyPrefix + captchaKey;
        _cache.Set(cacheKey, code, TimeSpan.FromMinutes(CaptchaExpirationMinutes));
        
        // 生成图片
        var imageBase64 = GenerateCaptchaImage(code);
        
        return new CaptchaResult
        {
            CaptchaKey = captchaKey,
            CaptchaImage = $"data:image/png;base64,{imageBase64}"
        };
    }

    /// <inheritdoc />
    public bool Validate(string captchaKey, string captchaCode)
    {
        if (string.IsNullOrWhiteSpace(captchaKey) || string.IsNullOrWhiteSpace(captchaCode))
        {
            return false;
        }

        var cacheKey = CacheKeyPrefix + captchaKey;
        
        // 尝试获取缓存中的验证码
        if (!_cache.TryGetValue(cacheKey, out string? storedCode))
        {
            return false; // 验证码不存在或已过期
        }
        
        // 无论验证成功与否，都删除验证码（单次使用）
        _cache.Remove(cacheKey);
        
        // 不区分大小写比较
        return string.Equals(storedCode, captchaCode, StringComparison.OrdinalIgnoreCase);
    }


    /// <summary>
    /// 生成随机验证码字符串
    /// </summary>
    private string GenerateRandomCode(int length)
    {
        var chars = new char[length];
        for (int i = 0; i < length; i++)
        {
            chars[i] = CharSet[_random.Next(CharSet.Length)];
        }
        return new string(chars);
    }

    /// <summary>
    /// 生成验证码图片
    /// </summary>
    private string GenerateCaptchaImage(string code)
    {
        using var bitmap = new SKBitmap(ImageWidth, ImageHeight);
        using var canvas = new SKCanvas(bitmap);
        
        // 填充背景色（浅色随机背景）
        var bgColor = new SKColor(
            (byte)_random.Next(200, 256),
            (byte)_random.Next(200, 256),
            (byte)_random.Next(200, 256)
        );
        canvas.Clear(bgColor);
        
        // 绘制干扰线
        DrawNoiseLines(canvas);
        
        // 绘制噪点
        DrawNoisePoints(canvas);
        
        // 绘制验证码文字
        DrawCaptchaText(canvas, code);
        
        // 转换为PNG并编码为Base64
        using var image = SKImage.FromBitmap(bitmap);
        using var data = image.Encode(SKEncodedImageFormat.Png, 100);
        return Convert.ToBase64String(data.ToArray());
    }

    /// <summary>
    /// 绘制干扰线
    /// </summary>
    private void DrawNoiseLines(SKCanvas canvas)
    {
        using var paint = new SKPaint
        {
            IsAntialias = true,
            StrokeWidth = 1
        };

        // 绘制5-8条干扰线
        var lineCount = _random.Next(5, 9);
        for (int i = 0; i < lineCount; i++)
        {
            paint.Color = new SKColor(
                (byte)_random.Next(100, 200),
                (byte)_random.Next(100, 200),
                (byte)_random.Next(100, 200)
            );
            
            var startX = _random.Next(ImageWidth);
            var startY = _random.Next(ImageHeight);
            var endX = _random.Next(ImageWidth);
            var endY = _random.Next(ImageHeight);
            
            canvas.DrawLine(startX, startY, endX, endY, paint);
        }
    }

    /// <summary>
    /// 绘制噪点
    /// </summary>
    private void DrawNoisePoints(SKCanvas canvas)
    {
        using var paint = new SKPaint();
        
        // 绘制50-100个噪点
        var pointCount = _random.Next(50, 101);
        for (int i = 0; i < pointCount; i++)
        {
            paint.Color = new SKColor(
                (byte)_random.Next(0, 256),
                (byte)_random.Next(0, 256),
                (byte)_random.Next(0, 256)
            );
            
            var x = _random.Next(ImageWidth);
            var y = _random.Next(ImageHeight);
            
            canvas.DrawPoint(x, y, paint);
        }
    }

    /// <summary>
    /// 绘制验证码文字
    /// </summary>
    private void DrawCaptchaText(SKCanvas canvas, string code)
    {
        using var paint = new SKPaint
        {
            IsAntialias = true,
            TextSize = 24,
            Typeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Bold)
        };

        var charWidth = (ImageWidth - 20) / code.Length;
        var startX = 10;

        for (int i = 0; i < code.Length; i++)
        {
            // 每个字符使用不同的深色
            paint.Color = new SKColor(
                (byte)_random.Next(0, 100),
                (byte)_random.Next(0, 100),
                (byte)_random.Next(0, 100)
            );
            
            // 随机Y位置（垂直偏移）
            var y = _random.Next(25, 35);
            
            // 绘制字符
            canvas.DrawText(code[i].ToString(), startX + i * charWidth, y, paint);
        }
    }
}
