"""
OpenSoul Database Layer

Manages SQLite database with INSERT-only architecture and hash chain integrity.
"""

import sqlite3
import json
import hashlib
from datetime import datetime
from pathlib import Path
from typing import Optional, List, Dict, Any

# Data directory
DATA_DIR = Path.home() / ".opensoul" / "data"
DATA_DIR.mkdir(parents=True, exist_ok=True)

DB_PATH = DATA_DIR / "soul.db"


def get_db() -> sqlite3.Connection:
    """Get database connection with WAL mode."""
    conn = sqlite3.connect(DB_PATH)
    conn.execute("PRAGMA journal_mode=WAL")
    conn.row_factory = sqlite3.Row
    return conn


def init_db():
    """Initialize database tables."""
    conn = get_db()
    
    # Core tables with hash chain
    conn.execute("""
        CREATE TABLE IF NOT EXISTS souls (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
            context TEXT,
            ai_suggestion TEXT,
            human_decision TEXT,
            divergence_reason TEXT,
            tags TEXT,  -- JSON array
            notes TEXT,
            emotional_state TEXT,
            energy TEXT,
            body_state TEXT,
            decision_layer TEXT,
            time_horizon TEXT,
            social_context TEXT,
            emotion_valence REAL,
            emotion_intensity REAL,
            emotion_duration TEXT,
            emotion_trigger_type TEXT,
            emotion_trigger_ref TEXT,
            emotion_label TEXT,
            emotion_secondary TEXT,
            prev_hash TEXT,
            current_hash TEXT
        )
    """)
    
    conn.execute("""
        CREATE TABLE IF NOT EXISTS states (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
            emotional_state TEXT,
            energy TEXT,
            body_state TEXT,
            social_context TEXT,
            environment TEXT,
            notes TEXT,
            tags TEXT,
            emotion_valence REAL,
            emotion_intensity REAL,
            emotion_duration TEXT,
            emotion_trigger_type TEXT,
            emotion_trigger_ref TEXT,
            emotion_label TEXT,
            emotion_secondary TEXT,
            prev_hash TEXT,
            current_hash TEXT
        )
    """)
    
    conn.execute("""
        CREATE TABLE IF NOT EXISTS contradictions (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
            description TEXT,
            soul_id_a INTEGER,
            soul_id_b INTEGER,
            analysis TEXT,
            resolution TEXT,
            tags TEXT,
            prev_hash TEXT,
            current_hash TEXT
        )
    """)
    
    conn.execute("""
        CREATE TABLE IF NOT EXISTS silences (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
            topic TEXT,
            silence_form TEXT,
            observation TEXT,
            tags TEXT,
            prev_hash TEXT,
            current_hash TEXT
        )
    """)
    
    conn.execute("""
        CREATE TABLE IF NOT EXISTS artifacts (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
            artifact_type TEXT,
            description TEXT,
            path TEXT,
            linked_soul_id INTEGER,
            tags TEXT,
            prev_hash TEXT,
            current_hash TEXT
        )
    """)
    
    conn.execute("""
        CREATE TABLE IF NOT EXISTS philosophy (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
            principle TEXT,
            source TEXT,
            examples TEXT,  -- JSON array
            prev_hash TEXT,
            current_hash TEXT
        )
    """)
    
    conn.execute("""
        CREATE TABLE IF NOT EXISTS profile_history (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
            key TEXT,
            value TEXT,
            category TEXT,
            prev_hash TEXT,
            current_hash TEXT
        )
    """)
    
    # Indexes
    conn.execute("CREATE INDEX IF NOT EXISTS idx_souls_timestamp ON souls(timestamp)")
    conn.execute("CREATE INDEX IF NOT EXISTS idx_souls_tags ON souls(tags)")
    conn.execute("CREATE INDEX IF NOT EXISTS idx_states_timestamp ON states(timestamp)")
    conn.execute("CREATE INDEX IF NOT EXISTS idx_contradictions_soul_a ON contradictions(soul_id_a)")
    conn.execute("CREATE INDEX IF NOT EXISTS idx_contradictions_soul_b ON contradictions(soul_id_b)")
    
    conn.commit()
    conn.close()


def compute_hash(data: Dict[str, Any], prev_hash: str = "0") -> str:
    """Compute SHA256 hash for record."""
    content = json.dumps(data, sort_keys=True, default=str)
    return hashlib.sha256((prev_hash + content).encode()).hexdigest()


