import os
import pathlib
from logging import getLogger
from typing import Any, Optional, Union

import yaml
from pydantic import BaseModel, ConfigDict, Field

from competitive_verifier import git, github
from competitive_verifier.models import RelativeDirectoryPath, SortedPathSet

_CONFIG_YML_PATH = "_config.yml"

COMPETITIVE_VERIFY_DOCS_CONFIG_YML = "COMPETITIVE_VERIFY_DOCS_CONFIG_YML"

logger = getLogger(__name__)


class ConfigIcons(BaseModel):
    model_config = ConfigDict(extra="allow")

    LIBRARY_ALL_AC: str = ":heavy_check_mark:"
    LIBRARY_PARTIAL_AC: str = ":heavy_check_mark:"
    LIBRARY_SOME_WA: str = ":question:"
    LIBRARY_ALL_WA: str = ":x:"
    LIBRARY_NO_TESTS: str = ":warning:"
    TEST_ACCEPTED: str = ":heavy_check_mark:"
    TEST_WRONG_ANSWER: str = ":x:"
    TEST_WAITING_JUDGE: str = ":warning:"


class ConfigYaml(BaseModel):
    model_config = ConfigDict(extra="allow")

    def merge(self, other: "ConfigYaml"):
        return ConfigYaml.model_validate(
            self.model_dump() | other.model_dump(),
        )

    def model_dump_yml(self):
        d = self.model_dump(
            mode="json",
            by_alias=True,
            exclude_none=True,
        )
        return yaml.safe_dump(d, encoding="utf-8", line_break="\n")

    basedir: Optional[RelativeDirectoryPath] = None
    action_name: Optional[str] = None
    branch_name: Optional[str] = None

    exclude: Optional[list[str]] = None
    description: str = (
        "<small>This documentation is automatically generated by "
        '<a href="https://github.com/competitive-verifier/competitive-verifier">competitive-verifier/competitive-verifier</a>'
        "</small>"
    )

    plugins: list[str] = Field(
        default_factory=lambda: [
            "jemoji",
            "jekyll-redirect-from",
            "jekyll-remote-theme",
        ]
    )

    theme: str = "jekyll-theme-minimal"
    mathjax: Union[str, int] = 3
    highlightjs_style: str = Field(
        default="default",
        serialization_alias="highlightjs-style",
    )
    filename_index: bool = Field(
        default=False,
        serialization_alias="filename-index",
    )
    sass: dict[str, Any] = Field(default_factory=lambda: {"style": "compressed"})
    icons: ConfigIcons = ConfigIcons()
    consolidate: Optional[SortedPathSet] = None


def _load_user_render_config_yml(docs_dir: pathlib.Path) -> Optional[ConfigYaml]:
    env_config_yml = os.getenv(COMPETITIVE_VERIFY_DOCS_CONFIG_YML)
    if env_config_yml:
        logger.info("Parse $COMPETITIVE_VERIFY_DOCS_CONFIG_YML: %s", env_config_yml)
        try:
            user_config_yml = yaml.safe_load(env_config_yml)
            return ConfigYaml.model_validate(user_config_yml)
        except Exception as e:
            logger.exception(
                "Failed to parse $COMPETITIVE_VERIFY_DOCS_CONFIG_YML: %s",
                e,
            )

    user_config_yml_path = docs_dir / _CONFIG_YML_PATH
    if user_config_yml_path.exists():
        logger.info("Parse user config: %s", user_config_yml_path)
        try:
            user_config_yml = yaml.safe_load(user_config_yml_path.read_bytes())
            return ConfigYaml.model_validate(user_config_yml)
        except Exception as e:
            logger.exception(
                "Failed to parse %s: %s", user_config_yml_path.as_posix(), e
            )


def load_config_yml(docs_dir: pathlib.Path) -> ConfigYaml:
    logger.info("docs_dir=%s", docs_dir.as_posix())

    config_yml = _load_user_render_config_yml(docs_dir)
    if not config_yml:
        config_yml = ConfigYaml()

    if not config_yml.action_name:
        config_yml.action_name = github.env.get_workflow_name()
    if not config_yml.branch_name:
        config_yml.branch_name = github.env.get_ref_name()

    if not config_yml.basedir:
        git_root = git.get_root_directory().resolve()
        config_yml.basedir = pathlib.Path.cwd().resolve().relative_to(git_root)
    return config_yml
