"""
ReceiptStore: Persistence layer for Loom receipts.

Supports PostgreSQL (via psycopg2) and SQLite (fallback).
"""

import os
import json
import logging
import sqlite3
from datetime import datetime
from typing import Dict, Any, Optional, List

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("ReceiptStore")

# Try importing psycopg2
try:
    import psycopg2
    from psycopg2.extras import Json
    HAS_POSTGRES = True
except ImportError:
    HAS_POSTGRES = False
    logger.warning("psycopg2 not found. Falling back to SQLite.")

class ReceiptStore:
    def __init__(self, connection_string: Optional[str] = None):
        self.connection_string = connection_string or os.getenv("DATABASE_URL")
        self.use_postgres = HAS_POSTGRES and self.connection_string and "postgres" in self.connection_string
        
        if not self.use_postgres:
            # SQLite fallback
            self.db_path = os.path.join(os.path.dirname(__file__), "receipts.db")
            self._init_sqlite()
        else:
            self._init_postgres()

    def _init_sqlite(self):
        """Initialize SQLite database."""
        try:
            with sqlite3.connect(self.db_path) as conn:
                conn.execute("""
                    CREATE TABLE IF NOT EXISTS receipts (
                        id TEXT PRIMARY KEY,
                        type TEXT NOT NULL,
                        timestamp TEXT NOT NULL,
                        data JSON NOT NULL,
                        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                    )
                """)
                conn.execute("CREATE INDEX IF NOT EXISTS idx_receipts_type ON receipts(type)")
                conn.execute("CREATE INDEX IF NOT EXISTS idx_receipts_timestamp ON receipts(timestamp)")
        except Exception as e:
            logger.error(f"Failed to init SQLite: {e}")
            raise

    def _init_postgres(self):
        """Initialize Postgres table."""
        try:
            with psycopg2.connect(self.connection_string) as conn:
                with conn.cursor() as cur:
                    cur.execute("""
                        CREATE TABLE IF NOT EXISTS receipts (
                            id TEXT PRIMARY KEY,
                            type TEXT NOT NULL,
                            timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
                            data JSONB NOT NULL,
                            created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
                        )
                    """)
                    cur.execute("CREATE INDEX IF NOT EXISTS idx_receipts_type ON receipts(type)")
                    cur.execute("CREATE INDEX IF NOT EXISTS idx_receipts_timestamp ON receipts(timestamp)")
        except Exception as e:
            logger.error(f"Failed to init Postgres: {e}")
            raise

    def save(self, receipt: Dict[str, Any]) -> bool:
        """Save a receipt to the store."""
        receipt_id = receipt.get("id")
        receipt_type = receipt.get("type")
        timestamp = receipt.get("timestamp") or datetime.now().isoformat()
        
        if not receipt_id or not receipt_type:
            logger.error("Receipt missing id or type")
            return False

        try:
            if self.use_postgres:
                with psycopg2.connect(self.connection_string) as conn:
                    with conn.cursor() as cur:
                        cur.execute(
                            """
                            INSERT INTO receipts (id, type, timestamp, data)
                            VALUES (%s, %s, %s, %s)
                            ON CONFLICT (id) DO UPDATE SET data = EXCLUDED.data
                            """,
                            (receipt_id, receipt_type, timestamp, Json(receipt))
                        )
            else:
                with sqlite3.connect(self.db_path) as conn:
                    conn.execute(
                        """
                        INSERT OR REPLACE INTO receipts (id, type, timestamp, data)
                        VALUES (?, ?, ?, ?)
                        """,
                        (receipt_id, receipt_type, timestamp, json.dumps(receipt))
                    )
            
            logger.info(f"Saved receipt {receipt_id}")
            return True
            
        except Exception as e:
            logger.error(f"Failed to save receipt {receipt_id}: {e}")
            return False

    def get(self, receipt_id: str) -> Optional[Dict[str, Any]]:
        """Retrieve a receipt by ID."""
        try:
            if self.use_postgres:
                with psycopg2.connect(self.connection_string) as conn:
                    with conn.cursor() as cur:
                        cur.execute("SELECT data FROM receipts WHERE id = %s", (receipt_id,))
                        result = cur.fetchone()
                        return result[0] if result else None
            else:
                with sqlite3.connect(self.db_path) as conn:
                    cursor = conn.execute("SELECT data FROM receipts WHERE id = ?", (receipt_id,))
                    result = cursor.fetchone()
                    return json.loads(result[0]) if result else None
        except Exception as e:
            logger.error(f"Failed to get receipt {receipt_id}: {e}")
            return None

    def list_recent(self, limit: int = 10) -> List[Dict[str, Any]]:
        """List recent receipts."""
        try:
            if self.use_postgres:
                with psycopg2.connect(self.connection_string) as conn:
                    with conn.cursor() as cur:
                        cur.execute("SELECT data FROM receipts ORDER BY timestamp DESC LIMIT %s", (limit,))
                        return [row[0] for row in cur.fetchall()]
            else:
                with sqlite3.connect(self.db_path) as conn:
                    cursor = conn.execute("SELECT data FROM receipts ORDER BY timestamp DESC LIMIT ?", (limit,))
                    return [json.loads(row[0]) for row in cursor.fetchall()]
        except Exception as e:
            logger.error(f"Failed to list receipts: {e}")
            return []
