"""
Data Health Scorecard for FoundryGraph.

Computes and displays data quality metrics:
- Coverage: % of non-null values per field
- Freshness: % of records updated within 6/12/18 months
- Source Mix: Distribution of data sources from provenance
- Conflict Rate: % of records with conflicting values
- Pain Score: Prioritized action indicator

Usage:
    from g_gremlin.health_scorecard import run_scorecard
    scorecard = run_scorecard(source="bigquery")
    print(scorecard.to_dataframe())
    # Local DuckDB:
    # scorecard = run_scorecard(source="duckdb", db_path=Path("config/foundrygraph.duckdb"))
"""

from __future__ import annotations

import argparse
import os
from dataclasses import dataclass, field
from datetime import date
from pathlib import Path
from typing import Any, Dict, Iterable, List, Optional, Set

from g_gremlin.paths import gremlin_path

# DuckDB path - same as foundrygraph.py
LOCAL_DB_PATH = Path("config/foundrygraph.duckdb")
DEFAULT_BQ_PROJECT_ID = (
    os.getenv("FM_FOUNDRYGRAPH_PROJECT_ID")
    or os.getenv("GOOGLE_CLOUD_PROJECT")
    or "your-project-id"
)
DEFAULT_BQ_TABLE = os.getenv("FM_FOUNDRYGRAPH_BQ_TABLE", "foundrygraph_gold.companies_gold")


@dataclass
class FieldScore:
    """Score for a single field."""
    field_name: str
    total_rows: int
    non_null_rows: int
    coverage_pct: float
    fresh_6mo: int = 0
    fresh_12mo: int = 0
    fresh_18mo: int = 0
    freshness_pct_6mo: float = 0.0
    freshness_pct_12mo: float = 0.0
    freshness_pct_18mo: float = 0.0
    importance_weight: float = 0.5
    primary_lever: str = "SOURCE"
    conflict_count: int = 0
    conflict_rate: float = 0.0
    pain_score: float = 0.0
    top_sources: List[Dict[str, Any]] = field(default_factory=list)

    def to_dict(self) -> Dict[str, Any]:
        return {
            "field_name": self.field_name,
            "total_rows": self.total_rows,
            "non_null_rows": self.non_null_rows,
            "coverage_pct": self.coverage_pct,
            "fresh_6mo": self.fresh_6mo,
            "fresh_12mo": self.fresh_12mo,
            "fresh_18mo": self.fresh_18mo,
            "freshness_pct_18mo": self.freshness_pct_18mo,
            "importance_weight": self.importance_weight,
            "primary_lever": self.primary_lever,
            "conflict_count": self.conflict_count,
            "conflict_rate": self.conflict_rate,
            "pain_score": self.pain_score,
        }


@dataclass
class Scorecard:
    """Complete data health scorecard."""
    snapshot_date: date
    fields: List[FieldScore]
    total_rows: int = 0
    freshness_meaningful: bool = True  # False if all records have same date (bulk rebuild)
    source_name: str = "company_profiles"

    def to_dataframe(self):
        """Convert to pandas DataFrame for display."""
        try:
            import pandas as pd
            return pd.DataFrame([f.to_dict() for f in self.fields])
        except ImportError:
            return [f.to_dict() for f in self.fields]

    def by_lever(self) -> Dict[str, List[FieldScore]]:
        """Group fields by primary lever."""
        result: Dict[str, List[FieldScore]] = {}
        for f in self.fields:
            if f.primary_lever not in result:
                result[f.primary_lever] = []
            result[f.primary_lever].append(f)
        return result

    def top_pain(self, n: int = 5) -> List[FieldScore]:
        """Get top N fields by pain score."""
        return sorted(self.fields, key=lambda f: f.pain_score, reverse=True)[:n]

    def summary(self) -> str:
        """Generate a text summary of the scorecard."""
        lines = [
            f"Data Health Scorecard - {self.snapshot_date}",
            f"Total rows in {self.source_name}: {self.total_rows:,}",
        ]
        if not self.freshness_meaningful:
            lines.append("")
            lines.append("NOTE: Freshness tracking not meaningful (bulk rebuild detected).")
            lines.append("      Pain scores based on coverage only. Add per-field timestamps for freshness.")
        lines.append("")
        lines.append("Top Pain Points:")
        for f in self.top_pain(5):
            if self.freshness_meaningful:
                lines.append(
                    f"  {f.field_name}: pain={f.pain_score:.1f} "
                    f"(coverage={f.coverage_pct:.1f}%, fresh={f.freshness_pct_18mo:.1f}%, "
                    f"lever={f.primary_lever})"
                )
            else:
                lines.append(
                    f"  {f.field_name}: pain={f.pain_score:.1f} "
                    f"(coverage={f.coverage_pct:.1f}%, lever={f.primary_lever})"
                )
        lines.append("")
        lines.append("By Primary Lever:")
        for lever, fields in sorted(self.by_lever().items()):
            total_pain = sum(f.pain_score for f in fields)
            lines.append(f"  {lever}: {len(fields)} fields, total_pain={total_pain:.1f}")
        return "\n".join(lines)


