#!/usr/bin/env python3
"""
Validation checks for DLR extracted_rows.csv / extracted_rows.json.
"""
from __future__ import annotations

import csv
import json
from pathlib import Path
from typing import Any, Dict, List

BASE = Path(__file__).resolve().parent

REQUIRED_FIELDS = [
    "company",
    "period",
    "metric_name",
    "raw_value",
    "normalized_value",
    "unit",
    "value_qualifier",
    "ownership_basis",
    "forecast_or_actual",
    "is_derived",
    "source_url",
    "source_location",
    "source_snippet",
    "snippet_support_status",
    "confidence",
    "caveat",
]

ALLOWED_UNITS = {"MW", "USD", "percent", "months"}
ALLOWED_OWNERSHIP = {"100% share", "Digital Realty share", "consolidated", "consolidated development projects"}
ALLOWED_CLASS = {"forecast", "actual"}
ALLOWED_DERIVED = {True, False, "true", "false", "True", "False"}


def load_json_rows() -> List[Dict[str, Any]]:
    with (BASE / "extracted_rows.json").open(encoding="utf-8") as f:
        return json.load(f)


def validate(rows: List[Dict[str, Any]]) -> Dict[str, Any]:
    errors: List[str] = []
    warnings: List[str] = []

    if len(rows) < 15:
        errors.append(f"minimum row count failed: expected >= 15, got {len(rows)}")

    for i, row in enumerate(rows, start=1):
        missing = [field for field in REQUIRED_FIELDS if field not in row or row[field] in ("", None)]
        if missing:
            errors.append(f"row {i} missing required fields: {missing}")

        if row.get("company") != "DLR":
            errors.append(f"row {i} company is not DLR")

        if row.get("unit") not in ALLOWED_UNITS:
            errors.append(f"row {i} unit not normalized: {row.get('unit')}")

        if row.get("ownership_basis") not in ALLOWED_OWNERSHIP:
            errors.append(f"row {i} unsupported ownership_basis: {row.get('ownership_basis')}")

        if row.get("forecast_or_actual") not in ALLOWED_CLASS:
            errors.append(f"row {i} invalid forecast_or_actual: {row.get('forecast_or_actual')}")

        if row.get("is_derived") not in ALLOWED_DERIVED:
            errors.append(f"row {i} invalid is_derived flag: {row.get('is_derived')}")

        if not str(row.get("source_url", "")).startswith("https://"):
            errors.append(f"row {i} source_url missing or not https")

        if row.get("snippet_support_status") != "supported":
            errors.append(f"row {i} snippet_support_status is not supported")

        snippet = str(row.get("source_snippet", ""))
        raw = str(row.get("raw_value", "")).replace("$", "").replace(",", "").replace("%", "")
        if row.get("value_qualifier") not in {"derived_qoq", "derived_sum", "range", "weighted_average_lag"}:
            compact_snippet = snippet.replace("$", "").replace(",", "").replace("%", "")
            if raw and raw not in compact_snippet:
                warnings.append(f"row {i} raw value not directly visible in compact snippet: {row.get('metric_name')}")

    derived_rows = [r for r in rows if r.get("is_derived") is True]
    if len(derived_rows) < 2:
        errors.append("expected at least two derived rows for qoq and sum handling")

    basis_counts = {}
    for r in rows:
        basis_counts[r["ownership_basis"]] = basis_counts.get(r["ownership_basis"], 0) + 1

    return {
        "status": "pass" if not errors else "fail",
        "row_count": len(rows),
        "errors": errors,
        "warnings": warnings,
        "checks": {
            "required_fields": "pass" if not any("missing required" in e for e in errors) else "fail",
            "minimum_row_count": "pass" if len(rows) >= 15 else "fail",
            "source_url_presence": "pass" if not any("source_url" in e for e in errors) else "fail",
            "unit_normalization": "pass" if not any("unit not normalized" in e for e in errors) else "fail",
            "ownership_basis": "pass" if not any("ownership_basis" in e for e in errors) else "fail",
            "forecast_or_actual": "pass" if not any("forecast_or_actual" in e for e in errors) else "fail",
            "derived_flag_handling": "pass" if not any("derived" in e for e in errors) else "fail",
            "snippet_provenance": "pass" if not any("snippet_support_status" in e for e in errors) else "fail",
        },
        "ownership_basis_counts": basis_counts,
    }


def main() -> None:
    rows = load_json_rows()
    report = validate(rows)
    with (BASE / "validation_report.json").open("w", encoding="utf-8") as f:
        json.dump(report, f, indent=2, ensure_ascii=False)
    if report["status"] != "pass":
        raise SystemExit(1)


if __name__ == "__main__":
    main()
