"""Compile governance findings into service-order continuity."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Iterable, Sequence

from .governance_models import EcosystemGovernancePortfolio, GovernanceOrderCandidate
from .models import OrderStatus, OrderType, ServiceOrder, incrementing_id, merge_unique, slugify


@dataclass(slots=True)
class CompiledOrderSet:
    """Service-order set produced from recommendations and governance checks."""

    service_orders: tuple[ServiceOrder, ...]
    source_candidates: tuple[GovernanceOrderCandidate, ...]
    executive_count: int
    managerial_count: int
    notes: tuple[str, ...]

    def to_dict(self) -> dict[str, object]:
        return {
            "service_orders": [order.to_dict() for order in self.service_orders],
            "source_candidates": [candidate.to_dict() for candidate in self.source_candidates],
            "executive_count": self.executive_count,
            "managerial_count": self.managerial_count,
            "notes": self.notes,
        }


def priority_rank(value: str) -> int:
    lowered = value.lower()
    if lowered in {"critica", "critico", "critical"}:
        return 4
    if lowered in {"alta", "high"}:
        return 3
    if lowered in {"media", "medium"}:
        return 2
    if lowered in {"baixa", "low"}:
        return 1
    return 0


def candidate_sort_key(candidate: GovernanceOrderCandidate) -> tuple[int, str, str]:
    return (-priority_rank(candidate.priority), candidate.platform_id, candidate.title)


def candidate_to_service_order(candidate: GovernanceOrderCandidate, index: int, project_id: str = "tudo-para-ia-mais-humana") -> ServiceOrder:
    prefix = "EXECUTIVA" if candidate.order_type == OrderType.EXECUTIVE else "GERENCIAL"
    return ServiceOrder(
        order_id=incrementing_id(prefix, index, candidate.title),
        order_type=candidate.order_type,
        project_id=project_id,
        title=candidate.title,
        purpose=candidate.purpose,
        object_scope=(
            f"Plataforma relacionada: {candidate.platform_id}. "
            "Checks de origem: " + ", ".join(candidate.source_check_ids)
        ),
        reason=candidate.reason,
        expected_result=candidate.expected_result,
        affected_paths=candidate.affected_paths,
        validations=candidate.validations,
        ready_criteria=(
            "check de governanca reavaliado",
            "evidencia registrada",
            "validacao executada ou pendencia real declarada",
            "SQL semantico atualizado",
        ),
        status=OrderStatus.PLANNED,
        priority=candidate.priority,
    )


def dedupe_service_orders(orders: Iterable[ServiceOrder]) -> tuple[ServiceOrder, ...]:
    seen: set[tuple[str, str, str]] = set()
    output: list[ServiceOrder] = []
    for order in orders:
        key = (order.order_type.value, slugify(order.title), order.object_scope[:80])
        if key in seen:
            continue
        seen.add(key)
        output.append(order)
    return tuple(output)


def select_candidates(candidates: Sequence[GovernanceOrderCandidate], order_type: OrderType, limit: int) -> tuple[GovernanceOrderCandidate, ...]:
    typed = [candidate for candidate in candidates if candidate.order_type == order_type]
    typed.sort(key=candidate_sort_key)
    return tuple(typed[:limit])


def compile_governance_orders(
    portfolio: EcosystemGovernancePortfolio,
    min_executive: int = 5,
    min_managerial: int = 5,
    project_id: str = "tudo-para-ia-mais-humana",
) -> CompiledOrderSet:
    executive_candidates = list(select_candidates(portfolio.order_candidates, OrderType.EXECUTIVE, min_executive))
    managerial_candidates = list(select_candidates(portfolio.order_candidates, OrderType.MANAGERIAL, min_managerial))
    notes: list[str] = []
    if len(executive_candidates) < min_executive:
        notes.append(
            f"Somente {len(executive_candidates)} candidatas executivas reais foram encontradas; "
            "nao foram criadas ordens artificiais."
        )
    if len(managerial_candidates) < min_managerial:
        notes.append(
            f"Somente {len(managerial_candidates)} candidatas gerenciais reais foram encontradas; "
            "nao foram criadas ordens artificiais."
        )
    orders: list[ServiceOrder] = []
    for index, candidate in enumerate(executive_candidates, start=1):
        orders.append(candidate_to_service_order(candidate, index, project_id))
    for index, candidate in enumerate(managerial_candidates, start=1):
        orders.append(candidate_to_service_order(candidate, index, project_id))
    service_orders = dedupe_service_orders(orders)
    return CompiledOrderSet(
        service_orders=service_orders,
        source_candidates=tuple(executive_candidates + managerial_candidates),
        executive_count=sum(1 for order in service_orders if order.order_type == OrderType.EXECUTIVE),
        managerial_count=sum(1 for order in service_orders if order.order_type == OrderType.MANAGERIAL),
        notes=tuple(notes),
    )


def merge_order_sets(primary: Sequence[ServiceOrder], governance: Sequence[ServiceOrder], min_executive: int = 5, min_managerial: int = 5) -> tuple[ServiceOrder, ...]:
    merged: list[ServiceOrder] = list(primary)
    executive_count = sum(1 for order in merged if order.order_type == OrderType.EXECUTIVE)
    managerial_count = sum(1 for order in merged if order.order_type == OrderType.MANAGERIAL)
    for order in governance:
        if order.order_type == OrderType.EXECUTIVE and executive_count >= min_executive:
            continue
        if order.order_type == OrderType.MANAGERIAL and managerial_count >= min_managerial:
            continue
        merged.append(order)
        if order.order_type == OrderType.EXECUTIVE:
            executive_count += 1
        else:
            managerial_count += 1
    return dedupe_service_orders(merged)


def compiled_orders_markdown(compiled: CompiledOrderSet) -> str:
    lines = [
        "# Ordens compiladas por governanca",
        "",
        f"- executivas: `{compiled.executive_count}`",
        f"- gerenciais: `{compiled.managerial_count}`",
        f"- candidatas de origem: `{len(compiled.source_candidates)}`",
        "",
    ]
    if compiled.notes:
        lines.append("## Observacoes")
        lines.append("")
        lines.extend(f"- {note}" for note in compiled.notes)
        lines.append("")
    lines.append("## Ordens")
    lines.append("")
    for order in compiled.service_orders:
        lines.append(f"### {order.order_id}")
        lines.append("")
        lines.append(f"- tipo: `{order.order_type.value}`")
        lines.append(f"- prioridade: `{order.priority}`")
        lines.append(f"- titulo: {order.title}")
        lines.append(f"- motivo: {order.reason}")
        lines.append(f"- resultado: {order.expected_result}")
        lines.append("- validacoes:")
        for validation in order.validations:
            lines.append(f"  - {validation}")
        lines.append("")
    return "\n".join(lines).strip() + "\n"


def order_coverage_rows(compiled: CompiledOrderSet) -> list[list[str]]:
    rows = [["order_id", "type", "priority", "title", "paths", "validations"]]
    for order in compiled.service_orders:
        rows.append(
            [
                order.order_id,
                order.order_type.value,
                order.priority,
                order.title,
                " | ".join(order.affected_paths),
                " | ".join(order.validations),
            ]
        )
    return rows


def source_candidate_rows(compiled: CompiledOrderSet) -> list[list[str]]:
    rows = [["candidate_id", "platform", "type", "priority", "title", "source_checks"]]
    for candidate in compiled.source_candidates:
        rows.append(
            [
                candidate.candidate_id,
                candidate.platform_id,
                candidate.order_type.value,
                candidate.priority,
                candidate.title,
                " | ".join(candidate.source_check_ids),
            ]
        )
    return rows


def active_queue_from_orders(orders: Sequence[ServiceOrder]) -> tuple[str, ...]:
    return tuple(order.order_id for order in orders if order.status == OrderStatus.PLANNED)


def explain_order_gap(compiled: CompiledOrderSet, order_type: OrderType, minimum: int = 5) -> str:
    actual = compiled.executive_count if order_type == OrderType.EXECUTIVE else compiled.managerial_count
    label = "executivas" if order_type == OrderType.EXECUTIVE else "gerenciais"
    if actual >= minimum:
        return f"Minimo de ordens {label} cumprido: {actual}/{minimum}."
    return f"Minimo de ordens {label} parcial: {actual}/{minimum}; faltam checks reais suficientes."


def order_set_summary(compiled: CompiledOrderSet) -> tuple[str, ...]:
    return (
        explain_order_gap(compiled, OrderType.EXECUTIVE),
        explain_order_gap(compiled, OrderType.MANAGERIAL),
        f"Candidatas usadas: {len(compiled.source_candidates)}.",
        f"Fila ativa compilada: {len(active_queue_from_orders(compiled.service_orders))}.",
    )


def combine_order_notes(*sets: CompiledOrderSet) -> tuple[str, ...]:
    notes: list[str] = []
    for item in sets:
        notes.extend(item.notes)
        notes.extend(order_set_summary(item))
    return merge_unique(notes)