def _get_duckdb_connection():
    """Get a read-only DuckDB connection."""
    try:
        import duckdb
    except ImportError:
        raise RuntimeError("duckdb not installed. Run: pip install duckdb")

    db_path = LOCAL_DB_PATH
    if not db_path.exists():
        # Try alternate locations
        candidates = [
            Path.cwd() / "config" / "foundrygraph.duckdb",
            gremlin_path("foundrygraph.duckdb"),
        ]
        for path in candidates:
            if path.exists():
                db_path = path
                break
        else:
            raise RuntimeError(
                "FoundryGraph database not found. "
                "Expected at: config/foundrygraph.duckdb"
            )
    return duckdb.connect(str(db_path), read_only=True)


def _get_bigquery_client(project_id: Optional[str] = None):
    try:
        from google.cloud import bigquery
    except ImportError as exc:
        raise RuntimeError("google-cloud-bigquery not installed. Run: pip install google-cloud-bigquery") from exc

    project = project_id or DEFAULT_BQ_PROJECT_ID
    if not project or project == "your-project-id":
        raise RuntimeError("BigQuery project not configured. Set FM_FOUNDRYGRAPH_PROJECT_ID or GOOGLE_CLOUD_PROJECT.")
    return bigquery.Client(project=project)


def _normalize_table_id(project_id: str, table_id: str) -> str:
    if table_id.count(".") == 1:
        return f"{project_id}.{table_id}"
    return table_id


def _get_bq_columns(bq_client, table_id: str) -> Set[str]:
    table = bq_client.get_table(table_id)
    return {field.name for field in table.schema}


def _pick_column(columns: Set[str], candidates: Iterable[str]) -> Optional[str]:
    for candidate in candidates:
        if candidate in columns:
            return candidate
    return None


def _build_bq_field_exprs(columns: Set[str]) -> Dict[str, Optional[str]]:
    domain_col = _pick_column(columns, ["primary_domain", "domain"])
    label_col = _pick_column(columns, ["label", "canonical_name", "name"])
    ticker_col = _pick_column(columns, ["stock_ticker", "ticker"])
    linkedin_col = _pick_column(columns, ["linkedin_url", "linkedin"])
    parent_col = _pick_column(columns, ["parent_org", "parent_organization", "ultimate_parent_id"])
    industry_col = _pick_column(columns, ["primary_industry_id", "industry"])
    hq_country_col = _pick_column(columns, ["hq_country"])
    employees_col = _pick_column(columns, ["employees"])
    revenue_col = _pick_column(columns, ["revenue"])
    headquarters_col = _pick_column(columns, ["headquarters"])
    industries_col = _pick_column(columns, ["industries"])

    field_exprs = {
        "domain": f"{domain_col} IS NOT NULL AND {domain_col} != ''" if domain_col else None,
        "label": f"{label_col} IS NOT NULL AND {label_col} != ''" if label_col else None,
        "employees": f"JSON_VALUE({employees_col}, '$.count') IS NOT NULL" if employees_col else None,
        "industry": None,
        "headquarters": None,
        "revenue": f"JSON_VALUE({revenue_col}, '$.amount') IS NOT NULL" if revenue_col else None,
        "linkedin": f"{linkedin_col} IS NOT NULL AND {linkedin_col} != ''" if linkedin_col else None,
        "parent_org": f"{parent_col} IS NOT NULL AND {parent_col} != ''" if parent_col else None,
        "ticker": f"{ticker_col} IS NOT NULL AND {ticker_col} != ''" if ticker_col else None,
    }

    if industry_col:
        field_exprs["industry"] = f"{industry_col} IS NOT NULL AND {industry_col} != ''"
    elif industries_col:
        field_exprs["industry"] = (
            f"JSON_VALUE({industries_col}, '$[0].id') IS NOT NULL OR "
            f"JSON_VALUE({industries_col}, '$[0]') IS NOT NULL"
        )

    if hq_country_col:
        field_exprs["headquarters"] = f"{hq_country_col} IS NOT NULL AND {hq_country_col} != ''"
    elif headquarters_col:
        field_exprs["headquarters"] = (
            f"JSON_VALUE({headquarters_col}, '$.country') IS NOT NULL OR "
            f"JSON_VALUE({headquarters_col}, '$[0].country') IS NOT NULL"
        )

    return field_exprs


