from typing import cast

from pydantic import BaseModel

from cli.infrastructure.output import OutputFormat, OutputService
from cli.infrastructure.renderers.entity_renderer import FieldConfig
from cli.infrastructure.renderers.list_renderer import ColumnConfig
from alloy_runtime_types.dtos.templates import (
    TemplateValidationDependencyTraceEntry,
    ValidateTemplateResponse,
)


class _TemplateValidationSummary(BaseModel):
    validation_status: str
    renderable: bool
    createable: bool
    required_variables: str
    unresolved_dependencies: str
    circular_dependencies: str
    issue_count: int
    resolved_dependency_count: int


def present_validate_result(response: ValidateTemplateResponse) -> None:
    output = OutputService.get()

    if getattr(output, "format", OutputFormat.COMPACT) == OutputFormat.JSON:
        output.raw(response)
        return

    summary = _TemplateValidationSummary(
        validation_status=("renderable" if response.is_renderable else "issues found"),
        renderable=response.is_renderable,
        createable=response.is_createable,
        required_variables=_format_string_list(response.required_variables),
        unresolved_dependencies=_format_string_list(response.unresolved_dependencies),
        circular_dependencies=_format_cycles(response.circular_dependencies),
        issue_count=len(response.issues),
        resolved_dependency_count=len(response.resolved_dependencies),
    )
    output.entity(
        summary,
        "Template Validation",
        [
            FieldConfig("validation_status", "Template Validation"),
            FieldConfig("renderable", "Renderable"),
            FieldConfig("createable", "Createable"),
            FieldConfig("required_variables", "Required Variables"),
            FieldConfig("unresolved_dependencies", "Unresolved Dependencies"),
            FieldConfig("circular_dependencies", "Circular Dependencies"),
            FieldConfig("issue_count", "Validation Issues"),
            FieldConfig("resolved_dependency_count", "Resolved Dependencies"),
        ],
        raw_payload=response,
    )

    if response.resolved_dependencies:
        output.table(
            items=cast(list[BaseModel], response.resolved_dependencies),
            title="Resolved Dependencies",
            columns=[
                ColumnConfig("template_name", "Template"),
                ColumnConfig("depth", "Depth"),
                ColumnConfig("was_pinned", "Pinned"),
                ColumnConfig("template_version_id", "Version ID", str),
            ],
        )

    if response.issues:
        output.table(
            items=cast(list[BaseModel], response.issues),
            title="Validation Issues",
            columns=[
                ColumnConfig("code", "Code"),
                ColumnConfig("identifier", "Identifier", _format_optional_value),
                ColumnConfig("message", "Message"),
                ColumnConfig(
                    "dependency_trace",
                    "Dependency Trace",
                    _format_issue_trace,
                ),
            ],
        )
    elif response.dependency_trace:
        output.table(
            items=cast(list[BaseModel], response.dependency_trace),
            title="Dependency Trace",
            columns=[
                ColumnConfig("template_name", "Template", _format_optional_value),
                ColumnConfig("depth", "Depth"),
                ColumnConfig("source_kind", "Source"),
                ColumnConfig(
                    "template_version_id", "Version ID", _format_optional_value
                ),
            ],
        )


def _format_string_list(values: list[str]) -> str:
    if not values:
        return "(none)"
    return ", ".join(values)


def _format_cycles(cycles: list[list[str]]) -> str:
    if not cycles:
        return "(none)"
    return " | ".join(" -> ".join(cycle) for cycle in cycles)


def _format_optional_value(value: object) -> str:
    if value is None or value == "":
        return "(none)"
    return str(value)


def _format_issue_trace(trace: list[TemplateValidationDependencyTraceEntry]) -> str:
    if not trace:
        return "(none)"
    return " -> ".join(_format_trace_entry(item) for item in trace)


def _format_trace_entry(item: TemplateValidationDependencyTraceEntry) -> str:
    name = item.template_name or "(unknown)"
    return f"{name} [{item.source_kind}]"
