"""Snapshot and diff helpers for governance portfolios."""

from __future__ import annotations

import json
from dataclasses import dataclass
from pathlib import Path
from typing import Mapping, Sequence

from .governance_models import EcosystemGovernancePortfolio
from .models import as_plain_data, utc_now


@dataclass(slots=True)
class GovernancePlatformSnapshot:
    platform_id: str
    status_label: str
    governance_score: int
    human_score: int
    maturity: str
    blocker_count: int
    warning_count: int

    def to_dict(self) -> dict[str, object]:
        return as_plain_data(self)


@dataclass(slots=True)
class GovernanceSnapshot:
    generated_at: str
    average_governance_score: int
    platforms: tuple[GovernancePlatformSnapshot, ...]

    def to_dict(self) -> dict[str, object]:
        return as_plain_data(self)


@dataclass(slots=True)
class GovernanceDelta:
    platform_id: str
    before_status: str
    after_status: str
    score_delta: int
    blocker_delta: int
    warning_delta: int
    summary: str

    def to_dict(self) -> dict[str, object]:
        return as_plain_data(self)


def snapshot_from_portfolio(portfolio: EcosystemGovernancePortfolio) -> GovernanceSnapshot:
    return GovernanceSnapshot(
        generated_at=utc_now(),
        average_governance_score=portfolio.average_governance_score,
        platforms=tuple(
            GovernancePlatformSnapshot(
                platform_id=card.platform_id,
                status_label=card.status_label,
                governance_score=card.governance_score,
                human_score=card.human_score,
                maturity=card.maturity.value,
                blocker_count=len(card.blockers),
                warning_count=len(card.warnings),
            )
            for card in sorted(portfolio.cards, key=lambda item: item.platform_id)
        ),
    )


def write_governance_snapshot(path: Path, snapshot: GovernanceSnapshot) -> Path:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(snapshot.to_dict(), ensure_ascii=False, indent=2, sort_keys=True), encoding="utf-8")
    return path


def load_governance_snapshot(path: Path) -> GovernanceSnapshot | None:
    if not path.exists():
        return None
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
    except (OSError, json.JSONDecodeError):
        return None
    platforms = []
    for item in data.get("platforms", []):
        if not isinstance(item, dict):
            continue
        platforms.append(
            GovernancePlatformSnapshot(
                platform_id=str(item.get("platform_id", "")),
                status_label=str(item.get("status_label", "")),
                governance_score=int(item.get("governance_score", 0)),
                human_score=int(item.get("human_score", 0)),
                maturity=str(item.get("maturity", "")),
                blocker_count=int(item.get("blocker_count", 0)),
                warning_count=int(item.get("warning_count", 0)),
            )
        )
    return GovernanceSnapshot(
        generated_at=str(data.get("generated_at", "")),
        average_governance_score=int(data.get("average_governance_score", 0)),
        platforms=tuple(platforms),
    )


def platform_map(snapshot: GovernanceSnapshot | None) -> Mapping[str, GovernancePlatformSnapshot]:
    if snapshot is None:
        return {}
    return {platform.platform_id: platform for platform in snapshot.platforms}


def diff_governance_snapshots(before: GovernanceSnapshot | None, after: GovernanceSnapshot) -> tuple[GovernanceDelta, ...]:
    before_map = platform_map(before)
    deltas: list[GovernanceDelta] = []
    for current in after.platforms:
        previous = before_map.get(current.platform_id)
        if previous is None:
            deltas.append(
                GovernanceDelta(
                    platform_id=current.platform_id,
                    before_status="novo",
                    after_status=current.status_label,
                    score_delta=current.governance_score,
                    blocker_delta=current.blocker_count,
                    warning_delta=current.warning_count,
                    summary="Plataforma entrou no snapshot de governanca.",
                )
            )
            continue
        score_delta = current.governance_score - previous.governance_score
        blocker_delta = current.blocker_count - previous.blocker_count
        warning_delta = current.warning_count - previous.warning_count
        changed = (
            previous.status_label != current.status_label
            or score_delta != 0
            or blocker_delta != 0
            or warning_delta != 0
        )
        if not changed:
            continue
        direction = "melhorou" if score_delta > 0 and blocker_delta <= 0 else "piorou" if score_delta < 0 or blocker_delta > 0 else "mudou"
        deltas.append(
            GovernanceDelta(
                platform_id=current.platform_id,
                before_status=previous.status_label,
                after_status=current.status_label,
                score_delta=score_delta,
                blocker_delta=blocker_delta,
                warning_delta=warning_delta,
                summary=f"Governanca {direction}: score {score_delta}, blockers {blocker_delta}, warnings {warning_delta}.",
            )
        )
    before_ids = set(before_map)
    after_ids = {platform.platform_id for platform in after.platforms}
    for removed in sorted(before_ids - after_ids):
        previous = before_map[removed]
        deltas.append(
            GovernanceDelta(
                platform_id=removed,
                before_status=previous.status_label,
                after_status="removido",
                score_delta=-previous.governance_score,
                blocker_delta=-previous.blocker_count,
                warning_delta=-previous.warning_count,
                summary="Plataforma saiu do snapshot de governanca.",
            )
        )
    return tuple(sorted(deltas, key=lambda item: (item.platform_id, item.summary)))


def governance_delta_markdown(deltas: Sequence[GovernanceDelta]) -> str:
    lines = ["# Delta de governanca operacional", ""]
    if not deltas:
        lines.append("- Nenhuma alteracao de governanca detectada contra snapshot anterior.")
        return "\n".join(lines) + "\n"
    for delta in deltas:
        lines.append(f"## {delta.platform_id}")
        lines.append("")
        lines.append(f"- status anterior: `{delta.before_status}`")
        lines.append(f"- status atual: `{delta.after_status}`")
        lines.append(f"- delta score: `{delta.score_delta}`")
        lines.append(f"- delta blockers: `{delta.blocker_delta}`")
        lines.append(f"- delta warnings: `{delta.warning_delta}`")
        lines.append(f"- leitura: {delta.summary}")
        lines.append("")
    return "\n".join(lines).strip() + "\n"


def governance_delta_rows(deltas: Sequence[GovernanceDelta]) -> list[list[str]]:
    rows = [["platform", "before_status", "after_status", "score_delta", "blocker_delta", "warning_delta", "summary"]]
    for delta in deltas:
        rows.append(
            [
                delta.platform_id,
                delta.before_status,
                delta.after_status,
                str(delta.score_delta),
                str(delta.blocker_delta),
                str(delta.warning_delta),
                delta.summary,
            ]
        )
    return rows