def _detect_timestamp_column(columns: Set[str]) -> Optional[str]:
    for candidate in ["updated_at", "last_updated", "last_refreshed", "ai_screened_at"]:
        if candidate in columns:
            return candidate
    return None


def _calculate_coverage_bq(bq_client, table_id: str) -> Dict[str, Dict[str, Any]]:
    columns = _get_bq_columns(bq_client, table_id)
    field_exprs = _build_bq_field_exprs(columns)

    select_parts = ["COUNT(*) AS total_rows"]
    for field_name, expr in field_exprs.items():
        if expr:
            select_parts.append(f"COUNTIF({expr}) AS {field_name}_filled")
        else:
            select_parts.append(f"0 AS {field_name}_filled")

    query = f"""
        SELECT
            {", ".join(select_parts)}
        FROM `{table_id}`
    """
    result = bq_client.query(query).result()
    row = next(iter(result), None)
    row = dict(row) if row else {}
    total = row.get("total_rows", 0) or 0

    results = {}
    for field_name in field_exprs.keys():
        non_null = row.get(f"{field_name}_filled", 0) or 0
        results[field_name] = {
            "total_rows": total,
            "non_null_rows": non_null,
            "coverage_pct": round(non_null * 100.0 / total, 2) if total > 0 else 0.0,
        }
    return results


def _calculate_freshness_bq(bq_client, table_id: str, timestamp_col: str) -> Dict[str, Dict[str, Any]]:
    columns = _get_bq_columns(bq_client, table_id)
    field_exprs = _build_bq_field_exprs(columns)
    ts_expr = f"CAST({timestamp_col} AS TIMESTAMP)"

    select_parts = []
    for field_name, expr in field_exprs.items():
        if not expr:
            select_parts.append(f"0 AS {field_name}_total")
            select_parts.append(f"0 AS {field_name}_fresh_6mo")
            select_parts.append(f"0 AS {field_name}_fresh_12mo")
            select_parts.append(f"0 AS {field_name}_fresh_18mo")
            continue
        select_parts.append(f"COUNTIF({expr}) AS {field_name}_total")
        select_parts.append(
            f"COUNTIF({expr} AND {ts_expr} >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 6 MONTH)) "
            f"AS {field_name}_fresh_6mo"
        )
        select_parts.append(
            f"COUNTIF({expr} AND {ts_expr} >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 12 MONTH)) "
            f"AS {field_name}_fresh_12mo"
        )
        select_parts.append(
            f"COUNTIF({expr} AND {ts_expr} >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 18 MONTH)) "
            f"AS {field_name}_fresh_18mo"
        )

    query = f"""
        SELECT
            {", ".join(select_parts)}
        FROM `{table_id}`
    """
    result = bq_client.query(query).result()
    row = next(iter(result), None)
    row = dict(row) if row else {}

    results = {}
    for field_name in field_exprs.keys():
        total = row.get(f"{field_name}_total", 0) or 0
        fresh_6 = row.get(f"{field_name}_fresh_6mo", 0) or 0
        fresh_12 = row.get(f"{field_name}_fresh_12mo", 0) or 0
        fresh_18 = row.get(f"{field_name}_fresh_18mo", 0) or 0
        results[field_name] = {
            "total_filled": total,
            "fresh_6mo": fresh_6,
            "fresh_12mo": fresh_12,
            "fresh_18mo": fresh_18,
            "freshness_pct_6mo": round(fresh_6 * 100.0 / total, 2) if total > 0 else 0.0,
            "freshness_pct_12mo": round(fresh_12 * 100.0 / total, 2) if total > 0 else 0.0,
            "freshness_pct_18mo": round(fresh_18 * 100.0 / total, 2) if total > 0 else 0.0,
        }
    return results


