"""SQLite store for scan history and trend tracking."""

from __future__ import annotations

import json
import sqlite3
import time
from dataclasses import dataclass, field, asdict
from pathlib import Path
from typing import Any


@dataclass
class ScanRecord:
    """A single scan result stored in the database."""

    scan_id: str
    repo_path: str
    branch: str
    commit_sha: str
    timestamp: float
    total_score: float
    file_count: int
    total_issues: int
    summary: dict[str, Any] = field(default_factory=dict)
    details: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for serialization."""
        return asdict(self)


class DebtStore:
    """SQLite-backed store for DebtMap scan history."""

    def __init__(self, db_path: str | Path | None = None) -> None:
        if db_path is None:
            store_dir = Path.home() / ".debtmap"
            store_dir.mkdir(parents=True, exist_ok=True)
            db_path = store_dir / "debtmap.db"
        self.db_path = Path(db_path)
        self._init_db()

    def _init_db(self) -> None:
        """Create tables if they don't exist."""
        with sqlite3.connect(self.db_path) as conn:
            conn.execute("""
                CREATE TABLE IF NOT EXISTS scans (
                    scan_id TEXT PRIMARY KEY,
                    repo_path TEXT NOT NULL,
                    branch TEXT NOT NULL DEFAULT '',
                    commit_sha TEXT NOT NULL DEFAULT '',
                    timestamp REAL NOT NULL,
                    total_score REAL NOT NULL,
                    file_count INTEGER NOT NULL DEFAULT 0,
                    total_issues INTEGER NOT NULL DEFAULT 0,
                    summary TEXT NOT NULL DEFAULT '{}',
                    details TEXT NOT NULL DEFAULT '{}'
                )
            """)
            conn.execute("""
                CREATE INDEX IF NOT EXISTS idx_scans_repo
                ON scans(repo_path, timestamp)
            """)
            conn.execute("""
                CREATE TABLE IF NOT EXISTS incidents (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    repo_path TEXT NOT NULL,
                    file_path TEXT NOT NULL,
                    incident_id TEXT NOT NULL,
                    severity TEXT NOT NULL DEFAULT 'medium',
                    timestamp REAL NOT NULL,
                    description TEXT NOT NULL DEFAULT ''
                )
            """)
            conn.execute("""
                CREATE TABLE IF NOT EXISTS velocity_samples (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    repo_path TEXT NOT NULL,
                    module TEXT NOT NULL,
                    sprint TEXT NOT NULL DEFAULT '',
                    planned_points REAL NOT NULL DEFAULT 0,
                    delivered_points REAL NOT NULL DEFAULT 0,
                    timestamp REAL NOT NULL
                )
            """)

    def save_scan(self, record: ScanRecord) -> None:
        """Persist a scan record."""
        with sqlite3.connect(self.db_path) as conn:
            conn.execute(
                """INSERT OR REPLACE INTO scans
                   (scan_id, repo_path, branch, commit_sha, timestamp,
                    total_score, file_count, total_issues, summary, details)
                   VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
                (
                    record.scan_id,
                    record.repo_path,
                    record.branch,
                    record.commit_sha,
                    record.timestamp,
                    record.total_score,
                    record.file_count,
                    record.total_issues,
                    json.dumps(record.summary),
                    json.dumps(record.details),
                ),
            )

    def get_scan(self, scan_id: str) -> ScanRecord | None:
        """Retrieve a scan by ID."""
        with sqlite3.connect(self.db_path) as conn:
            conn.row_factory = sqlite3.Row
            row = conn.execute(
                "SELECT * FROM scans WHERE scan_id = ?", (scan_id,)
            ).fetchone()
            if row is None:
                return None
            return ScanRecord(
                scan_id=row["scan_id"],
                repo_path=row["repo_path"],
                branch=row["branch"],
                commit_sha=row["commit_sha"],
                timestamp=row["timestamp"],
                total_score=row["total_score"],
                file_count=row["file_count"],
                total_issues=row["total_issues"],
                summary=json.loads(row["summary"]),
                details=json.loads(row["details"]),
            )

    def get_scans_for_repo(
        self, repo_path: str, limit: int = 50
    ) -> list[ScanRecord]:
        """Get recent scans for a repository, newest first."""
        with sqlite3.connect(self.db_path) as conn:
            conn.row_factory = sqlite3.Row
            rows = conn.execute(
                """SELECT * FROM scans WHERE repo_path = ?
                   ORDER BY timestamp DESC LIMIT ?""",
                (repo_path, limit),
            ).fetchall()
            return [
                ScanRecord(
                    scan_id=r["scan_id"],
                    repo_path=r["repo_path"],
                    branch=r["branch"],
                    commit_sha=r["commit_sha"],
                    timestamp=r["timestamp"],
                    total_score=r["total_score"],
                    file_count=r["file_count"],
                    total_issues=r["total_issues"],
                    summary=json.loads(r["summary"]),
                    details=json.loads(r["details"]),
                )
                for r in rows
            ]

    def record_incident(
        self,
        repo_path: str,
        file_path: str,
        incident_id: str,
        severity: str = "medium",
        description: str = "",
    ) -> None:
        """Record a production incident linked to a file."""
        with sqlite3.connect(self.db_path) as conn:
            conn.execute(
                """INSERT INTO incidents
                   (repo_path, file_path, incident_id, severity, timestamp, description)
                   VALUES (?, ?, ?, ?, ?, ?)""",
                (repo_path, file_path, incident_id, severity, time.time(), description),
            )

    def get_incidents_for_file(self, repo_path: str, file_path: str) -> list[dict]:
        """Get all incidents associated with a file."""
        with sqlite3.connect(self.db_path) as conn:
            conn.row_factory = sqlite3.Row
            rows = conn.execute(
                """SELECT * FROM incidents
                   WHERE repo_path = ? AND file_path = ?
                   ORDER BY timestamp DESC""",
                (repo_path, file_path),
            ).fetchall()
            return [dict(r) for r in rows]

    def get_incident_hotspots(self, repo_path: str, limit: int = 20) -> list[dict]:
        """Get files with the most incidents."""
        with sqlite3.connect(self.db_path) as conn:
            conn.row_factory = sqlite3.Row
            rows = conn.execute(
                """SELECT file_path, COUNT(*) as incident_count,
                   SUM(CASE WHEN severity = 'critical' THEN 4
                            WHEN severity = 'high' THEN 3
                            WHEN severity = 'medium' THEN 2
                            ELSE 1 END) as weighted_score
                   FROM incidents WHERE repo_path = ?
                   GROUP BY file_path
                   ORDER BY weighted_score DESC LIMIT ?""",
                (repo_path, limit),
            ).fetchall()
            return [dict(r) for r in rows]

    def record_velocity(
        self,
        repo_path: str,
        module: str,
        sprint: str,
        planned_points: float,
        delivered_points: float,
    ) -> None:
        """Record sprint velocity for a module."""
        with sqlite3.connect(self.db_path) as conn:
            conn.execute(
                """INSERT INTO velocity_samples
                   (repo_path, module, sprint, planned_points, delivered_points, timestamp)
                   VALUES (?, ?, ?, ?, ?, ?)""",
                (repo_path, module, sprint, planned_points, delivered_points, time.time()),
            )

    def get_velocity_for_module(self, repo_path: str, module: str) -> list[dict]:
        """Get velocity history for a module."""
        with sqlite3.connect(self.db_path) as conn:
            conn.row_factory = sqlite3.Row
            rows = conn.execute(
                """SELECT * FROM velocity_samples
                   WHERE repo_path = ? AND module = ?
                   ORDER BY timestamp ASC""",
                (repo_path, module),
            ).fetchall()
            return [dict(r) for r in rows]
