"""Quality gates for human-centered readiness.

The gates separate technical readiness from human usefulness.  A repository can
build successfully and still be poor for a support analyst, a CEO, or a client.
This module makes that distinction explicit and machine-checkable.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Iterable, Sequence

from .models import EvidenceKind, MatrixCell, PlatformHumanReport, PlatformScan, as_plain_data


@dataclass(slots=True)
class GateResult:
    gate_id: str
    title: str
    passed: bool
    severity: str
    reason: str
    evidence: tuple[str, ...]
    next_action: str

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


@dataclass(slots=True)
class PlatformQualityReport:
    platform_id: str
    gates: tuple[GateResult, ...]
    human_ready: bool
    technical_ready: bool
    blocker_count: int
    warning_count: int

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


def refs_for_kind(scan: PlatformScan, kind: EvidenceKind, limit: int = 5) -> tuple[str, ...]:
    refs = [evidence.reference for evidence in scan.evidence if evidence.kind == kind]
    return tuple(refs[:limit])


def gate_repository_exists(scan: PlatformScan) -> GateResult:
    return GateResult(
        gate_id="repository_exists",
        title="Repositorio real existe",
        passed=scan.exists,
        severity="blocker" if not scan.exists else "info",
        reason="Repositorio local encontrado." if scan.exists else "Repositorio local nao encontrado.",
        evidence=(scan.repo_path,),
        next_action="Criar ou clonar repositorio real sem numero da pasta gerencial." if not scan.exists else "Manter rastreabilidade.",
    )


def gate_git_ready(scan: PlatformScan) -> GateResult:
    passed = scan.exists and scan.git_present
    evidence = tuple(item for item in (scan.branch, scan.head, scan.remote_origin) if item)
    return GateResult(
        gate_id="git_ready",
        title="Git operacional",
        passed=passed,
        severity="blocker" if scan.exists and not scan.git_present else "info",
        reason="Git local detectado." if passed else "Repositorio sem .git ou inacessivel.",
        evidence=evidence or (scan.repo_path,),
        next_action="Inicializar Git, configurar origin e registrar hash final." if not passed else "Validar status antes de commit.",
    )


def gate_documentation(scan: PlatformScan) -> GateResult:
    passed = bool(scan.readme_excerpt)
    evidence = refs_for_kind(scan, EvidenceKind.README) or ("README.md",)
    return GateResult(
        gate_id="documentation",
        title="Documentacao inicial",
        passed=passed,
        severity="warning" if not passed else "info",
        reason="README tecnico/humano encontrado." if passed else "README inicial nao encontrado.",
        evidence=evidence,
        next_action="Criar README com missao, comandos, validacoes e papel humano." if not passed else "Manter README alinhado ao estado real.",
    )


def gate_tests(scan: PlatformScan) -> GateResult:
    passed = scan.has_tests
    return GateResult(
        gate_id="tests",
        title="Testes detectaveis",
        passed=passed,
        severity="warning" if not passed else "info",
        reason="Testes foram encontrados." if passed else "Nenhum teste detectado pela varredura local.",
        evidence=refs_for_kind(scan, EvidenceKind.TEST) or ("tests/",),
        next_action="Criar smoke ou teste canonico de uso humano." if not passed else "Executar suite antes de fechar OS.",
    )


def gate_operational_evidence(scan: PlatformScan) -> GateResult:
    refs = refs_for_kind(scan, EvidenceKind.OBSERVABILITY) + refs_for_kind(scan, EvidenceKind.ROUTE)
    passed = bool(refs)
    return GateResult(
        gate_id="operational_evidence",
        title="Evidencia operacional",
        passed=passed,
        severity="warning" if not passed else "info",
        reason="Health/readiness/rota/evidencia detectada." if passed else "Sem evidencia operacional clara.",
        evidence=refs or ("health/readiness",),
        next_action="Publicar health, readiness, evidencia ou comandos humanos." if not passed else "Revalidar endpoints e evidencias.",
    )


def gate_human_matrix(cells: Sequence[MatrixCell]) -> GateResult:
    if not cells:
        return GateResult(
            gate_id="human_matrix",
            title="Matriz humana",
            passed=False,
            severity="blocker",
            reason="Matriz sem celulas.",
            evidence=(),
            next_action="Gerar matriz plataforma x perfil.",
        )
    average = round(sum(cell.score for cell in cells) / len(cells))
    low = [cell.profile_id for cell in cells if cell.score < 45]
    return GateResult(
        gate_id="human_matrix",
        title="Cobertura por perfil humano",
        passed=average >= 60 and len(low) <= max(1, len(cells) // 4),
        severity="warning" if low else "info",
        reason=f"Score medio {average}; perfis frageis: {', '.join(low[:6]) or 'nenhum'}.",
        evidence=tuple(f"{cell.profile_id}:{cell.score}" for cell in sorted(cells, key=lambda item: item.score)[:6]),
        next_action="Priorizar perfis com score baixo e transformar lacunas em telas, relatorios ou OS.",
    )


def gate_no_known_blocker(scan: PlatformScan) -> GateResult:
    blockers = scan.platform.known_blockers
    return GateResult(
        gate_id="known_blockers",
        title="Bloqueios conhecidos",
        passed=not blockers,
        severity="blocker" if blockers else "info",
        reason="Sem bloqueios conhecidos no catalogo." if not blockers else "; ".join(blockers),
        evidence=tuple(blockers),
        next_action="Resolver, formalizar excecao ou criar OS especifica para bloqueio." if blockers else "Manter catalogo atualizado.",
    )


def evaluate_platform_quality(report: PlatformHumanReport) -> PlatformQualityReport:
    gates = (
        gate_repository_exists(report.scan),
        gate_git_ready(report.scan),
        gate_documentation(report.scan),
        gate_tests(report.scan),
        gate_operational_evidence(report.scan),
        gate_human_matrix(report.cells),
        gate_no_known_blocker(report.scan),
    )
    blocker_count = sum(1 for gate in gates if not gate.passed and gate.severity == "blocker")
    warning_count = sum(1 for gate in gates if not gate.passed and gate.severity == "warning")
    technical_ready = gates[0].passed and gates[1].passed and gates[3].passed
    human_ready = technical_ready and blocker_count == 0 and report.average_score >= 70
    return PlatformQualityReport(
        platform_id=report.platform.platform_id,
        gates=gates,
        human_ready=human_ready,
        technical_ready=technical_ready,
        blocker_count=blocker_count,
        warning_count=warning_count,
    )


def evaluate_ecosystem_quality(reports: Sequence[PlatformHumanReport]) -> tuple[PlatformQualityReport, ...]:
    return tuple(evaluate_platform_quality(report) for report in reports)


def worst_gates(quality_reports: Sequence[PlatformQualityReport], limit: int = 12) -> tuple[GateResult, ...]:
    failed: list[GateResult] = []
    for quality in quality_reports:
        failed.extend(gate for gate in quality.gates if not gate.passed)
    failed.sort(key=lambda gate: (0 if gate.severity == "blocker" else 1, gate.gate_id))
    return tuple(failed[:limit])


def quality_summary_lines(quality_reports: Sequence[PlatformQualityReport]) -> list[str]:
    total = len(quality_reports)
    human_ready = sum(1 for item in quality_reports if item.human_ready)
    technical_ready = sum(1 for item in quality_reports if item.technical_ready)
    blockers = sum(item.blocker_count for item in quality_reports)
    warnings = sum(item.warning_count for item in quality_reports)
    lines = [
        f"Plataformas avaliadas: {total}",
        f"Prontas tecnicamente: {technical_ready}",
        f"Prontas para leitura humana: {human_ready}",
        f"Blockers: {blockers}",
        f"Warnings: {warnings}",
    ]
    for gate in worst_gates(quality_reports, limit=10):
        lines.append(f"{gate.severity.upper()} {gate.gate_id}: {gate.reason} Proxima acao: {gate.next_action}")
    return lines


def quality_to_markdown(quality_reports: Sequence[PlatformQualityReport]) -> str:
    lines = ["# Quality Gate Mais Humano", ""]
    lines.extend(f"- {line}" for line in quality_summary_lines(quality_reports))
    lines.append("")
    for quality in sorted(quality_reports, key=lambda item: item.platform_id):
        lines.append(f"## {quality.platform_id}")
        lines.append("")
        lines.append(f"- technical_ready: `{quality.technical_ready}`")
        lines.append(f"- human_ready: `{quality.human_ready}`")
        lines.append(f"- blockers: `{quality.blocker_count}`")
        lines.append(f"- warnings: `{quality.warning_count}`")
        for gate in quality.gates:
            status = "ok" if gate.passed else gate.severity
            lines.append(f"- {gate.gate_id}: {status} - {gate.reason}")
        lines.append("")
    return "\n".join(lines).strip() + "\n"


def quality_to_rows(quality_reports: Sequence[PlatformQualityReport]) -> list[list[str]]:
    rows: list[list[str]] = []
    for item in sorted(quality_reports, key=lambda quality: quality.platform_id):
        rows.append(
            [
                item.platform_id,
                "yes" if item.technical_ready else "no",
                "yes" if item.human_ready else "no",
                str(item.blocker_count),
                str(item.warning_count),
            ]
        )
    return rows