def _freshness_meaningful_bq(bq_client, table_id: str, timestamp_col: str) -> bool:
    query = f"""
        SELECT
            MIN(CAST({timestamp_col} AS TIMESTAMP)) AS min_ts,
            MAX(CAST({timestamp_col} AS TIMESTAMP)) AS max_ts,
            TIMESTAMP_DIFF(
                MAX(CAST({timestamp_col} AS TIMESTAMP)),
                MIN(CAST({timestamp_col} AS TIMESTAMP)),
                DAY
            ) AS date_spread
        FROM `{table_id}`
        WHERE {timestamp_col} IS NOT NULL
    """
    result = bq_client.query(query).result()
    row = next(iter(result), None)
    row = dict(row) if row else {}
    date_spread = row.get("date_spread")
    return (date_spread or 0) > 7


def _calculate_conflicts_bq(bq_client, project_id: str) -> Dict[str, Dict[str, Any]]:
    query = f"""
        WITH domain_analysis AS (
            SELECT
                wikidata_id,
                COUNT(DISTINCT domain) AS domain_count,
                COUNT(DISTINCT IF(confidence >= 0.85, domain, NULL)) AS high_conf_domains
            FROM `{project_id}.foundrygraph_silver.domains`
            WHERE confidence >= 0.70
            GROUP BY wikidata_id
        )
        SELECT
            COUNT(*) AS total_companies,
            SUM(IF(high_conf_domains > 1, 1, 0)) AS conflict_count
        FROM domain_analysis
    """
    try:
        result = bq_client.query(query).result()
        row = next(iter(result), None)
        row = dict(row) if row else {}
        total = row.get("total_companies", 0) or 0
        conflicts = row.get("conflict_count", 0) or 0
        return {
            "domain": {
                "total_companies": total,
                "conflict_count": conflicts,
                "conflict_rate": round(conflicts * 100.0 / total, 2) if total > 0 else 0.0,
            }
        }
    except Exception:
        return {"domain": {"conflict_count": 0, "conflict_rate": 0.0}}


def _calculate_coverage(conn) -> Dict[str, Dict[str, Any]]:
    """Calculate coverage for each field."""
    # Field definitions with their SQL expressions
    fields = {
        "domain": "domain IS NOT NULL AND domain <> ''",
        "label": "label IS NOT NULL AND label <> ''",
        "employees": "employees IS NOT NULL",
        "industry": "industry IS NOT NULL AND industry <> ''",
        "headquarters": "headquarters IS NOT NULL",
        "revenue": "revenue IS NOT NULL",
        "linkedin": "linkedin IS NOT NULL AND linkedin <> ''",
        "parent_org": "parent_org IS NOT NULL",
        "ticker": "ticker IS NOT NULL AND ticker <> ''",
    }

    results = {}
    for field_name, expr in fields.items():
        query = f"""
            SELECT
                COUNT(*) AS total_rows,
                SUM(CASE WHEN {expr} THEN 1 ELSE 0 END) AS non_null_rows
            FROM company_profiles
        """
        row = conn.execute(query).fetchone()
        total = row[0] or 0
        non_null = row[1] or 0
        results[field_name] = {
            "total_rows": total,
            "non_null_rows": non_null,
            "coverage_pct": round(non_null * 100.0 / total, 2) if total > 0 else 0.0,
        }
    return results


def _calculate_freshness(conn) -> Dict[str, Dict[str, Any]]:
    """Calculate freshness for each field (record-level using last_updated)."""
    fields = {
        "domain": "domain IS NOT NULL AND domain <> ''",
        "label": "label IS NOT NULL AND label <> ''",
        "employees": "employees IS NOT NULL",
        "industry": "industry IS NOT NULL AND industry <> ''",
        "headquarters": "headquarters IS NOT NULL",
        "revenue": "revenue IS NOT NULL",
        "linkedin": "linkedin IS NOT NULL AND linkedin <> ''",
        "parent_org": "parent_org IS NOT NULL",
        "ticker": "ticker IS NOT NULL AND ticker <> ''",
    }

    results = {}
    for field_name, expr in fields.items():
        query = f"""
            SELECT
                COUNT(*) FILTER (WHERE {expr}) AS total_filled,
                COUNT(*) FILTER (WHERE {expr}
                    AND last_updated >= CURRENT_DATE - INTERVAL '6 months') AS fresh_6mo,
                COUNT(*) FILTER (WHERE {expr}
                    AND last_updated >= CURRENT_DATE - INTERVAL '12 months') AS fresh_12mo,
                COUNT(*) FILTER (WHERE {expr}
                    AND last_updated >= CURRENT_DATE - INTERVAL '18 months') AS fresh_18mo
            FROM company_profiles
        """
        row = conn.execute(query).fetchone()
        total = row[0] or 0
        fresh_6 = row[1] or 0
        fresh_12 = row[2] or 0
        fresh_18 = row[3] or 0
        results[field_name] = {
            "total_filled": total,
            "fresh_6mo": fresh_6,
            "fresh_12mo": fresh_12,
            "fresh_18mo": fresh_18,
            "freshness_pct_6mo": round(fresh_6 * 100.0 / total, 2) if total > 0 else 0.0,
            "freshness_pct_12mo": round(fresh_12 * 100.0 / total, 2) if total > 0 else 0.0,
            "freshness_pct_18mo": round(fresh_18 * 100.0 / total, 2) if total > 0 else 0.0,
        }
    return results


