import json
import os
import re
from typing import Tuple, List
from urllib.parse import quote, unquote


def load_template(template_name: str) -> str:
    with open("./template.md", "r", encoding="utf-8") as f:
        content = f.read()
        start_text = f"<!-- 这里是{template_name}开始位置 -->"
        end_text = f"<!-- 这里是{template_name}结束位置 -->"
        content = re.search(f"{start_text}(.*?){end_text}", content, re.S).group(1)
        return content.strip()


readme_cn = load_template("readme_template")
readme_en = load_template("readme_template_en")
problem_readme_cn = load_template("problem_readme_template")
problem_readme_en = load_template("problem_readme_template_en")
sql_readme_cn = load_template("sql_problem_readme_template")
sql_readme_en = load_template("sql_problem_readme_template_en")
bash_readme_cn = load_template("bash_problem_readme_template")
bash_readme_en = load_template("bash_problem_readme_template_en")
ts_readme_cn = load_template("ts_problem_readme_template")
ts_readme_en = load_template("ts_problem_readme_template_en")
contest_readme_cn = load_template("contest_readme_template")
contest_readme_en = load_template("contest_readme_template_en")
category_readme_cn = load_template("category_readme_template")
category_readme_en = load_template("category_readme_template_en")

category_dict = {
    "Database": "数据库",
}


def load_cookies() -> Tuple[str, str]:
    cookie_cn, cookie_en = "", ""
    env_file = "./.env"
    if not os.path.exists(env_file):
        return cookie_cn, cookie_en
    with open(env_file, "r") as f:
        lines = f.readlines()
        for line in lines:
            if line.startswith("COOKIE_CN"):
                parts = line.split("=")[1:]
                cookie_cn = "=".join(parts).strip().strip('"')
                continue

            if line.startswith("COOKIE_EN"):
                parts = line.split("=")[1:]
                cookie_en = "=".join(parts).strip().strip('"')
                continue
    return cookie_cn, cookie_en


def load_refresh_config() -> bool:
    env_file = "./.env"
    if not os.path.exists(env_file):
        return False
    with open(env_file, "r") as f:
        lines = f.readlines()
        for line in lines:
            if line.startswith("REFRESH"):
                parts = line.split("=")[1:]
                return "=".join(parts).strip().strip('"') == "True"
    return False


def load_result() -> List[dict]:
    result_file = "./result.json"
    if not os.path.exists(result_file):
        return []
    with open(result_file, "r", encoding="utf-8") as f:
        res = f.read()
        return json.loads(res)


def load_contest_result() -> List[dict]:
    contest_result_file = "./contest.json"
    if not os.path.exists(contest_result_file):
        return []
    with open(contest_result_file, "r", encoding="utf-8") as f:
        res = f.read()
        if res:
            return json.loads(res)
        return []


def save_result(data: List[dict]):
    with open("./result.json", "w", encoding="utf-8") as f:
        f.write(json.dumps(data))


def save_contest_result(data: List[dict]):
    with open("./contest.json", "w", encoding="utf-8") as f:
        f.write(json.dumps(data))


def select_templates(category):
    if category == "Shell":
        return [bash_readme_cn, bash_readme_en]
    if category == "Database":
        return [sql_readme_cn, sql_readme_en]
    if category == "JavaScript" or category == "TypeScript":
        return [ts_readme_cn, ts_readme_en]
    return [problem_readme_cn, problem_readme_en]


def generate_readme(result):
    md_table_cn = [item["md_table_row_cn"] for item in result]
    md_table_en = [item["md_table_row_en"] for item in result]

    # generate README.md
    items = []
    table_cn = "\n|  题号  |  题解  |  标签  |  难度  | 备注 |\n| --- | --- | --- | --- | --- |"
    for item in sorted(md_table_cn, key=lambda x: x[0]):
        items.append(
            f"\n|  {item[0]}  |  {item[1]}  |  {item[2]}  |  {item[3]}  |  {item[4]}  |"
        )
    table_cn += "".join(items)

    # generate README_EN.md
    items = []
    table_en = "\n|  #  |  Solution  |  Tags  |  Difficulty  |  Remark |\n| --- | --- | --- | --- | --- |"
    for item in sorted(md_table_en, key=lambda x: x[0]):
        items.append(
            f"\n|  {item[0]}  |  {item[1]}  |  {item[2]}  |  {item[3]}  |  {item[4]}  |"
        )
    table_en += "".join(items)

    with open("./README.md", "w", encoding="utf-8") as f:
        f.write(readme_cn.format(table_cn))
    with open("./README_EN.md", "w", encoding="utf-8") as f:
        f.write(readme_en.format(table_en))


