from __future__ import annotations

import logging
import os
from dataclasses import dataclass, field
from pathlib import Path

import requests
import yaml

logger = logging.getLogger(__name__)

MEMEGEN_ROOT = Path(__file__).resolve().parent / "data"
TEMPLATES_DIR = MEMEGEN_ROOT / "templates"
FONTS_DIR = MEMEGEN_ROOT / "fonts"

_GITHUB_RAW_BASE = (
    "https://raw.githubusercontent.com/doron-cohen/memes-mcp/main"
    "/assets-package/src/memes_mcp_assets/templates"
)

_IMAGE_EXTENSIONS = ("jpg", "png", "jpeg", "gif")


def _get_cache_dir() -> Path:
    xdg = os.environ.get("XDG_CACHE_HOME")
    base = Path(xdg) if xdg else Path.home() / ".cache"
    return base / "memes-mcp" / "templates"

_DEFAULT_FONT_FILE = "TitilliumWeb-Black.ttf"

DEFAULT_FONT = "thick"


@dataclass
class TextConfig:
    style: str = "upper"
    color: str = "white"
    font: str = DEFAULT_FONT
    anchor_x: float = 0.0
    anchor_y: float = 0.0
    angle: float = 0.0
    scale_x: float = 1.0
    scale_y: float = 0.2
    align: str = "center"


@dataclass
class TemplateInfo:
    id: str
    name: str
    keywords: list[str] = field(default_factory=list)
    example: list[str] = field(default_factory=list)
    lines: list[TextConfig] = field(default_factory=list)
    source: str = ""


_cache: dict[str, TemplateInfo] | None = None


def _load_all() -> dict[str, TemplateInfo]:
    global _cache
    if _cache is not None:
        return _cache

    templates: dict[str, TemplateInfo] = {}
    if not TEMPLATES_DIR.exists():
        _cache = templates
        return templates

    for config_path in sorted(TEMPLATES_DIR.glob("*/config.yml")):
        template_id = config_path.parent.name
        if template_id.startswith("_"):
            continue

        with open(config_path) as f:
            data = yaml.safe_load(f)

        if not data:
            continue

        text_configs = []
        for t in data.get("text", []):
            text_configs.append(
                TextConfig(
                    style=t.get("style", "upper"),
                    color=t.get("color", "white"),
                    font=t.get("font", DEFAULT_FONT),
                    anchor_x=float(t.get("anchor_x", 0.0)),
                    anchor_y=float(t.get("anchor_y", 0.0)),
                    angle=float(t.get("angle", 0.0)),
                    scale_x=float(t.get("scale_x", 1.0)),
                    scale_y=float(t.get("scale_y", 0.2)),
                    align=t.get("align", "center"),
                )
            )

        keywords = [k for k in data.get("keywords", []) if k]
        example = data.get("example", []) or []

        templates[template_id] = TemplateInfo(
            id=template_id,
            name=data.get("name", template_id),
            keywords=keywords,
            example=example,
            lines=text_configs,
            source=data.get("source", "") or "",
        )

    _cache = templates
    return templates


def get_all_templates() -> dict[str, TemplateInfo]:
    return _load_all()


def get_template(template_id: str) -> TemplateInfo | None:
    return _load_all().get(template_id)


def search_templates(query: str) -> list[TemplateInfo]:
    query_lower = query.lower()
    results = []
    for t in _load_all().values():
        searchable = " ".join(
            [
                t.id,
                t.name.lower(),
                " ".join(t.keywords),
            ]
        )
        if query_lower in searchable:
            results.append(t)
    return results


def _find_image_in_dir(directory: Path, style: str) -> Path | None:
    if style != "default":
        for ext in _IMAGE_EXTENSIONS:
            p = directory / f"{style}.{ext}"
            if p.exists():
                return p

    for ext in _IMAGE_EXTENSIONS:
        p = directory / f"default.{ext}"
        if p.exists():
            return p

    return None


def _try_assets_package(template_id: str, style: str) -> Path | None:
    try:
        from memes_mcp_assets import ASSETS_DIR
    except ImportError:
        return None
    return _find_image_in_dir(ASSETS_DIR / "templates" / template_id, style)


def _try_cache(template_id: str, style: str) -> Path | None:
    return _find_image_in_dir(_get_cache_dir() / template_id, style)


def _fetch_from_github(template_id: str, style: str) -> Path:
    cache_dir = _get_cache_dir() / template_id
    cache_dir.mkdir(parents=True, exist_ok=True)

    for ext in _IMAGE_EXTENSIONS:
        filename = f"{style}.{ext}"
        url = f"{_GITHUB_RAW_BASE}/{template_id}/{filename}"
        try:
            resp = requests.get(url, timeout=15)
            if resp.status_code == 200:
                dest = cache_dir / filename
                dest.write_bytes(resp.content)
                logger.debug("Cached %s to %s", url, dest)
                return dest
        except requests.RequestException as exc:
            logger.debug("Failed to fetch %s: %s", url, exc)
            continue

    raise FileNotFoundError(
        f"Could not find image for template '{template_id}' (style='{style}'). "
        f"Install the assets package for offline use: pip install memes-mcp[assets]"
    )


def get_template_image_path(template_id: str, style: str = "default") -> Path:
    path = _try_assets_package(template_id, style)
    if path:
        return path

    path = _try_cache(template_id, style)
    if path:
        return path

    return _fetch_from_github(template_id, style)


def get_font_path(font_name: str = "") -> Path:
    return FONTS_DIR / _DEFAULT_FONT_FILE
