import hashlib
import json
import logging as sv
import os
import random
import time
from io import BytesIO

import aiohttp
import cairosvg
import qrcode
import requests
import requests.exceptions
from PIL import Image, ImageDraw, ImageFont

filepath = os.path.dirname(__file__).replace("\\", "/")
# 记录URL
bf_ban_url = "https://api.gametools.network/bfban/checkban"


# 圆角遮罩处理
def draw_rect(img, pos, radius, **kwargs):
    transp = Image.new('RGBA', img.size, (0, 0, 0, 0))
    alpha_draw = ImageDraw.Draw(transp, "RGBA")
    alpha_draw.rounded_rectangle(pos, radius, **kwargs)
    img.paste(Image.alpha_composite(img, transp))
    return img


# 圆角处理
def circle_corner(img, radii):
    """
    半透明圆角处理
    :param img: 要修改的文件
    :param radii: 圆角弧度
    :return: 返回修改过的文件
    """
    circle = Image.new('L', (radii * 2, radii * 2), 0)  # 创建黑色方形
    draw = ImageDraw.Draw(circle)
    draw.ellipse((0, 0, radii * 2, radii * 2), fill=255)  # 黑色方形内切白色圆形

    img = img.convert("RGBA")
    w, h = img.size

    # 创建一个alpha层，存放四个圆角，使用透明度切除圆角外的图片
    alpha = Image.new('L', img.size, 255)
    alpha.paste(circle.crop((0, 0, radii, radii)), (0, 0))  # 左上角
    alpha.paste(circle.crop((radii, 0, radii * 2, radii)),
                (w - radii, 0))  # 右上角
    alpha.paste(circle.crop((radii, radii, radii * 2, radii * 2)),
                (w - radii, h - radii))  # 右下角
    alpha.paste(circle.crop((0, radii, radii, radii * 2)),
                (0, h - radii))  # 左下角
    img.putalpha(alpha)  # 白色区域透明可见，黑色区域不可见

    # 添加圆角边框
    draw = ImageDraw.Draw(img)
    draw.rounded_rectangle(img.getbbox(), outline="white", width=3, radius=radii)
    return img


# 获取专家类型图片
def get_class_type(class_type):
    """
    获取专家类型
    :param class_type: 专家类型
    :return: 返回对应的图标路径
    """
    icon_path = filepath + "/img/class_icon/No-Pats.png"
    if class_type == 'Assault':
        icon_path = filepath + "/img/class_icon/ui/Assault_Icon_small.png"
    elif class_type == 'Support':
        icon_path = filepath + "/img/class_icon/ui/Support_Icon_small.png"
    elif class_type == 'Recon':
        icon_path = filepath + "/img/class_icon/ui/Recon_Icon_small.png"
    elif class_type == 'Engineer':
        icon_path = filepath + "/img/class_icon/ui/Engineer_Icon_small.png"
    return icon_path


# PNG重绘大小
def png_resize(source_file, new_width=0, new_height=0, resample="LANCZOS", ref_file=''):
    """
    PNG缩放透明度处理
    :param source_file: 源文件（Image.open()）
    :param new_width: 设置的宽度
    :param new_height: 设置的高度
    :param resample: 抗锯齿
    :param ref_file: 参考文件
    :return:
    """
    img = source_file
    img = img.convert("RGBA")
    width, height = img.size

    if ref_file != '':
        imgRef = Image.open(ref_file)
        new_width, new_height = imgRef.size
    else:
        if new_height == 0:
            new_height = new_width * width / height

    bands = img.split()
    resample_map = {
        "NEAREST": Image.NEAREST,
        "BILINEAR": Image.BILINEAR,
        "BICUBIC": Image.BICUBIC,
        "LANCZOS": Image.LANCZOS
    }
    resample_method = resample_map.get(resample, Image.LANCZOS)  # 默认使用 LANCZOS

    bands = [b.resize((new_width, new_height), resample=resample_method) for b in bands]
    resized_file = Image.merge('RGBA', bands)

    return resized_file


# 获取物品图片
def get_top_object_img(object_data):
    """
    获取对应物品图标
    :param object_data: 物品数据
    :return: 图标
    """
    img_url = object_data["image"]
    img = Image.open(filepath + "/img/object_icon/default.png").convert('RGBA')
    # object_name = "default"
    path = filepath + "/img/object_icon/"
    try:
        obj_name = os.listdir(path)
        if "weaponName" in object_data:
            object_name = object_data["weaponName"]
            if object_name in str(obj_name):
                sv.info(f"本地已存在{object_name}物品图标")
                img = Image.open(f"{path}{object_name}.png").convert('RGBA')
            else:
                sv.info(f"未检测到{object_name}物品图标，缓存至本地")
                img = Image.open(BytesIO(requests.get(img_url).content)).convert('RGBA')
                img.save(filepath + f"/img/object_icon/{object_name}.png")
        elif "vehicleName" in object_data:
            object_name = object_data["vehicleName"]
            if object_name in str(obj_name):
                sv.info(f"本地已存在{object_name}物品图标")
                img = Image.open(f"{path}{object_name}.png").convert('RGBA')
            else:
                sv.info(f"未检测到{object_name}物品图标，缓存至本地")
                img = Image.open(BytesIO(requests.get(img_url).content)).convert('RGBA')
                img.save(filepath + f"/img/object_icon/{object_name}.png")
    except Exception as err:
        print(err)
    return img