def generate_question_readme(result):
    for item in result:
        if not item["content_cn"] and not item["content_en"]:
            continue
        path = (
            f'./{item["sub_folder"]}/{item["frontend_question_id"]}.{item["title_en"]}'
        )
        path = path.replace(":", " ")
        if os.path.isdir(path):
            continue
        os.makedirs(path)

        # choose the readme template
        category = item["category"]
        readme_template_cn, readme_template_en = select_templates(category)
        paid_only = ' 🔒' if item['paid_only'] else ''

        # generate lc-cn problem readme
        with open(f"{path}/README.md", "w", encoding="utf-8") as f1:
            f1.write(
                readme_template_cn.format(
                    int(item["frontend_question_id"]),
                    item["title_cn"].strip() + paid_only,
                    item["url_cn"],
                    item["relative_path_en"],
                    ",".join(item["tags_cn"]),
                    item["content_cn"].replace("leetcode-cn.com", "leetcode.cn"),
                )
            )

        # generate lc-en problem readme
        with open(f"{path}/README_EN.md", "w", encoding="utf-8") as f2:
            f2.write(
                readme_template_en.format(
                    int(item["frontend_question_id"]),
                    item["title_en"].strip() + paid_only,
                    item["url_en"],
                    item["relative_path_cn"],
                    ",".join(item["tags_en"]),
                    item["content_en"],
                )
            )


def generate_category_summary(result, category=""):
    """generate category summary files"""
    summary_cn = (
        "- " + category_dict.get(category, category) + "专项练习\n\n"
        if category
        else ""
    )
    summary_en = "- " + category + " Practice\n\n" if category else ""
    category = category.lower() if category else ""
    sub_category = category + "-" if category else ""
    m = {int(item["frontend_question_id"]): item for item in result}
    for file in sorted(os.listdir("./"), key=lambda x: x.lower()):
        if os.path.isdir("./" + file) and file != "__pycache__":
            for sub in sorted(os.listdir("./" + file), key=lambda x: x.lower()):
                sub = sub.replace("`", " ")
                enc = quote(sub)
                if not sub[:4].isdigit():
                    continue
                data = m.get(int(sub[:4]))
                if not data or (category and data["category"].lower() != category):
                    continue
                sub_cn = sub
                if data:
                    sub_cn = sub[:5] + data["title_cn"]

                summary_cn += (
                    f"  - [{sub_cn}](/{sub_category}solution/{file}/{enc}/README.md)\n"
                )
                summary_en += (
                    f"  - [{sub}](/{sub_category}solution/{file}/{enc}/README_EN.md)\n"
                )

    # generate summary.md
    with open(f"./{sub_category}summary.md", "w", encoding="utf-8") as f:
        f.write(summary_cn)

    # generate summary_en.md
    with open(f"./{sub_category}summary_en.md", "w", encoding="utf-8") as f:
        f.write(summary_en)


def generate_category_readme(result, category=""):
    md_table_cn = [item["md_table_row_cn"] for item in result]
    md_table_en = [item["md_table_row_en"] for item in result]
    m = {int(item["frontend_question_id"]): item for item in result}

    # generate README.md
    items = []
    table_cn = "\n|  题号  |  题解  |  标签  |  难度  | 备注 |\n| --- | --- | --- | --- | --- |"
    for item in sorted(md_table_cn, key=lambda x: x[0]):
        if category and m[int(item[0])]["category"] != category:
            continue
        items.append(
            f"\n|  {item[0]}  |  {item[1]}  |  {item[2]}  |  {item[3]}  |  {item[4]}  |"
        )
    table_cn += "".join(items)

    # generate README_EN.md
    items = []
    table_en = "\n|  #  |  Solution  |  Tags  |  Difficulty  |  Remark |\n| --- | --- | --- | --- | --- |"
    for item in sorted(md_table_en, key=lambda x: x[0]):
        if category and m[int(item[0])]["category"] != category:
            continue
        items.append(
            f"\n|  {item[0]}  |  {item[1]}  |  {item[2]}  |  {item[3]}  |  {item[4]}  |"
        )
    table_en += "".join(items)
    path_prefix = category.upper() + "_" if category else ""
    with open(f"./{path_prefix}README.md", "w", encoding="utf-8") as f:
        f.write(
            category_readme_cn.format(
                category_dict.get(category, category), category.upper(), table_cn
            )
        )
    with open(f"./{path_prefix}README_EN.md", "w", encoding="utf-8") as f:
        f.write(category_readme_en.format(category, category.upper(), table_en))


