"""
Database initialization and management
"""

import sqlite3
import aiosqlite
from pathlib import Path
from typing import Optional
from datetime import datetime
import json
import os

from config.settings import settings

async def init_db():
    """Initialize the database with required tables"""
    db_path = Path(settings.database_url.replace("sqlite:///", ""))
    db_path.parent.mkdir(parents=True, exist_ok=True)
    
    async with aiosqlite.connect(db_path) as db:
        await db.execute("""
            CREATE TABLE IF NOT EXISTS users (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                username TEXT UNIQUE NOT NULL,
                email TEXT UNIQUE NOT NULL,
                role TEXT DEFAULT 'user',
                ldap_dn TEXT,
                is_active BOOLEAN DEFAULT 1,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                last_login TIMESTAMP
            )
        """)
        
        await db.execute("""
            CREATE TABLE IF NOT EXISTS kpi_files (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                filename TEXT NOT NULL,
                file_path TEXT NOT NULL,
                uploaded_by INTEGER,
                upload_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                file_size INTEGER,
                file_hash TEXT,
                processed BOOLEAN DEFAULT 0,
                nextcloud_file_id TEXT,
                FOREIGN KEY (uploaded_by) REFERENCES users (id)
            )
        """)
        
        await db.execute("""
            CREATE TABLE IF NOT EXISTS kpi_analysis_results (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                file_id INTEGER,
                analysis_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                total_score REAL,
                perspective_scores TEXT, -- JSON: {financial: score, customer: score, ...}
                achievement_status TEXT, -- JSON: achieve/not achieve for each KPI
                recommendations TEXT, -- JSON array of recommendations
                report_path TEXT,
                FOREIGN KEY (file_id) REFERENCES kpi_files (id)
            )
        """)
        
        await db.execute("""
            CREATE TABLE IF NOT EXISTS kpi_data_cache (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                file_id INTEGER,
                sheet_name TEXT,
                data_cache TEXT, -- JSON serialized pandas DataFrame
                cache_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (file_id) REFERENCES kpi_files (id)
            )
        """)
        
        await db.execute("""
            CREATE TABLE IF NOT EXISTS user_sessions (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id INTEGER,
                session_token TEXT UNIQUE NOT NULL,
                expires_at TIMESTAMP,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (user_id) REFERENCES users (id)
            )
        """)
        
        await db.execute("""
            CREATE TABLE IF NOT EXISTS application_logs (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id INTEGER,
                action TEXT NOT NULL,
                details TEXT,
                timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                ip_address TEXT,
                FOREIGN KEY (user_id) REFERENCES users (id)
            )
        """)
        
        await db.commit()
        print("✅ Database initialized successfully")

async def log_action(user_id: Optional[int], action: str, details: str = "", ip_address: str = ""):
    """Log user actions for audit trail"""
    async with aiosqlite.connect(Path(settings.database_url.replace("sqlite:///", ""))) as db:
        await db.execute("""
            INSERT INTO application_logs (user_id, action, details, ip_address)
            VALUES (?, ?, ?, ?)
        """, (user_id, action, details, ip_address))
        await db.commit()

async def create_user(username: str, email: str, role: str = "user", ldap_dn: str = None) -> int:
    """Create a new user"""
    async with aiosqlite.connect(Path(settings.database_url.replace("sqlite:///", ""))) as db:
        cursor = await db.execute("""
            INSERT INTO users (username, email, role, ldap_dn)
            VALUES (?, ?, ?, ?)
        """, (username, email, role, ldap_dn))
        await db.commit()
        return cursor.lastrowid

async def get_user_by_username(username: str):
    """Get user by username"""
    async with aiosqlite.connect(Path(settings.database_url.replace("sqlite:///", ""))) as db:
        db.row_factory = aiosqlite.Row
        cursor = await db.execute("""
            SELECT * FROM users WHERE username = ? AND is_active = 1
        """, (username,))
        return await cursor.fetchone()

async def create_session(user_id: int, expires_hours: int = 24) -> str:
    """Create a new user session"""
    import secrets
    
    session_token = secrets.token_urlsafe(32)
    expires_at = datetime.now().timestamp() + (expires_hours * 3600)
    
    async with aiosqlite.connect(Path(settings.database_url.replace("sqlite:///", ""))) as db:
        await db.execute("""
            INSERT INTO user_sessions (user_id, session_token, expires_at)
            VALUES (?, ?, ?)
        """, (user_id, session_token, expires_at))
        await db.commit()
        
    return session_token

async def validate_session(session_token: str):
    """Validate user session"""
    async with aiosqlite.connect(Path(settings.database_url.replace("sqlite:///", ""))) as db:
        db.row_factory = aiosqlite.Row
        cursor = await db.execute("""
            SELECT s.*, u.username, u.email, u.role
            FROM user_sessions s
            JOIN users u ON s.user_id = u.id
            WHERE s.session_token = ? AND s.expires_at > ? AND u.is_active = 1
        """, (session_token, datetime.now().timestamp()))
        return await cursor.fetchone()

