# -*- coding: utf-8 -*-

import base64
import random
import string
import sys
from io import BytesIO
from pathlib import Path
from typing import Tuple
from PIL import Image, ImageDraw, ImageFont

from app.config.setting import settings


class CaptchaUtil:
    """
    验证码工具类
    """

    @classmethod
    def _get_real_font_path(cls) -> str:
        """
        私有方法：获取字体文件的真实路径（兼容开发/打包环境）
        - 开发环境：项目根目录下的相对路径
        - 打包环境：PyInstaller 临时目录下的路径
        """
        # 基础相对路径（从settings中获取）
        font_relative_path = settings.CAPTCHA_FONT_PATH

        if getattr(sys, 'frozen', False):
            # 打包后：拼接PyInstaller临时目录路径
            real_path = Path(sys._MEIPASS) / font_relative_path
        else:
            # 开发环境：拼接项目根目录路径（根据你的项目结构调整parent层级）
            # 假设当前文件路径：app/utils/captcha_util.py
            # 项目根目录 = 当前文件目录 → app/utils → app → 项目根
            real_path = Path(__file__).parent.parent.parent / font_relative_path

        # 验证路径是否存在，避免加载失败
        if not real_path.exists():
            raise FileNotFoundError(f"验证码字体文件不存在：{real_path}")

        return str(real_path)

    @classmethod
    def generate_captcha(cls) -> Tuple[str, str]:
        """
        生成带有噪声和干扰的验证码图片（4位随机字符）。

        返回:
        - Tuple[str, str]: [base64图片字符串, 验证码值]。
        """
        # 生成4位随机验证码
        chars = string.digits + string.ascii_letters
        captcha_value = ''.join(random.sample(chars, 4))

        # 创建一张随机颜色背景的图片
        width, height = 160, 60
        background_color = tuple(random.randint(230, 255) for _ in range(3))
        image = Image.new('RGB', (width, height), color=background_color)
        draw = ImageDraw.Draw(image)

        # ========== 修复：使用真实字体路径 ==========
        font = ImageFont.truetype(font=cls._get_real_font_path(), size=settings.CAPTCHA_FONT_SIZE)

        # 计算文本总宽度和高度
        total_width = sum(draw.textbbox((0, 0), char, font=font)[2] for char in captcha_value)
        text_height = draw.textbbox((0, 0), captcha_value[0], font=font)[3]

        # 计算起始位置,使文字居中
        x_start = (width - total_width) / 2
        y_start = (height - text_height) / 2 - draw.textbbox((0, 0), captcha_value[0], font=font)[1]

        # 绘制字符
        x = x_start
        for char in captcha_value:
            # 使用深色文字,增加对比度
            text_color = tuple(random.randint(0, 80) for _ in range(3))

            # 随机偏移,增加干扰
            x_offset = x + random.uniform(-2, 2)
            y_offset = y_start + random.uniform(-2, 2)

            # 绘制字符
            draw.text((x_offset, y_offset), char, font=font, fill=text_color)

            # 更新x坐标,增加字符间距的随机性
            x += draw.textbbox((0, 0), char, font=font)[2] + random.uniform(1, 5)

        # 添加干扰线
        for _ in range(4):
            line_color = tuple(random.randint(150, 200) for _ in range(3))
            points = [(i, int(random.uniform(0, height))) for i in range(0, width, 20)]
            draw.line(points, fill=line_color, width=1)

        # 添加随机噪点
        for _ in range(width * height // 60):
            point_color = tuple(random.randint(0, 255) for _ in range(3))
            draw.point(
                (random.randint(0, width), random.randint(0, height)),
                fill=point_color
            )

        # 将图像数据保存到内存中并转换为base64
        buffer = BytesIO()
        image.save(buffer, format='PNG', optimize=True)
        base64_string = base64.b64encode(buffer.getvalue()).decode()

        return base64_string, captcha_value

    @classmethod
    def captcha_arithmetic(cls) -> Tuple[str, int]:
        """
        创建验证码图片（加减乘运算）。

        返回:
        - Tuple[str, int]: [base64图片字符串, 计算结果]。
        """
        # 创建空白图像,使用随机浅色背景
        background_color = tuple(random.randint(230, 255) for _ in range(3))
        image = Image.new('RGB', (160, 60), color=background_color)
        draw = ImageDraw.Draw(image)

        # ========== 修复：使用真实字体路径 ==========
        font = ImageFont.truetype(font=cls._get_real_font_path(), size=settings.CAPTCHA_FONT_SIZE)

        # 生成运算数字和运算符
        operators = ['+', '-', '*']
        operator = random.choice(operators)

        # 对于减法,确保num1大于num2
        if operator == '-':
            num1 = random.randint(6, 10)
            num2 = random.randint(1, 5)
        else:
            num1 = random.randint(1, 9)
            num2 = random.randint(1, 9)

        # 计算结果
        result_map = {
            '+': lambda x, y: x + y,
            '-': lambda x, y: x - y,
            '*': lambda x, y: x * y
        }
        captcha_value = result_map[operator](num1, num2)

        # 绘制文本,使用深色增加对比度
        text = f'{num1} {operator} {num2} = ?'
        text_bbox = draw.textbbox((0, 0), text, font=font)
        text_width = text_bbox[2] - text_bbox[0]
        x = (160 - text_width) // 2
        draw.text((x, 15), text, fill=(0, 0, 139), font=font)

        # 添加干扰线
        for _ in range(3):
            line_color = tuple(random.randint(150, 200) for _ in range(3))
            draw.line([
                (random.randint(0, 160), random.randint(0, 60)),
                (random.randint(0, 160), random.randint(0, 60))
            ], fill=line_color, width=1)

        # 将图像数据保存到内存中并转换为base64
        buffer = BytesIO()
        image.save(buffer, format='PNG', optimize=True)
        base64_string = base64.b64encode(buffer.getvalue()).decode()

        return base64_string, captcha_value