def _calculate_conflicts(conn) -> Dict[str, Dict[str, Any]]:
    """Calculate conflict rates for domain field."""
    # Domain conflict: multiple domains with high confidence
    query = """
        WITH domain_analysis AS (
            SELECT
                wikidata_id,
                COUNT(DISTINCT domain) AS domain_count,
                COUNT(DISTINCT CASE WHEN confidence >= 0.85 THEN domain END) AS high_conf_domains
            FROM company_domains
            WHERE confidence >= 0.70
            GROUP BY wikidata_id
        )
        SELECT
            COUNT(*) AS total_companies,
            SUM(CASE WHEN high_conf_domains > 1 THEN 1 ELSE 0 END) AS conflict_count
        FROM domain_analysis
    """
    try:
        row = conn.execute(query).fetchone()
        total = row[0] or 0
        conflicts = row[1] or 0
        return {
            "domain": {
                "total_companies": total,
                "conflict_count": conflicts,
                "conflict_rate": round(conflicts * 100.0 / total, 2) if total > 0 else 0.0,
            }
        }
    except Exception:
        # Table might not exist
        return {"domain": {"conflict_count": 0, "conflict_rate": 0.0}}


# Field importance and primary levers (from field_registry design)
FIELD_CONFIG = {
    "domain": {"importance": 1.0, "lever": "MATCHING"},
    "label": {"importance": 1.0, "lever": "SOURCE"},
    "employees": {"importance": 0.8, "lever": "SOURCE"},
    "industry": {"importance": 0.7, "lever": "MATCHING"},
    "headquarters": {"importance": 0.6, "lever": "REFRESH"},
    "revenue": {"importance": 0.5, "lever": "SOURCE"},
    "linkedin": {"importance": 0.5, "lever": "MATCHING"},
    "parent_org": {"importance": 0.4, "lever": "SOURCE"},
    "ticker": {"importance": 0.3, "lever": "REFRESH"},
}