async def save_uploaded_file(filename: str, file_path: str, uploaded_by: int, file_size: int) -> int:
    """Save uploaded file record to database"""
    async with aiosqlite.connect(Path(settings.database_url.replace("sqlite:///", ""))) as db:
        cursor = await db.execute("""
            INSERT INTO kpi_files (filename, file_path, uploaded_by, file_size, processed)
            VALUES (?, ?, ?, ?, 0)
        """, (filename, file_path, uploaded_by, file_size))
        await db.commit()
        return cursor.lastrowid

async def get_uploaded_files():
    """Get list of uploaded files"""
    async with aiosqlite.connect(Path(settings.database_url.replace("sqlite:///", ""))) as db:
        db.row_factory = aiosqlite.Row
        cursor = await db.execute("""
            SELECT 
                id,
                filename,
                upload_date,
                file_size,
                processed
            FROM kpi_files
            ORDER BY upload_date DESC
        """)
        rows = await cursor.fetchall()
        
        files = []
        for row in rows:
            # Format file size
            size_mb = row['file_size'] / (1024 * 1024) if row['file_size'] else 0
            
            files.append({
                "id": row['id'],
                "filename": row['filename'],
                "upload_date": row['upload_date'],
                "size": f"{size_mb:.2f} MB",
                "processed": bool(row['processed'])
            })
        
        return files

async def mark_file_processed(file_id: int):
    """Mark file as processed"""
    async with aiosqlite.connect(Path(settings.database_url.replace("sqlite:///", ""))) as db:
        await db.execute("""
            UPDATE kpi_files
            SET processed = 1
            WHERE id = ?
        """, (file_id,))
        await db.commit()

async def save_analysis_results(file_id: int, total_score: float, perspective_scores: dict, 
                                achievements: dict, recommendations: list, report_path: str = None):
    """Save analysis results to database"""
    async with aiosqlite.connect(Path(settings.database_url.replace("sqlite:///", ""))) as db:
        # Convert dict/list to JSON strings
        perspective_scores_json = json.dumps({k.value if hasattr(k, 'value') else k: v for k, v in perspective_scores.items()})
        achievements_json = json.dumps(achievements)
        recommendations_json = json.dumps(recommendations)
        
        await db.execute("""
            INSERT INTO kpi_analysis_results 
            (file_id, total_score, perspective_scores, achievement_status, recommendations, report_path)
            VALUES (?, ?, ?, ?, ?, ?)
        """, (file_id, total_score, perspective_scores_json, achievements_json, recommendations_json, report_path))
        await db.commit()

async def get_analysis_results(file_id: int):
    """Get analysis results for a file"""
    async with aiosqlite.connect(Path(settings.database_url.replace("sqlite:///", ""))) as db:
        db.row_factory = aiosqlite.Row
        cursor = await db.execute("""
            SELECT * FROM kpi_analysis_results
            WHERE file_id = ?
            ORDER BY analysis_date DESC
            LIMIT 1
        """, (file_id,))
        row = await cursor.fetchone()
        
        if row:
            return {
                "id": row['id'],
                "file_id": row['file_id'],
                "analysis_date": row['analysis_date'],
                "total_score": row['total_score'],
                "perspective_scores": json.loads(row['perspective_scores']) if row['perspective_scores'] else {},
                "achievements": json.loads(row['achievement_status']) if row['achievement_status'] else {},
                "recommendations": json.loads(row['recommendations']) if row['recommendations'] else [],
                "report_path": row['report_path']
            }
        
        return None

async def delete_uploaded_file(file_id: int) -> bool:
    """Delete uploaded file and its related data"""
    try:
        async with aiosqlite.connect(Path(settings.database_url.replace("sqlite:///", ""))) as db:
            db.row_factory = aiosqlite.Row
            
            # Get file path before deleting
            cursor = await db.execute("SELECT file_path FROM kpi_files WHERE id = ?", (file_id,))
            row = await cursor.fetchone()
            
            if not row:
                return False
            
            file_path = row['file_path']
            
            # Delete analysis results
            await db.execute("DELETE FROM kpi_analysis_results WHERE file_id = ?", (file_id,))
            
            # Delete data cache
            await db.execute("DELETE FROM kpi_data_cache WHERE file_id = ?", (file_id,))
            
            # Delete file record
            await db.execute("DELETE FROM kpi_files WHERE id = ?", (file_id,))
            
            await db.commit()
            
            # Delete physical file if it exists
            if file_path and os.path.exists(file_path):
                try:
                    os.remove(file_path)
                except Exception as e:
                    print(f"Warning: Could not delete physical file {file_path}: {e}")
            
            return True
            
    except Exception as e:
        print(f"Error deleting file: {e}")
        return False