import psycopg2
from psycopg2 import pool
from contextlib import contextmanager
from typing import Generator
from app.config import settings
import json

# Connection pool for better performance
connection_pool = pool.SimpleConnectionPool(1, 20, settings.database_url)

@contextmanager
def get_db_connection():
    """Get a database connection from the pool"""
    conn = connection_pool.getconn()
    try:
        yield conn
        conn.commit()
    except Exception as e:
        conn.rollback()
        raise e
    finally:
        connection_pool.putconn(conn)

def init_db():
    """Initialize database tables"""
    with get_db_connection() as conn:
        cur = conn.cursor()
        
        # Create tables
        cur.execute("""
            CREATE TABLE IF NOT EXISTS users (
                id SERIAL PRIMARY KEY,
                email VARCHAR(255) UNIQUE NOT NULL,
                hashed_password VARCHAR(255) NOT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            );
        """)
        
        cur.execute("""
            CREATE TABLE IF NOT EXISTS profiles (
                id SERIAL PRIMARY KEY,
                user_id INTEGER NOT NULL UNIQUE,
                display_name VARCHAR(255) NOT NULL,
                age INTEGER NOT NULL,
                gender VARCHAR(50) NOT NULL,
                location VARCHAR(255) NOT NULL,
                bio TEXT,
                interests JSONB DEFAULT '[]',
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
            );
        """)
        
        cur.execute("""
            CREATE TABLE IF NOT EXISTS photos (
                id SERIAL PRIMARY KEY,
                profile_id INTEGER NOT NULL,
                file_path VARCHAR(255) NOT NULL,
                display_order INTEGER NOT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE
            );
        """)
        
        cur.execute("""
            CREATE TABLE IF NOT EXISTS likes (
                id SERIAL PRIMARY KEY,
                liker_id INTEGER NOT NULL,
                liked_id INTEGER NOT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                UNIQUE(liker_id, liked_id),
                FOREIGN KEY (liker_id) REFERENCES users(id) ON DELETE CASCADE,
                FOREIGN KEY (liked_id) REFERENCES users(id) ON DELETE CASCADE
            );
        """)
        
        cur.execute("""
            CREATE TABLE IF NOT EXISTS conversations (
                id SERIAL PRIMARY KEY,
                user_id_1 INTEGER NOT NULL,
                user_id_2 INTEGER NOT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                UNIQUE(user_id_1, user_id_2),
                FOREIGN KEY (user_id_1) REFERENCES users(id) ON DELETE CASCADE,
                FOREIGN KEY (user_id_2) REFERENCES users(id) ON DELETE CASCADE
            );
        """)
        
        cur.execute("""
            CREATE TABLE IF NOT EXISTS messages (
                id SERIAL PRIMARY KEY,
                conversation_id INTEGER NOT NULL,
                sender_id INTEGER NOT NULL,
                content TEXT NOT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (conversation_id) REFERENCES conversations(id) ON DELETE CASCADE,
                FOREIGN KEY (sender_id) REFERENCES users(id) ON DELETE CASCADE
            );
        """)
        
        # Create indexes for common queries
        cur.execute("CREATE INDEX IF NOT EXISTS idx_profiles_user_id ON profiles(user_id);")
        cur.execute("CREATE INDEX IF NOT EXISTS idx_photos_profile_id ON photos(profile_id);")
        cur.execute("CREATE INDEX IF NOT EXISTS idx_likes_liker_id ON likes(liker_id);")
        cur.execute("CREATE INDEX IF NOT EXISTS idx_likes_liked_id ON likes(liked_id);")
        cur.execute("CREATE INDEX IF NOT EXISTS idx_conversations_users ON conversations(user_id_1, user_id_2);")
        cur.execute("CREATE INDEX IF NOT EXISTS idx_messages_conversation_id ON messages(conversation_id);")
        cur.execute("CREATE INDEX IF NOT EXISTS idx_messages_created_at ON messages(created_at);")
        
        conn.commit()

def close_db():
    """Close all database connections"""
    if connection_pool:
        connection_pool.closeall()