def run_scorecard(
    source: str = "bigquery",
    db_path: Optional[Path] = None,
    project_id: Optional[str] = None,
    table_id: Optional[str] = None,
) -> Scorecard:
    """
    Run the data health scorecard against BigQuery or local DuckDB.

    Returns a Scorecard object with coverage, freshness, and pain scores.
    """
    source_name = "company_profiles"
    freshness_meaningful = True

    if source == "duckdb":
        global LOCAL_DB_PATH
        if db_path:
            LOCAL_DB_PATH = db_path

        conn = _get_duckdb_connection()

        total_rows = conn.execute("SELECT COUNT(*) FROM company_profiles").fetchone()[0]
        date_check = conn.execute("""
            SELECT
                MIN(last_updated) as min_date,
                MAX(last_updated) as max_date,
                DATEDIFF('day', MIN(last_updated), MAX(last_updated)) as date_spread
            FROM company_profiles
        """).fetchone()
        date_spread = date_check[2] or 0
        freshness_meaningful = date_spread > 7

        coverage = _calculate_coverage(conn)
        freshness = _calculate_freshness(conn) if freshness_meaningful else {}
        conflicts = _calculate_conflicts(conn)
        conn.close()
    else:
        project = project_id or DEFAULT_BQ_PROJECT_ID
        table_id = _normalize_table_id(project, table_id or DEFAULT_BQ_TABLE)
        bq_client = _get_bigquery_client(project)

        coverage = _calculate_coverage_bq(bq_client, table_id)
        total_rows = next(iter(coverage.values()))["total_rows"] if coverage else 0
        source_name = table_id

        columns = _get_bq_columns(bq_client, table_id)
        timestamp_col = _detect_timestamp_column(columns)
        if timestamp_col:
            freshness_meaningful = _freshness_meaningful_bq(bq_client, table_id, timestamp_col)
            freshness = _calculate_freshness_bq(bq_client, table_id, timestamp_col) if freshness_meaningful else {}
        else:
            freshness_meaningful = False
            freshness = {}
        conflicts = _calculate_conflicts_bq(bq_client, project)

    # Build field scores
    field_scores = []
    for field_name, config in FIELD_CONFIG.items():
        cov = coverage.get(field_name, {})
        fresh = freshness.get(field_name, {})
        conf = conflicts.get(field_name, {})

        coverage_pct = cov.get("coverage_pct", 0.0)
        freshness_pct = fresh.get("freshness_pct_18mo", 100.0) if freshness_meaningful else None
        importance = config["importance"]

        # Pain score: importance × (1-coverage)
        # If freshness is meaningful, multiply by (1-freshness)
        if freshness_meaningful and freshness_pct is not None:
            pain = importance * (1 - coverage_pct / 100) * (1 - freshness_pct / 100) * 100
        else:
            # Freshness not meaningful (bulk rebuild) - use coverage-only pain
            pain = importance * (1 - coverage_pct / 100) * 100

        score = FieldScore(
            field_name=field_name,
            total_rows=cov.get("total_rows", 0),
            non_null_rows=cov.get("non_null_rows", 0),
            coverage_pct=coverage_pct,
            fresh_6mo=fresh.get("fresh_6mo", 0),
            fresh_12mo=fresh.get("fresh_12mo", 0),
            fresh_18mo=fresh.get("fresh_18mo", 0),
            freshness_pct_6mo=fresh.get("freshness_pct_6mo", 0.0),
            freshness_pct_12mo=fresh.get("freshness_pct_12mo", 0.0),
            freshness_pct_18mo=freshness_pct if freshness_pct is not None else 0.0,
            importance_weight=importance,
            primary_lever=config["lever"],
            conflict_count=conf.get("conflict_count", 0),
            conflict_rate=conf.get("conflict_rate", 0.0),
            pain_score=round(pain, 2),
        )
        field_scores.append(score)

    # Sort by pain score descending
    field_scores.sort(key=lambda f: f.pain_score, reverse=True)

    return Scorecard(
        snapshot_date=date.today(),
        fields=field_scores,
        total_rows=total_rows,
        freshness_meaningful=freshness_meaningful,
        source_name=source_name,
    )


def print_scorecard(scorecard: Optional[Scorecard] = None) -> None:
    """Print a formatted scorecard to stdout."""
    if scorecard is None:
        scorecard = run_scorecard()

    print(scorecard.summary())
    print()
    print("Detailed Metrics:")
    print("-" * 100)
    print(
        f"{'Field':<15} {'Coverage':>10} {'Fresh18mo':>10} {'Importance':>10} "
        f"{'Lever':<10} {'Pain':>8} {'Action'}"
    )
    print("-" * 100)
    for f in scorecard.fields:
        action = _get_action_hint(f)
        print(
            f"{f.field_name:<15} {f.coverage_pct:>9.1f}% {f.freshness_pct_18mo:>9.1f}% "
            f"{f.importance_weight:>10.1f} {f.primary_lever:<10} {f.pain_score:>8.1f} {action}"
        )


def _get_action_hint(field: FieldScore) -> str:
    """Generate action hint based on metrics."""
    if field.pain_score < 5:
        return "OK"
    if field.primary_lever == "SOURCE":
        return "Need new data provider"
    if field.primary_lever == "MATCHING":
        return "Fix resolution logic"
    if field.primary_lever == "REFRESH":
        return "Run enrichment on stale"
    if field.primary_lever == "MODELING":
        return "Derive from other fields"
    return "Investigate"


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="FoundryGraph data health scorecard.")
    source_group = parser.add_mutually_exclusive_group()
    source_group.add_argument("--bigquery", action="store_true", help="Use BigQuery (default).")
    source_group.add_argument("--duckdb", action="store_true", help="Use local DuckDB.")
    parser.add_argument("--project", default=DEFAULT_BQ_PROJECT_ID, help="BigQuery project ID")
    parser.add_argument("--table", default=DEFAULT_BQ_TABLE, help="BigQuery table (dataset.table or project.dataset.table)")
    parser.add_argument("--db-path", type=Path, help="DuckDB path for local scorecard")
    args = parser.parse_args()

    source = "duckdb" if args.duckdb else "bigquery"
    scorecard = run_scorecard(
        source=source,
        db_path=args.db_path,
        project_id=args.project,
        table_id=args.table,
    )
    print_scorecard(scorecard)