# 二维码生成
def qr_code_gen(player, platform):
    """
    version ：QR code 的版次，可以设置 1 ～ 40 的版次。
    error_correction ：容错率，可选 7%、15%、25%、30%，参数如下 ：
    qrcode.constants.ERROR_CORRECT_L ：7%
    qrcode.constants.ERROR_CORRECT_M ：15%（预设）
    qrcode.constants.ERROR_CORRECT_Q ：25%
    qrcode.constants.ERROR_CORRECT_H ：30%
    box_size ：每个模块的像素个数。
    border ：边框区的厚度，预设是 4。
    image_factory ：图片格式，默认是 PIL。
    mask_pattern ：mask_pattern 参数是 0 ～ 7，如果省略会自行使用最适当的方法。
    """
    if "pc" == platform:
        platform = "origin"
    bf_tracker_link = f"https://battlefieldtracker.com/bf2042/profile/{platform}/{player}/overview"
    qr = qrcode.QRCode(version=1,
                       error_correction=qrcode.constants.ERROR_CORRECT_M,
                       box_size=5,
                       border=2)
    qr.add_data(bf_tracker_link)
    img = qr.make_image(fill_color='white', back_color="black")
    return img


# 图片粘贴
def image_paste(paste_image, under_image, pos):
    """

    :param paste_image: 需要粘贴的图片
    :param under_image: 底图
    :param pos: 位置（x,y）坐标
    :return: 返回图片
    """
    # 获取需要贴入图片的透明通道
    r, g, b, alpha = paste_image.split()
    # 粘贴时将alpha值传递至mask属性
    under_image.paste(paste_image, pos, alpha)
    return under_image


# 获取专属图库
def get_favorite_image(uid):
    bg_path = filepath + f"/img/bg/user/{uid}/"
    if os.listdir(bg_path):
        bg_name = os.listdir(bg_path)
        index = random.randint(0, len(bg_name) - 1)
        img = Image.open(bg_path + f"{bg_name[index]}").convert('RGBA').resize((1920, 1080))
    else:
        common_bg_name = os.listdir(filepath + "/img/bg/common/")
        index = random.randint(0, len(common_bg_name) - 1)
        img = Image.open(filepath + f"/img/bg/common/{common_bg_name[index]}").convert('RGBA').resize((1920, 1080))
    return img


# 获取bot管理员专属图库
def get_user_avatar(user):
    avatar = download_avatar(user)
    avatar = Image.open(BytesIO(avatar)).convert('RGBA').resize((1920, 1080))
    return avatar


# 下载QQ头像
def download_avatar(user_id: str) -> bytes:
    url = f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=640"
    data = download_url(url)
    if not data or hashlib.md5(data).hexdigest() == "acef72340ac0e914090bd35799f5594e":
        url = f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=100"
        data = download_url(url)
    return data


# 根据URL下载文件
def download_url(url: str) -> bytes:
    for i in range(3):
        try:
            resp = requests.get(url)
            if resp.status_code != 200:
                continue
            return resp.content
        except Exception as e:
            print(f"Error downloading {url}, retry {i}/3: {str(e)}")


# 保存用户的图片
async def user_img_save(pic_data: bytes, uid: int):
    bg_path = filepath + f"/img/bg/user/{uid}/"
    try:
        # 裁剪图片
        pic_data = cut_image(pic_data, 16 / 9)
        # 保存图片
        time_now = int(time.time())
        pic_data = pic_data.convert('RGB')
        pic_data = pic_data.resize((1920, 1080))
        pic_data.save(bg_path + str(time_now) + ".jpeg", quality=95)
    except Exception as e:
        raise Exception("图片保存失败")