def refresh(result):
    """update problems"""
    pattern = re.compile('src="(.*?)"')
    for question in result:
        front_question_id = question["frontend_question_id"]
        print(front_question_id)
        paid_only = ' 🔒' if question['paid_only'] else ''
        title = question["title_cn"].strip() + paid_only
        title_en = question["title_en"].strip() + paid_only
        tags = ",".join(question["tags_cn"])
        tags_en = ",".join(question["tags_en"])

        path_cn = unquote(str(question["relative_path_cn"]).replace("/solution", "."))
        path_en = unquote(str(question["relative_path_en"]).replace("/solution", "."))

        with open(path_cn, "r", encoding="utf-8") as f1:
            cn_content = f1.read()

        # update title
        with open(path_en, "r", encoding="utf-8") as f2:
            en_content = f2.read()
        i = cn_content.index(". ")
        j = cn_content.index("]")
        cn_content = cn_content.replace(cn_content[i + 2 : j], title)
        i = en_content.index(". ")
        j = en_content.index("]")
        en_content = en_content.replace(en_content[i + 2 : j], title_en)

        # update tags
        match = re.search(r"<!-- tags:(.*?) -->", cn_content)
        if match:
            # If tags exist, update them
            cn_content = re.sub(
                r"<!-- tags:(.*?) -->", f"<!-- tags:{tags} -->", cn_content
            )
        else:
            # If tags do not exist, insert them before "题目描述"
            cn_content = cn_content.replace(
                "## 题目描述", f"<!-- tags:{tags} -->\n\n## 题目描述"
            )
        match = re.search(r"<!-- tags:(.*?) -->", en_content)
        if match:
            # If tags exist, update them
            en_content = re.sub(
                r"<!-- tags:(.*?) -->", f"<!-- tags:{tags_en} -->", en_content
            )
        else:
            # If tags do not exist, insert them before "Description"
            en_content = en_content.replace(
                "## Description", f"<!-- tags:{tags_en} -->\n\n## Description"
            )

        # update question content
        old_content = re.search(
            "<!-- 这里写题目描述 -->(.*?)## 解法", cn_content, re.S
        ).group(1)
        if question.get("content_cn"):
            cn_content = cn_content.replace(
                old_content, "\n\n" + question["content_cn"] + "\n\n"
            ).replace("\n\n    <ul>", "\n    <ul>")

        # replace image url to cdn link
        for url in pattern.findall(cn_content) or []:
            image_name = (
                os.path.basename(url).replace(".PNG", ".png").replace(".JPG", ".jpg")
            )
            new_url = (
                "https://fastly.jsdelivr.net/gh/doocs/leetcode@main"
                + str(question["relative_path_cn"]).replace("README.md", "images/")
                + image_name
            )
            cn_content = cn_content.replace(url, new_url)

        cn_content = cn_content.replace("leetcode-cn.com", "leetcode.cn")
        with open(path_cn, "w", encoding="utf-8") as f1:
            f1.write(cn_content)

        old_content = re.search(
            "## Description(.*?)## Solutions", en_content, re.S
        ).group(1)
        if question.get("content_en"):
            en_content = en_content.replace(
                old_content, "\n\n" + question["content_en"] + "\n\n"
            ).replace("\n\n    <ul>", "\n    <ul>")

        for url in pattern.findall(en_content) or []:
            image_name = (
                os.path.basename(url).replace(".PNG", ".png").replace(".JPG", ".jpg")
            )
            new_url = (
                "https://fastly.jsdelivr.net/gh/doocs/leetcode@main"
                + str(question["relative_path_cn"]).replace("README.md", "images/")
                + image_name
            )
            en_content = en_content.replace(url, new_url)

        with open(path_en, "w", encoding="utf-8") as f2:
            f2.write(en_content)


def generate_contest_readme(result: List):
    result.sort(key=lambda x: -x[0])
    content_cn = "\n\n".join(c[1] for c in result)
    content_en = "\n\n".join(c[2] for c in result)
    content_cn = contest_readme_cn.format(content_cn)
    with open("./CONTEST_README.md", "w", encoding="utf-8") as f:
        f.write(content_cn)
    content_en = contest_readme_en.format(content_en)
    with open("./CONTEST_README_EN.md", "w", encoding="utf-8") as f:
        f.write(content_en)