"""Standardized SQLite storage for forced alignment results with content hashing"""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/forced_alignment_storage.ipynb.

# %% auto #0
__all__ = ['ForcedAlignmentRow', 'ForcedAlignmentStorage']

# %% ../nbs/forced_alignment_storage.ipynb #cell-imports
import json
import sqlite3
import time
from dataclasses import dataclass
from typing import Any, Dict, List, Optional

from cjm_plugin_system.utils.hashing import hash_bytes, hash_file

# %% ../nbs/forced_alignment_storage.ipynb #cell-row
@dataclass
class ForcedAlignmentRow:
    """A single row from the forced_alignments table."""
    job_id: str          # Unique job identifier
    audio_path: str      # Path to the source audio file
    audio_hash: str      # Hash of source audio in "algo:hexdigest" format
    text: str            # Input transcript text that was aligned
    text_hash: str       # Hash of input text in "algo:hexdigest" format
    items: Optional[List[Dict[str, Any]]] = None  # Serialized ForcedAlignItems
    metadata: Optional[Dict[str, Any]] = None      # Plugin metadata
    created_at: Optional[float] = None             # Unix timestamp

# %% ../nbs/forced_alignment_storage.ipynb #cell-storage
class ForcedAlignmentStorage:
    """Standardized SQLite storage for forced alignment results."""

    SCHEMA = """
        CREATE TABLE IF NOT EXISTS forced_alignments (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            job_id TEXT UNIQUE NOT NULL,
            audio_path TEXT NOT NULL,
            audio_hash TEXT NOT NULL,
            text TEXT NOT NULL,
            text_hash TEXT NOT NULL,
            items JSON,
            metadata JSON,
            created_at REAL NOT NULL
        )
    """

    INDEX = "CREATE INDEX IF NOT EXISTS idx_forced_alignments_job_id ON forced_alignments(job_id);"

    def __init__(
        self,
        db_path: str  # Absolute path to the SQLite database file
    ):
        """Initialize storage and create table if needed."""
        self.db_path = db_path
        with sqlite3.connect(self.db_path) as con:
            con.execute(self.SCHEMA)
            con.execute(self.INDEX)

    def save(
        self,
        job_id: str,        # Unique job identifier
        audio_path: str,    # Path to the source audio file
        audio_hash: str,    # Hash of source audio in "algo:hexdigest" format
        text: str,          # Input transcript text
        text_hash: str,     # Hash of input text in "algo:hexdigest" format
        items: Optional[List[Dict[str, Any]]] = None,  # Serialized ForcedAlignItems
        metadata: Optional[Dict[str, Any]] = None       # Plugin metadata
    ) -> None:
        """Save a forced alignment result to the database."""
        with sqlite3.connect(self.db_path) as con:
            con.execute(
                """INSERT INTO forced_alignments
                   (job_id, audio_path, audio_hash, text, text_hash, items, metadata, created_at)
                   VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
                (
                    job_id,
                    audio_path,
                    audio_hash,
                    text,
                    text_hash,
                    json.dumps(items) if items else None,
                    json.dumps(metadata) if metadata else None,
                    time.time()
                )
            )

    def get_by_job_id(
        self,
        job_id: str  # Job identifier to look up
    ) -> Optional[ForcedAlignmentRow]:  # Row or None if not found
        """Retrieve a forced alignment result by job ID."""
        with sqlite3.connect(self.db_path) as con:
            cur = con.execute(
                """SELECT job_id, audio_path, audio_hash, text, text_hash,
                          items, metadata, created_at
                   FROM forced_alignments WHERE job_id = ?""",
                (job_id,)
            )
            row = cur.fetchone()
            if not row:
                return None
            return ForcedAlignmentRow(
                job_id=row[0],
                audio_path=row[1],
                audio_hash=row[2],
                text=row[3],
                text_hash=row[4],
                items=json.loads(row[5]) if row[5] else None,
                metadata=json.loads(row[6]) if row[6] else None,
                created_at=row[7]
            )

    def list_jobs(
        self,
        limit: int = 100  # Maximum number of rows to return
    ) -> List[ForcedAlignmentRow]:  # List of forced alignment rows
        """List forced alignment jobs ordered by creation time (newest first)."""
        results = []
        with sqlite3.connect(self.db_path) as con:
            cur = con.execute(
                """SELECT job_id, audio_path, audio_hash, text, text_hash,
                          items, metadata, created_at
                   FROM forced_alignments ORDER BY created_at DESC LIMIT ?""",
                (limit,)
            )
            for row in cur:
                results.append(ForcedAlignmentRow(
                    job_id=row[0],
                    audio_path=row[1],
                    audio_hash=row[2],
                    text=row[3],
                    text_hash=row[4],
                    items=json.loads(row[5]) if row[5] else None,
                    metadata=json.loads(row[6]) if row[6] else None,
                    created_at=row[7]
                ))
        return results

    def verify_audio(
        self,
        job_id: str  # Job identifier to verify
    ) -> Optional[bool]:  # True if audio matches, False if tampered, None if job not found
        """Verify the source audio file still matches its stored hash."""
        row = self.get_by_job_id(job_id)
        if not row:
            return None
        current_hash = hash_file(row.audio_path)
        return current_hash == row.audio_hash

    def verify_text(
        self,
        job_id: str  # Job identifier to verify
    ) -> Optional[bool]:  # True if text matches, False if tampered, None if job not found
        """Verify the input text still matches its stored hash."""
        row = self.get_by_job_id(job_id)
        if not row:
            return None
        current_hash = hash_bytes(row.text.encode())
        return current_hash == row.text_hash