def get_last_hash(table: str) -> str:
    """Get the last hash from a table."""
    conn = get_db()
    cursor = conn.execute(f"SELECT current_hash FROM {table} ORDER BY id DESC LIMIT 1")
    row = cursor.fetchone()
    conn.close()
    return row["current_hash"] if row else "0"


# ── Recording Functions ─────────────────────────────────────────────────

def record_soul(**kwargs) -> Dict:
    """Record a soul event."""
    conn = get_db()
    
    # Get previous hash
    prev_hash = get_last_hash("souls")
    
    # Prepare data
    data = {k: v for k, v in kwargs.items() if v is not None}
    if "tags" in data and isinstance(data["tags"], list):
        data["tags"] = json.dumps(data["tags"])
    
    # Compute hash
    current_hash = compute_hash(data, prev_hash)
    
    # Insert
    columns = list(data.keys()) + ["prev_hash", "current_hash"]
    placeholders = ["?"] * len(columns)
    values = list(data.values()) + [prev_hash, current_hash]
    
    cursor = conn.execute(
        f"INSERT INTO souls ({', '.join(columns)}) VALUES ({', '.join(placeholders)})",
        values
    )
    
    soul_id = cursor.lastrowid
    conn.commit()
    conn.close()
    
    return {
        "id": soul_id,
        "timestamp": datetime.now().isoformat(),
        "current_hash": current_hash
    }


def record_state(**kwargs) -> Dict:
    """Record a state snapshot."""
    conn = get_db()
    
    prev_hash = get_last_hash("states")
    data = {k: v for k, v in kwargs.items() if v is not None}
    if "tags" in data and isinstance(data["tags"], list):
        data["tags"] = json.dumps(data["tags"])
    
    current_hash = compute_hash(data, prev_hash)
    
    columns = list(data.keys()) + ["prev_hash", "current_hash"]
    placeholders = ["?"] * len(columns)
    values = list(data.values()) + [prev_hash, current_hash]
    
    cursor = conn.execute(
        f"INSERT INTO states ({', '.join(columns)}) VALUES ({', '.join(placeholders)})",
        values
    )
    
    state_id = cursor.lastrowid
    conn.commit()
    conn.close()
    
    return {
        "id": state_id,
        "timestamp": datetime.now().isoformat(),
        "current_hash": current_hash
    }


def record_contradiction(**kwargs) -> Dict:
    """Record a contradiction."""
    conn = get_db()
    
    prev_hash = get_last_hash("contradictions")
    data = {k: v for k, v in kwargs.items() if v is not None}
    if "tags" in data and isinstance(data["tags"], list):
        data["tags"] = json.dumps(data["tags"])
    
    current_hash = compute_hash(data, prev_hash)
    
    columns = list(data.keys()) + ["prev_hash", "current_hash"]
    placeholders = ["?"] * len(columns)
    values = list(data.values()) + [prev_hash, current_hash]
    
    cursor = conn.execute(
        f"INSERT INTO contradictions ({', '.join(columns)}) VALUES ({', '.join(placeholders)})",
        values
    )
    
    conn_id = cursor.lastrowid
    conn.commit()
    conn.close()
    
    return {
        "id": conn_id,
        "timestamp": datetime.now().isoformat(),
        "current_hash": current_hash
    }


def record_silence(**kwargs) -> Dict:
    """Record a silence."""
    conn = get_db()
    
    prev_hash = get_last_hash("silences")
    data = {k: v for k, v in kwargs.items() if v is not None}
    if "tags" in data and isinstance(data["tags"], list):
        data["tags"] = json.dumps(data["tags"])
    
    current_hash = compute_hash(data, prev_hash)
    
    columns = list(data.keys()) + ["prev_hash", "current_hash"]
    placeholders = ["?"] * len(columns)
    values = list(data.values()) + [prev_hash, current_hash]
    
    cursor = conn.execute(
        f"INSERT INTO silences ({', '.join(columns)}) VALUES ({', '.join(placeholders)})",
        values
    )
    
    silence_id = cursor.lastrowid
    conn.commit()
    conn.close()
    
    return {
        "id": silence_id,
        "timestamp": datetime.now().isoformat(),
        "current_hash": current_hash
    }


