# Create telemetry module: fmatch/telemetry/rule_telemetry.py
from dataclasses import dataclass
from datetime import datetime, timedelta
from pathlib import Path
from typing import Dict, Optional
import os

from sqlalchemy import create_engine, text
from sqlalchemy.engine import make_url


@dataclass
class RuleHit:
    rule_name: str
    column: str
    dataset_hash: str
    timestamp: datetime
    score_impact: float
    chosen_algorithm: str


class RuleEngineTelemetry:
    def __init__(self, db_url: Optional[str] = None, db_path: Optional[Path] = None):
        raw_url = (
            db_url
            or os.getenv("RULE_TELEMETRY_DATABASE_URL")
            or os.getenv("DATABASE_URL")
        )

        if raw_url:
            url = make_url(raw_url)
            if url.drivername == "postgresql+asyncpg":
                url = url.set(drivername="postgresql+psycopg2")
            elif url.drivername == "postgresql":
                url = url.set(drivername="postgresql+psycopg2")
            self._engine = create_engine(url)
        else:
            db_path = db_path or Path.home() / ".fmatch" / "telemetry.db"
            db_path.parent.mkdir(parents=True, exist_ok=True)
            self._engine = create_engine(f"sqlite:///{db_path}")

        self._dialect = self._engine.dialect.name
        self._init_db()

    def _init_db(self) -> None:
        create_sql = """
            CREATE TABLE IF NOT EXISTS rule_hits (
                id BIGSERIAL PRIMARY KEY,
                rule_name TEXT NOT NULL,
                column_name TEXT NOT NULL,
                dataset_hash TEXT NOT NULL,
                timestamp TIMESTAMPTZ DEFAULT NOW(),
                score_impact DOUBLE PRECISION,
                chosen_algorithm TEXT,
                metadata TEXT
            )
        """
        if self._dialect == "sqlite":
            create_sql = """
                CREATE TABLE IF NOT EXISTS rule_hits (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    rule_name TEXT NOT NULL,
                    column_name TEXT NOT NULL,
                    dataset_hash TEXT NOT NULL,
                    timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
                    score_impact REAL,
                    chosen_algorithm TEXT,
                    metadata TEXT
                )
            """

        with self._engine.begin() as conn:
            conn.execute(text(create_sql))
            conn.execute(
                text(
                    "CREATE INDEX IF NOT EXISTS idx_rule_hits_timestamp "
                    "ON rule_hits (timestamp DESC)"
                )
            )

    def record_hit(self, rule_hit: RuleHit) -> None:
        """Record a rule hit in telemetry."""
        with self._engine.begin() as conn:
            conn.execute(
                text(
                    """
                    INSERT INTO rule_hits
                    (rule_name, column_name, dataset_hash, score_impact, chosen_algorithm)
                    VALUES (:rule_name, :column_name, :dataset_hash, :score_impact, :chosen_algorithm)
                    """
                ),
                {
                    "rule_name": rule_hit.rule_name,
                    "column_name": rule_hit.column,
                    "dataset_hash": rule_hit.dataset_hash,
                    "score_impact": rule_hit.score_impact,
                    "chosen_algorithm": rule_hit.chosen_algorithm,
                },
            )

    def get_rule_effectiveness(self, days: int = 30) -> Dict[str, Dict]:
        """Analyze rule effectiveness over time."""
        cutoff = datetime.utcnow() - timedelta(days=days)
        with self._engine.begin() as conn:
            results = conn.execute(
                text(
                    """
                    SELECT
                        rule_name,
                        COUNT(*) AS hit_count,
                        AVG(score_impact) AS avg_impact,
                        COUNT(DISTINCT dataset_hash) AS unique_datasets
                    FROM rule_hits
                    WHERE timestamp > :cutoff
                    GROUP BY rule_name
                    ORDER BY hit_count DESC
                    """
                ),
                {"cutoff": cutoff},
            ).fetchall()

        return {
            row[0]: {"hits": row[1], "avg_impact": row[2], "datasets_affected": row[3]}
            for row in results
        }
