"""Derived insights for roadmap, risk, dependencies, and human priorities."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Sequence

from .catalog import HUMAN_PROFILES, PLATFORM_BY_ID
from .models import MatrixCell, PlatformHumanReport, Recommendation, as_plain_data, score_label


@dataclass(slots=True)
class DependencyEdge:
    source_platform: str
    target_platform: str
    reason: str
    strength: str

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


@dataclass(slots=True)
class RiskItem:
    risk_id: str
    platform_id: str
    title: str
    severity: str
    evidence: tuple[str, ...]
    impact: str
    mitigation: str

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


@dataclass(slots=True)
class RoadmapItem:
    roadmap_id: str
    platform_id: str
    title: str
    why_now: str
    expected_human_change: str
    suggested_sequence: int
    linked_recommendations: tuple[str, ...]

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


@dataclass(slots=True)
class ProfileCoverage:
    profile_id: str
    best_platforms: tuple[str, ...]
    weakest_platforms: tuple[str, ...]
    average_score: int
    reading: str

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


@dataclass(slots=True)
class EcosystemInsights:
    dependencies: tuple[DependencyEdge, ...]
    risks: tuple[RiskItem, ...]
    roadmap: tuple[RoadmapItem, ...]
    profile_coverage: tuple[ProfileCoverage, ...]

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


def build_dependency_edges(reports: Sequence[PlatformHumanReport]) -> tuple[DependencyEdge, ...]:
    available = {report.platform.platform_id for report in reports}
    edges: list[DependencyEdge] = []
    for report in reports:
        for target in report.platform.related_platforms:
            strength = "forte" if target in available else "planejada"
            title = PLATFORM_BY_ID[target].title if target in PLATFORM_BY_ID else target
            edges.append(
                DependencyEdge(
                    source_platform=report.platform.platform_id,
                    target_platform=target,
                    reason=f"{report.platform.title} depende ou conversa com {title} para entregar experiencia humana completa.",
                    strength=strength,
                )
            )
    return tuple(edges)


def severity_from_score(score: int) -> str:
    if score < 25:
        return "critica"
    if score < 45:
        return "alta"
    if score < 65:
        return "media"
    return "baixa"


def build_risks(reports: Sequence[PlatformHumanReport]) -> tuple[RiskItem, ...]:
    risks: list[RiskItem] = []
    for report in reports:
        if not report.scan.exists:
            risks.append(
                RiskItem(
                    risk_id=f"{report.platform.platform_id}-repo-ausente",
                    platform_id=report.platform.platform_id,
                    title="Repositorio real ausente",
                    severity="critica",
                    evidence=(report.scan.repo_path,),
                    impact="Nao ha base material para validar atendimento humano.",
                    mitigation="Criar ou clonar repositorio real e registrar sincronizacao.",
                )
            )
        if report.scan.exists and not report.scan.git_present:
            risks.append(
                RiskItem(
                    risk_id=f"{report.platform.platform_id}-git-ausente",
                    platform_id=report.platform.platform_id,
                    title="Git ausente no repositorio real",
                    severity="alta",
                    evidence=(report.scan.repo_path,),
                    impact="Nao ha commit, hash ou sincronizacao confiavel.",
                    mitigation="Inicializar Git, configurar origin e registrar status.",
                )
            )
        if report.platform.known_blockers:
            risks.append(
                RiskItem(
                    risk_id=f"{report.platform.platform_id}-blockers-catalogados",
                    platform_id=report.platform.platform_id,
                    title="Bloqueio catalogado de maturidade",
                    severity="alta",
                    evidence=report.platform.known_blockers,
                    impact="Pode haver contradicao entre estado tecnico e prontidao humana.",
                    mitigation="Resolver, formalizar excecao ou isolar o bloqueio em readiness.",
                )
            )
        if report.average_score < 55:
            weak = sorted(report.cells, key=lambda cell: cell.score)[:4]
            risks.append(
                RiskItem(
                    risk_id=f"{report.platform.platform_id}-score-humano-baixo",
                    platform_id=report.platform.platform_id,
                    title="Score humano baixo",
                    severity=severity_from_score(report.average_score),
                    evidence=tuple(f"{cell.profile_id}:{cell.score}" for cell in weak),
                    impact="Perfis humanos importantes podem nao entender ou usar a plataforma.",
                    mitigation="Priorizar lacunas dos perfis mais fracos e gerar telas/relatorios.",
                )
            )
    risks.sort(key=lambda item: ({"critica": 0, "alta": 1, "media": 2, "baixa": 3}.get(item.severity, 4), item.platform_id))
    return tuple(risks)


def build_roadmap(reports: Sequence[PlatformHumanReport], recommendations: Sequence[Recommendation]) -> tuple[RoadmapItem, ...]:
    grouped: dict[str, list[Recommendation]] = {}
    for rec in recommendations:
        grouped.setdefault(rec.platform_id, []).append(rec)
    low_reports = sorted(reports, key=lambda report: report.average_score)
    roadmap: list[RoadmapItem] = []
    sequence = 1
    for report in low_reports:
        recs = sorted(grouped.get(report.platform.platform_id, ()), key=lambda rec: -rec.priority)[:3]
        if not recs:
            continue
        weakest = sorted(report.cells, key=lambda cell: cell.score)[:3]
        roadmap.append(
            RoadmapItem(
                roadmap_id=f"roadmap-{sequence:02d}-{report.platform.platform_id}",
                platform_id=report.platform.platform_id,
                title=f"Elevar {report.platform.title} para atendimento humano verificavel",
                why_now=(
                    f"Score medio {report.average_score}; perfis mais frageis: "
                    + ", ".join(f"{cell.profile_id}:{cell.score}" for cell in weakest)
                ),
                expected_human_change="Pessoas deixam de depender de leitura tecnica e passam a receber tela, relatorio ou proxima acao clara.",
                suggested_sequence=sequence,
                linked_recommendations=tuple(rec.recommendation_id for rec in recs),
            )
        )
        sequence += 1
        if sequence > 12:
            break
    return tuple(roadmap)


def build_profile_coverage(reports: Sequence[PlatformHumanReport]) -> tuple[ProfileCoverage, ...]:
    cells: list[MatrixCell] = [cell for report in reports for cell in report.cells]
    coverage: list[ProfileCoverage] = []
    for profile in HUMAN_PROFILES:
        profile_cells = [cell for cell in cells if cell.profile_id == profile.profile_id]
        if not profile_cells:
            coverage.append(
                ProfileCoverage(
                    profile_id=profile.profile_id,
                    best_platforms=(),
                    weakest_platforms=(),
                    average_score=0,
                    reading="Sem celulas de matriz para este perfil.",
                )
            )
            continue
        ordered = sorted(profile_cells, key=lambda cell: cell.score, reverse=True)
        average = round(sum(cell.score for cell in profile_cells) / len(profile_cells))
        best = tuple(f"{cell.platform_id}:{cell.score}" for cell in ordered[:4])
        weakest = tuple(f"{cell.platform_id}:{cell.score}" for cell in ordered[-4:])
        coverage.append(
            ProfileCoverage(
                profile_id=profile.profile_id,
                best_platforms=best,
                weakest_platforms=weakest,
                average_score=average,
                reading=(
                    f"{profile.name} tem cobertura media {average} ({score_label(average)}). "
                    "As melhores plataformas devem virar referencia; as mais fracas precisam de OS direcionada."
                ),
            )
        )
    return tuple(coverage)


def build_insights(
    reports: Sequence[PlatformHumanReport],
    recommendations: Sequence[Recommendation],
) -> EcosystemInsights:
    return EcosystemInsights(
        dependencies=build_dependency_edges(reports),
        risks=build_risks(reports),
        roadmap=build_roadmap(reports, recommendations),
        profile_coverage=build_profile_coverage(reports),
    )


def insights_markdown(insights: EcosystemInsights) -> str:
    lines = ["# Insights operacionais Mais Humana", ""]
    lines.append("## Riscos")
    lines.append("")
    for risk in insights.risks[:20]:
        lines.append(f"- `{risk.severity}` {risk.platform_id}: {risk.title}. Impacto: {risk.impact} Mitigacao: {risk.mitigation}")
    lines.append("")
    lines.append("## Roadmap sugerido")
    lines.append("")
    for item in insights.roadmap:
        lines.append(f"- {item.suggested_sequence}. {item.title}: {item.why_now}")
    lines.append("")
    lines.append("## Cobertura por perfil")
    lines.append("")
    for coverage in insights.profile_coverage:
        lines.append(f"- {coverage.profile_id}: {coverage.reading}")
    lines.append("")
    lines.append("## Dependencias")
    lines.append("")
    for edge in insights.dependencies:
        lines.append(f"- {edge.source_platform} -> {edge.target_platform} ({edge.strength}): {edge.reason}")
    return "\n".join(lines).strip() + "\n"


def dependency_dot(insights: EcosystemInsights) -> str:
    lines = ["digraph mais_humana {", "  rankdir=LR;"]
    for edge in insights.dependencies:
        lines.append(
            f'  "{edge.source_platform}" -> "{edge.target_platform}" '
            f'[label="{edge.strength}"];'
        )
    lines.append("}")
    return "\n".join(lines) + "\n"