def record_artifact(**kwargs) -> Dict:
    """Record an artifact."""
    conn = get_db()
    
    prev_hash = get_last_hash("artifacts")
    data = {k: v for k, v in kwargs.items() if v is not None}
    if "tags" in data and isinstance(data["tags"], list):
        data["tags"] = json.dumps(data["tags"])
    
    current_hash = compute_hash(data, prev_hash)
    
    columns = list(data.keys()) + ["prev_hash", "current_hash"]
    placeholders = ["?"] * len(columns)
    values = list(data.values()) + [prev_hash, current_hash]
    
    cursor = conn.execute(
        f"INSERT INTO artifacts ({', '.join(columns)}) VALUES ({', '.join(placeholders)})",
        values
    )
    
    artifact_id = cursor.lastrowid
    conn.commit()
    conn.close()
    
    return {
        "id": artifact_id,
        "timestamp": datetime.now().isoformat(),
        "current_hash": current_hash
    }


def ingest_media(**kwargs) -> Dict:
    """Ingest media file."""
    # Simplified version - just record as artifact
    return record_artifact(**kwargs)


# ── Query Functions ─────────────────────────────────────────────────────

def list_souls(limit: int = 10, tag: Optional[str] = None) -> List[Dict]:
    """List recent soul events."""
    conn = get_db()
    
    if tag:
        cursor = conn.execute(
            "SELECT * FROM souls WHERE tags LIKE ? ORDER BY id DESC LIMIT ?",
            (f'%"{tag}"%', limit)
        )
    else:
        cursor = conn.execute(
            "SELECT * FROM souls ORDER BY id DESC LIMIT ?",
            (limit,)
        )
    
    rows = cursor.fetchall()
    conn.close()
    
    return [dict(row) for row in rows]


def search_souls(keyword: str) -> List[Dict]:
    """Search souls by keyword."""
    conn = get_db()
    
    cursor = conn.execute(
        """SELECT * FROM souls 
           WHERE context LIKE ? OR human_decision LIKE ? OR divergence_reason LIKE ?
           ORDER BY id DESC""",
        (f"%{keyword}%", f"%{keyword}%", f"%{keyword}%")
    )
    
    rows = cursor.fetchall()
    conn.close()
    
    return [dict(row) for row in rows]


def query_souls(query: str, limit: int = 10) -> List[Dict]:
    """Semantic search souls (simplified - falls back to keyword)."""
    # TODO: Implement vector search with bge-m3
    return search_souls(query)[:limit]


def get_soul_by_id(soul_id: int) -> Optional[Dict]:
    """Get a specific soul by ID."""
    conn = get_db()
    
    cursor = conn.execute("SELECT * FROM souls WHERE id = ?", (soul_id,))
    row = cursor.fetchone()
    conn.close()
    
    return dict(row) if row else None


# ── Profile Functions ───────────────────────────────────────────────────

def set_profile(**kwargs) -> Dict:
    """Set a profile attribute."""
    conn = get_db()
    
    prev_hash = get_last_hash("profile_history")
    data = {k: v for k, v in kwargs.items() if v is not None}
    
    current_hash = compute_hash(data, prev_hash)
    
    columns = list(data.keys()) + ["prev_hash", "current_hash"]
    placeholders = ["?"] * len(columns)
    values = list(data.values()) + [prev_hash, current_hash]
    
    cursor = conn.execute(
        f"INSERT INTO profile_history ({', '.join(columns)}) VALUES ({', '.join(placeholders)})",
        values
    )
    
    profile_id = cursor.lastrowid
    conn.commit()
    conn.close()
    
    return {
        "id": profile_id,
        "timestamp": datetime.now().isoformat(),
        "current_hash": current_hash
    }


def get_profile(category: Optional[str] = None) -> List[Dict]:
    """Get profile history."""
    conn = get_db()
    
    if category:
        cursor = conn.execute(
            "SELECT * FROM profile_history WHERE category = ? ORDER BY id DESC",
            (category,)
        )
    else:
        cursor = conn.execute("SELECT * FROM profile_history ORDER BY id DESC")
    
    rows = cursor.fetchall()
    conn.close()
    
    return [dict(row) for row in rows]


def get_portrait() -> Dict:
    """Get full personality portrait."""
    conn = get_db()
    
    # Get latest values for each key
    cursor = conn.execute("""
        SELECT key, value, category FROM profile_history
        WHERE id IN (
            SELECT MAX(id) FROM profile_history GROUP BY key
        )
    """)
    
    profile = {}
    for row in cursor.fetchall():
        profile[row["key"]] = {
            "value": row["value"],
            "category": row["category"]
        }
    
    # Get stats
    cursor = conn.execute("SELECT COUNT(*) as count FROM souls")
    soul_count = cursor.fetchone()["count"]
    
    cursor = conn.execute("SELECT COUNT(*) as count FROM states")
    state_count = cursor.fetchone()["count"]
    
    conn.close()
    
    return {
        "profile": profile,
        "stats": {
            "soul_events": soul_count,
            "state_snapshots": state_count
        }
    }


