"""Local context cache formatting and staleness helpers."""

from __future__ import annotations

import json
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

import yaml


def _format_rules_md(rules: list[dict[str, Any]]) -> str:
    """Format rules into concise markdown summary.

    Args:
        rules: List of rule dicts from the API (each has name, status, rationale, etc.)

    Returns:
        Markdown string with one line per rule.
    """
    if not rules:
        return "# Project Rules\n\nNo rules defined.\n"

    lines = ["# Project Rules\n"]
    for rule in rules:
        name = rule.get("name", "unnamed")
        status = rule.get("status", "unknown")
        rationale = rule.get("rationale") or rule.get("description") or ""
        if rationale:
            lines.append(f"- **{name}** ({status}) — {rationale}")
        else:
            lines.append(f"- **{name}** ({status})")
    lines.append("")
    return "\n".join(lines)


def _format_architecture_rich(architecture: dict[str, Any] | list[dict[str, Any]]) -> str:
    """Format architecture into a Rich-markup summary.

    Args:
        architecture: Architecture dict or list of elements from the API.

    Returns:
        Text with Rich markup for elements and connections.
    """
    lines = ["Architecture Overview", ""]

    # Handle both dict and list formats
    if isinstance(architecture, list):
        elements = architecture
        connections: list[dict[str, Any]] = []
        decisions: list[dict[str, Any]] = []
    else:
        elements = architecture.get("elements", [])
        connections = architecture.get("connections", [])
        decisions = architecture.get("decisions", [])

    if elements:
        lines.append("[bold]Elements:[/bold]")
        for elem in elements:
            name = elem.get("name", "unnamed")
            elem_type = elem.get("type", "")
            description = elem.get("description", "")
            prefix = f"  [dim]\\[{elem_type}][/dim] " if elem_type else "  "
            suffix = f" — {description}" if description else ""
            lines.append(f"{prefix}{name}{suffix}")
        lines.append("")

    if connections:
        lines.append("[bold]Connections:[/bold]")
        for conn in connections:
            source = conn.get("source", "?")
            target = conn.get("target", "?")
            label = conn.get("label") or conn.get("description") or ""
            suffix = f" ({label})" if label else ""
            lines.append(f"  {source} -> {target}{suffix}")
        lines.append("")

    if decisions:
        lines.append("[bold]Decisions:[/bold]")
        for dec in decisions:
            title = dec.get("title") or dec.get("name", "unnamed")
            status = dec.get("status", "")
            suffix = f" [{status}]" if status else ""
            lines.append(f"  - {title}{suffix}")
        lines.append("")

    if not elements and not connections and not decisions:
        lines.append("No architecture data available.")
        lines.append("")

    return "\n".join(lines)


# Backward-compatible alias
_format_architecture_txt = _format_architecture_rich


def _is_cache_stale(config: dict[str, Any]) -> bool | None:
    """Check if the local cache is stale based on config metadata.

    Args:
        config: The .gjalla/config.json contents.

    Returns:
        True if stale, False if fresh, None if no cache metadata.
    """
    cache_meta = config.get("cache")
    if not cache_meta:
        return None

    last_synced = cache_meta.get("last_synced")
    if not last_synced:
        return None

    stale_after_hours = cache_meta.get("stale_after_hours", 24)

    try:
        synced_at = datetime.fromisoformat(last_synced.replace("Z", "+00:00"))
        now = datetime.now(timezone.utc)
        age_hours = (now - synced_at).total_seconds() / 3600
        return age_hours > stale_after_hours
    except (ValueError, TypeError):
        return True


def write_cache_files(
    repo_root: Path,
    context: dict[str, Any],
    *,
    element_tree: str | None = None,
) -> None:
    """Write context cache files to .gjalla/cache/.

    Args:
        repo_root: Repository root path.
        context: Full context dict from the API.
        element_tree: Pre-rendered compact architecture markdown from the
            agent API.  When provided, written directly to architecture.txt
            instead of formatting the flat element list.
    """
    cache_dir = repo_root / ".gjalla" / "cache"
    cache_dir.mkdir(parents=True, exist_ok=True)

    # rules.md
    rules = context.get("rules", [])
    (cache_dir / "rules.md").write_text(_format_rules_md(rules), encoding="utf-8")

    # architecture.txt — prefer pre-rendered element tree from the API
    if element_tree:
        (cache_dir / "architecture.txt").write_text(element_tree, encoding="utf-8")
    else:
        architecture = context.get("architecture", {})
        (cache_dir / "architecture.txt").write_text(_format_architecture_txt(architecture), encoding="utf-8")

    # state.json — full context
    (cache_dir / "state.json").write_text(json.dumps(context, indent=2, default=str) + "\n", encoding="utf-8")

    # Update config.yaml with cache metadata
    from ._shared import load_local_config, save_local_config
    config = load_local_config(repo_root)

    config["cache"] = {
        "last_synced": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
        "stale_after_hours": config.get("cache", {}).get("stale_after_hours", 24),
    }
    save_local_config(repo_root, config)