# 图片裁剪
def cut_image(pic_data: bytes, target_ratio: float):
    try:
        pic_data = Image.open(BytesIO(pic_data))
        w, h = pic_data.size
        pic_ratio = w / h
        if pic_ratio > target_ratio:
            # 宽高比大于目标比例，按高度缩放。保持宽度不变
            new_h = w / target_ratio
            h_delta = (h - new_h) / 2
            w_delta = 0
        else:
            # 宽高比小于目标比例，按宽度缩放。保持高度不变
            new_w = h * target_ratio
            w_delta = (w - new_w) / 2
            h_delta = 0
        cropped = pic_data.crop((w_delta, h_delta, w - w_delta, h - h_delta))
        return cropped
    except Exception as e:
        raise Exception("图片剪裁失败")


# 加logo
def paste_ic_logo(img):
    # 载入logo
    ic_logo = filepath + "/img/dev_logo/IC.png"
    # 载入字体
    en_text_font = ImageFont.truetype(filepath + '/font/BF_Modernista-Bold.ttf', 18)
    # 载入字体
    ch_text_font = ImageFont.truetype(filepath + '/font/NotoSansSCMedium-4.ttf', 18)
    logo_file = Image.open(ic_logo).convert("RGBA").resize((20, 20))
    draw = ImageDraw.Draw(img)
    img = draw_rect(img, (25, 1058, 1895, 1078), 1, fill=(0, 0, 0, 150))
    draw.text((30, 1056), "Data Source From : GAMETOOLS.NETWORK", fill="white", font=en_text_font)
    draw.text((700, 1056), "BF2042 Player‘s Status Plugin Designed By", fill="white", font=en_text_font)
    img = image_paste(logo_file, img, (1040, 1058))
    draw.text((1065, 1056), "SANSENHOSHI", fill="skyblue", font=en_text_font)
    draw.text((1400, 1058), "友情合作：", fill="white", font=ch_text_font)
    draw.text((1500, 1058), "铁幕重工：224077009", fill="#99CC00", font=ch_text_font)
    draw.text((1700, 1058), "贴吧官群：559190861", fill="#99CC00", font=ch_text_font)
    return img


# 获取EA头像
async def get_avatar(platform_id, persona_id, nucleus_id):
    default_avatar_path = filepath + "/img/class_icon/No-Pats.png"
    try:
        url = f"https://api.gametools.network/bf2042/feslid/?platformid={platform_id}&personaid={persona_id}&nucleusid={nucleus_id}"
        async with aiohttp.ClientSession() as session:
            async with session.get(url, headers={'accept': 'application/json'}) as response:
                response.raise_for_status()
                data = json.loads(await response.text())
                avatar_url = data.get('avatar')
                sv.info("头像URL处理" + avatar_url)
                if avatar_url:
                    try:
                        # 添加10s超时判断，如果超时直接使用默认头像
                        res = BytesIO(requests.get(avatar_url, timeout=10).content)
                        avatar = Image.open(res).convert('RGBA')
                        return avatar
                    except requests.exceptions.RequestException as e:
                        sv.warning(f"请求异常：{e}")

    except requests.exceptions.RequestException as e:
        sv.warning(f"请求异常：{e}")

    # 使用默认头像
    avatar = Image.open(default_avatar_path).convert('RGBA')
    return avatar


async def get_special_icon(special):
    """
    获取专家头像
    :return: 专家头像
    """
    """
        获取对应物品图标
        :param object_data: 物品数据
        :return: 图标
        """
    img_url = special["image"]
    img = Image.open(filepath + "/img/specialist_icon/No-Pats.png").convert('RGBA')
    # object_name = "default"
    path = filepath + "/img/specialist_icon/"
    try:
        icons_name = os.listdir(path)
        character_name = special["characterName"]
        if character_name in str(icons_name):
            sv.info(f"本地已存在{character_name}专家图标")
            img = Image.open(f"{path}{character_name}.png").convert('RGBA')
        else:
            sv.info(f"未检测到{character_name}专家图标，缓存至本地")
            out_put = filepath + f"/img/specialist_icon/{character_name}.png"
            img = await svg_to_png(img_url, out_put)
    except Exception as err:
        sv.error(f"获取专家图标失败：{str(err)}")
    return img


async def svg_to_png(svg_file, png_file, width=500, height=500):
    try:
        # 使用 cairosvg 将 SVG 转换为 PNG，并指定输出大小
        cairosvg.svg2png(url=svg_file,
                         write_to=png_file,
                         output_width=width,
                         output_height=height)
        character_icon = Image.open(png_file)
        return character_icon
    except Exception as err:
        sv.error(f"获取图标失败：{str(err)}")


async def draw_point_line(image, start_point, end_point, line_spacing=5, line_length=10, line_width=2,
                          line_color='white'):
    # 创建一个绘图对象
    draw = ImageDraw.Draw(image)
    # 绘制虚线
    for x in range(start_point[0], end_point[0], line_length + line_spacing):
        draw.line([(x, start_point[1]), (x + line_length, start_point[1])], fill=line_color, width=line_width)
    return image
