"""
Request/Response models for ETL run endpoint.

Pipeline (column/dataset-based) quality report types are here; contract (row-based)
quality is in api.models.quality.
"""

from __future__ import annotations

from typing import Any

from pydantic import BaseModel, Field

# -----------------------------------------------------------------------------
# Pipeline quality (column/dataset-based): row count, null rate, uniqueness, etc.
# -----------------------------------------------------------------------------


class PipelineQualityCheckResult(BaseModel):
    """Result of a single pipeline quality check (e.g. row_count, null_rate)."""

    check_name: str = Field(..., description="Human-readable check name")
    check_type: str = Field(
        ..., description="Check type: row_count, null_rate, uniqueness, expression"
    )
    status: str = Field(..., description="passed, failed, or skipped")
    severity: str = Field(..., description="fail or warn")
    message: str = Field(..., description="Descriptive message")
    details: dict[str, Any] = Field(
        default_factory=dict, description="Additional context"
    )


class PipelineQualityReportResponse(BaseModel):
    """Column/dataset-based quality result when pipeline load config includes quality_checks."""

    passed: bool = Field(..., description="True if no severity=FAIL checks failed")
    total_checks: int = Field(0, description="Number of checks run")
    failed_count: int = Field(0, description="Number of failed checks")
    warning_count: int = Field(
        0, description="Number of failed checks with severity=warn"
    )
    checks: list[PipelineQualityCheckResult] = Field(
        default_factory=list,
        description="Per-check results",
    )


def pipeline_quality_report_from_dict(
    data: dict[str, Any],
) -> PipelineQualityReportResponse:
    """Build PipelineQualityReportResponse from ETL QualityReport.to_dict() output."""
    checks = [
        PipelineQualityCheckResult(
            check_name=c["check_name"],
            check_type=c["check_type"],
            status=c["status"],
            severity=c["severity"],
            message=c["message"],
            details=c.get("details") or {},
        )
        for c in data.get("checks") or []
    ]
    return PipelineQualityReportResponse(
        passed=data.get("passed", True),
        total_checks=data.get("total_checks", 0),
        failed_count=data.get("failed_count", 0),
        warning_count=data.get("warning_count", 0),
        checks=checks,
    )


class EtlRunRequest(BaseModel):
    """Request model for running an ETL pipeline from YAML configs."""

    extract_yaml: str = Field(..., description="Extract config as YAML string")
    load_yaml: str = Field(..., description="Load config as YAML string")
    transform_yaml: str | None = Field(
        default=None,
        description="Optional transform config as YAML string",
    )
    variables: dict[str, str | None] | None = Field(
        default=None,
        description="Optional variables for ${VAR} substitution in configs",
    )
    settings_yaml: str | None = Field(
        default=None,
        description="Optional settings YAML (metadata_store, dlq, contract, lineage)",
    )
    dry_run: bool = Field(
        default=False,
        description="If True, extract and transform but do not load",
    )


class EtlRunResponse(BaseModel):
    """Response model for ETL pipeline run result (mirrors PipelineResult.to_dict())."""

    success: bool = Field(..., description="Whether the pipeline run succeeded")
    rows_extracted: int = Field(0, description="Number of rows extracted")
    rows_transformed: int = Field(0, description="Number of rows transformed")
    rows_loaded: int = Field(0, description="Number of rows loaded")
    rows_failed: int = Field(0, description="Number of rows that failed to load")
    # Validation tracking
    rows_quarantined_extract: int = Field(
        0,
        description="Number of rows quarantined at extract stage due to validation",
    )
    rows_quarantined_load: int = Field(
        0,
        description="Number of rows quarantined at load stage due to validation",
    )
    total_quarantined: int = Field(
        0,
        description="Total rows quarantined at both stages",
    )
    validation_errors_extract: list[str] = Field(
        default_factory=list,
        description="Validation error messages from extract stage",
    )
    validation_errors_load: list[str] = Field(
        default_factory=list,
        description="Validation error messages from load stage",
    )
    # Timing and metadata
    duration_seconds: float | None = Field(
        None,
        description="Total run duration in seconds",
    )
    batches_processed: int = Field(0, description="Number of batches processed")
    errors: list[str] = Field(default_factory=list, description="Error messages if any")
    pipeline_name: str | None = Field(None, description="Pipeline name if set")
    run_id: str | None = Field(None, description="Run identifier")
    lineage_events: list[dict] = Field(
        default_factory=list,
        description="OpenLineage event payloads emitted when lineage is enabled",
    )
    pipeline_quality_report: PipelineQualityReportResponse | None = Field(
        None,
        description="Column/dataset-based quality result when pipeline uses quality_checks",
    )
