from copy import deepcopy
from pathlib import Path
from typing import Callable, Dict, List, Optional, Tuple

from nonebot_plugin_datastore import get_plugin_data
from PIL import Image, ImageDraw, ImageFilter, ImageFont

from ..l4_image.convert import convert_img, pic_quality
from ..l4_image.image_tools import crop_center_img
from ..l4_image.model import PluginHelp

cache: Dict[str, int] = {}
Micon_path = Path(__file__).parent / "icon"
DEFAULT_ICON = Micon_path / "拼图.png"
try:
    plugin_data = get_plugin_data()
except ValueError:
    plugin_data = Path() / "data"


def cx(w: int, x: int) -> int:
    return int((w - x) / 2)


def _get_icon(name: str, icon_path: Path) -> Optional[Image.Image]:
    path = icon_path / f"{name}.png"
    icon = None
    if path.exists():
        icon = Image.open(path)
    else:
        for i in icon_path.glob("*.png"):
            if i.stem in name:
                icon = Image.open(i)
                break

    return icon


def get_icon(name: str, icon_path: Optional[Path]) -> Image.Image:
    if icon_path is not None:
        icon = _get_icon(name, icon_path)
        if icon is None:
            icon = _get_icon(name, Micon_path)
    else:
        icon = _get_icon(name, Micon_path)

    if icon is None:
        icon = Image.open(DEFAULT_ICON)

    return icon.resize((36, 36))


async def get_help(
    name: str,
    sub_text: str,
    help_data: Dict[str, PluginHelp],
    bg: Image.Image,
    icon: Image.Image,
    badge: Image.Image,
    banner: Image.Image,
    button: Image.Image,
    font: Callable[[int], ImageFont.FreeTypeFont],
    is_dark: bool = True,
    text_color: Tuple[int, int, int] = (250, 250, 250),
    sub_c: Optional[Tuple[int, int, int]] = None,
    op_color: Optional[Tuple[int, int, int]] = None,
    title_color: Tuple[int, int, int] = (250, 250, 250),
    sub_title_color: Tuple[int, int, int] = (235, 235, 235),
    sv_color: Tuple[int, int, int] = (250, 250, 250),
    sv_desc_color: Tuple[int, int, int] = (235, 235, 235),
    column: int = 5,
    is_gaussian: bool = False,
    gaussian_blur: int = 20,
    is_icon: bool = True,
    icon_path: Optional[Path] = None,
    extra_message: Optional[List[str]] = None,
    enable_cache: bool = True,
) -> bytes:
    if sub_c is None and is_dark:
        sub_c = tuple(x - 50 if x > 50 else x for x in text_color)  # type: ignore
    elif sub_c is None and not is_dark:
        sub_c = tuple(x + 50 if x < 205 else x for x in text_color)  # type: ignore

    if op_color is None and is_dark:
        op_color = tuple(x - 90 if x > 90 else x for x in text_color)  # type: ignore
    elif op_color is None and not is_dark:
        op_color = tuple(x + 90 if x < 160 else x for x in text_color)  # type: ignore

    _h = 600

    if extra_message:
        _h += 100

    w, h = 50 + 260 * column, _h + 30
    button_x = 260
    button_y = 103  # 80

    title = Image.new("RGBA", (w, _h))
    icon = icon.resize((300, 300))

    title.paste(icon, (cx(w, 300), 89), icon)
    title.paste(badge, (cx(w, 900), 390), badge)
    badge_s = badge.resize((720, 80))
    title.paste(badge_s, (cx(w, 720), 480), badge_s)

    title_draw = ImageDraw.Draw(title)

    if extra_message:
        all_lenth = 300 * (len(extra_message) - 1) + 720
        first_x = (w - all_lenth) / 2
        for _i, message in enumerate(extra_message):
            _x = int(first_x + _i * 300)
            title.paste(badge_s, (_x, 556), badge_s)
            title_draw.text((_x + 360, 596), message, sub_c, font(26), "mm")

    title_draw.text(
        (cx(w, 0), 440),
        f"{name} 帮助",
        title_color,
        font(36),
        "mm",
    )
    title_draw.text((cx(w, 0), 520), sub_text, sub_title_color, font(26), "mm")

    if is_dark:
        icon_mask = Image.new("RGBA", (36, 36), (255, 255, 255))
    else:
        icon_mask = Image.new("RGBA", (36, 36), (10, 10, 10))

    sv_img_list: List[Image.Image] = []
    for sv_name in help_data:
        tr_size = len(help_data[sv_name]["data"])
        y = 100 + ((tr_size + column - 1) // column) * button_y
        h += y

        # 生成单个服务的背景， 依据默认column
        sv_img = Image.new("RGBA", (w, y))
        sv_data = help_data[sv_name]["data"]
        sv_desc = help_data[sv_name]["desc"]

        bc = deepcopy(banner)
        bc_draw = ImageDraw.Draw(bc)
        bc_draw.text((30, 25), sv_name, sv_color, font(35), "lm")

        if hasattr(font, "getsize"):
            size, _ = font(35).getsize(sv_name)  # type: ignore
        else:
            bbox = font(35).getbbox(sv_name)
            size, _ = bbox[2] - bbox[0], bbox[3] - bbox[1]

        bc_draw.text((42 + size, 30), sv_desc, sv_desc_color, font(20), "lm")
        sv_img.paste(bc, (0, 10), bc)
        # sv_img = easy_alpha_composite(sv_img, bc, (0, 10))

        # 开始绘制各个按钮
        for index, tr in enumerate(sv_data):
            bt = deepcopy(button)
            bt_draw = ImageDraw.Draw(bt)

            # 限制长度
            tr_name = tr["name"]

            if is_icon:
                f = 38
                icon = get_icon(tr["name"], icon_path)
                bt.paste(icon_mask, (14, 20), icon)
            else:
                f = 0

            # 标题
            bt_draw.text((20 + f, 28), tr_name, text_color, font(26), "lm")
            # 使用范例
            bt_draw.text((20 + f, 50), tr["eg"], sub_c, font(17), "lm")
            # 简单介绍
            bt_draw.text((20, 78), tr["desc"], op_color, font(16), "lm")

            offset_x = button_x * (index % column)
            offset_y = button_y * (index // column)
            sv_img.paste(bt, (25 + offset_x, 83 + offset_y), bt)

        sv_img_list.append(sv_img)

    img = crop_center_img(bg, w, h)
    if is_gaussian:
        img = img.filter(ImageFilter.GaussianBlur(gaussian_blur))

    img.paste(title, (0, 0), title)
    temp = 0
    for _sm in sv_img_list:
        img.paste(_sm, (0, _h + temp), _sm)
        temp += _sm.size[1]

    img = img.convert("RGBA")
    all_white = Image.new("RGBA", img.size, (255, 255, 255))
    img = Image.alpha_composite(all_white, img)

    img = img.convert("RGB")
    help_path = plugin_data.data_dir.joinpath("help") / f"{name}.jpg"
    help_path.parent.mkdir(parents=True, exist_ok=True)
    if enable_cache:
        img.save(
            help_path,
            "JPEG",
            quality=pic_quality,
            subsampling=0,
        )
        cache[name] = 1

    return await convert_img(img)