# ── Philosophy Functions ─────────────────────────────────────────────────

def add_philosophy(**kwargs) -> Dict:
    """Add a philosophy entry."""
    conn = get_db()
    
    prev_hash = get_last_hash("philosophy")
    data = {k: v for k, v in kwargs.items() if v is not None}
    if "examples" in data and isinstance(data["examples"], list):
        data["examples"] = json.dumps(data["examples"])
    
    current_hash = compute_hash(data, prev_hash)
    
    columns = list(data.keys()) + ["prev_hash", "current_hash"]
    placeholders = ["?"] * len(columns)
    values = list(data.values()) + [prev_hash, current_hash]
    
    cursor = conn.execute(
        f"INSERT INTO philosophy ({', '.join(columns)}) VALUES ({', '.join(placeholders)})",
        values
    )
    
    phil_id = cursor.lastrowid
    conn.commit()
    conn.close()
    
    return {
        "id": phil_id,
        "timestamp": datetime.now().isoformat(),
        "current_hash": current_hash
    }


def list_philosophy() -> List[Dict]:
    """List all philosophies."""
    conn = get_db()
    
    cursor = conn.execute("SELECT * FROM philosophy ORDER BY id DESC")
    rows = cursor.fetchall()
    conn.close()
    
    return [dict(row) for row in rows]


# ── Analysis Functions ───────────────────────────────────────────────────

def analyze_tags() -> Dict:
    """Analyze tag distribution."""
    conn = get_db()
    
    cursor = conn.execute("SELECT tags FROM souls WHERE tags IS NOT NULL")
    tag_counts = {}
    
    for row in cursor.fetchall():
        try:
            tags = json.loads(row["tags"])
            for tag in tags:
                tag_counts[tag] = tag_counts.get(tag, 0) + 1
        except:
            pass
    
    conn.close()
    
    return {
        "tag_distribution": tag_counts,
        "total_tagged_events": sum(tag_counts.values())
    }


def analyze_coverage() -> Dict:
    """Analyze 7-dimension coverage."""
    conn = get_db()
    
    # Simplified coverage analysis
    dimensions = ["identity", "values", "emotion", "cognition", "relationship", "creation", "mission"]
    coverage = {}
    
    for dim in dimensions:
        cursor = conn.execute(
            "SELECT COUNT(*) as count FROM profile_history WHERE category = ?",
            (dim,)
        )
        count = cursor.fetchone()["count"]
        coverage[dim] = {
            "recorded": count > 0,
            "entries": count
        }
    
    conn.close()
    
    return {
        "dimensions": coverage,
        "coverage_rate": sum(1 for d in coverage.values() if d["recorded"]) / len(dimensions)
    }


def summarize_souls() -> Dict:
    """Summarize all soul events."""
    conn = get_db()
    
    cursor = conn.execute("SELECT COUNT(*) as count FROM souls")
    total = cursor.fetchone()["count"]
    
    cursor = conn.execute("""
        SELECT decision_layer, COUNT(*) as count 
        FROM souls 
        WHERE decision_layer IS NOT NULL
        GROUP BY decision_layer
    """)
    layer_dist = {row["decision_layer"]: row["count"] for row in cursor.fetchall()}
    
    cursor = conn.execute("""
        SELECT time_horizon, COUNT(*) as count 
        FROM souls 
        WHERE time_horizon IS NOT NULL
        GROUP BY time_horizon
    """)
    horizon_dist = {row["time_horizon"]: row["count"] for row in cursor.fetchall()}
    
    conn.close()
    
    return {
        "total_events": total,
        "decision_layer_distribution": layer_dist,
        "time_horizon_distribution": horizon_dist
    }


# ── System Functions ─────────────────────────────────────────────────────

def health_check() -> Dict:
    """Check system health."""
    try:
        conn = get_db()
        
        tables = ["souls", "states", "contradictions", "silences", "artifacts", "philosophy", "profile_history"]
        stats = {}
        
        for table in tables:
            cursor = conn.execute(f"SELECT COUNT(*) as count FROM {table}")
            stats[table] = cursor.fetchone()["count"]
        
        conn.close()
        
        return {
            "status": "healthy",
            "database": str(DB_PATH),
            "record_counts": stats
        }
    except Exception as e:
        return {
            "status": "unhealthy",
            "error": str(e)
        }


def get_stats() -> Dict:
    """Get database statistics."""
    return health_check()
