import asyncio
from pathlib import Path
from typing import Any, Dict

import filetype

from meme_generator import get_memes
from meme_generator.meme import Meme

memes = sorted(get_memes(), key=lambda meme: meme.key)

image_path = Path("docs/images")


async def generate_preview_images():
    for meme in memes:

        async def generate_image(name: str, args: Dict[str, Any] = {}):
            for path in image_path.iterdir():
                if name == path.stem:
                    return

            result = await meme.generate_preview(args=args)
            content = result.getvalue()
            ext = filetype.guess_extension(content)
            filename = f"{name}.{ext}"
            with open(image_path / filename, "wb") as f:
                f.write(content)

        await generate_image(f"{meme.key}")
        if args := meme.params_type.args_type:
            if instances := args.instances:
                for i, instance in enumerate(instances):
                    await generate_image(f"{meme.key}_instance{i}", instance.dict())


def meme_doc(meme: Meme) -> str:
    keywords = "、".join([f"`{keyword}`" for keyword in meme.keywords])

    patterns = "、".join([f"`{pattern}`" for pattern in meme.patterns])

    image_num = f"`{meme.params_type.min_images}`"
    if meme.params_type.max_images > meme.params_type.min_images:
        image_num += f" ~ `{meme.params_type.max_images}`"

    text_num = f"`{meme.params_type.min_texts}`"
    if meme.params_type.max_texts > meme.params_type.min_texts:
        text_num += f" ~ `{meme.params_type.max_texts}`"

    default_texts = (
        f"{', '.join([f'`{text}`' for text in meme.params_type.default_texts])}"
    )

    def arg_info(name: str, info: Dict[str, Any]) -> str:
        text = (
            f"    - `{name}`\n"
            f"        - 描述:{info.get('description', '')}\n"
            f"        - 类型:`{info.get('type', '')}`\n"
            f"        - 默认值:`{info.get('default', '')}`"
        )
        if enum := info.get("enum", []):
            assert isinstance(enum, list)
            text += f"\n        - 可选值:{'、'.join([f'`{e}`' for e in enum])}"
        return text

    if args := meme.params_type.args_type:
        model = args.model
        properties: Dict[str, Dict[str, Any]] = (
            model.schema().get("properties", {}).copy()
        )
        properties.pop("user_infos")
        args_info = "\n" + "\n".join(
            [arg_info(name, info) for name, info in properties.items()]
        )
    else:
        args_info = ""

    if args := meme.params_type.args_type:
        parser = args.parser
        parser_info = parser.format_help()
        parser_info = parser_info.replace("update_doc.py", f"meme generate {meme.key}")
    else:
        parser_info = ""

    def image_doc(name: str) -> str:
        for path in image_path.iterdir():
            if name == path.stem:
                img_path = path.relative_to(Path("docs"))
                return (
                    '<div align="left">\n'
                    f'  <img src="{img_path}" width="200" />\n'
                    "</div>"
                )
        return ""

    preview_image = ""
    if args := meme.params_type.args_type:
        if instances := args.instances:
            preview_image = "\n\n".join(
                [
                    f"> 参数:{instance.json(exclude={'user_infos'})}\n"
                    + image_doc(meme.key + f"_instance{i}")
                    for i, instance in enumerate(instances)
                ]
            )
    if not preview_image:
        preview_image = image_doc(meme.key)

    return (
        f"## {meme.key}\n\n"
        + f"- 关键词:{keywords}\n"
        + (f"- 正则表达式:{patterns}\n" if patterns else "")
        + f"- 需要图片数目:{image_num}\n"
        + f"- 需要文字数目:{text_num}\n"
        + (f"- 默认文字:[{default_texts}]\n" if default_texts else "")
        + (f"- 其他参数:{args_info}\n" if args_info else "")
        + (f"- 其他参数(命令行选项):\n```shell\n{parser_info}```\n\n" if parser_info else "")
        + "- 预览:\n"
        + f"{preview_image}"
    )


def generate_toc():
    return "\n".join(
        f"{i}. [{meme.key} ({'/'.join(meme.keywords)})](#{meme.key})"
        for i, meme in enumerate(memes, start=1)
    )


def generate_doc():
    doc = "# 表情列表\n\n以下为内置表情的关键词、所需参数等信息及表情预览\n\n按照表情的 `key` 排列\n\n\n"
    doc += generate_toc() + "\n\n\n"
    doc += "\n\n".join(meme_doc(meme) for meme in memes) + "\n"
    with open("docs/memes.md", "w") as f:
        f.write(doc)


async def main():
    await generate_preview_images()
    generate_doc()


if __name__ == "__main__":
    loop = asyncio.new_event_loop()
    loop.run_until_complete(main())