import os
import logging
from contextlib import contextmanager
from sqlalchemy import create_engine, text
from sqlalchemy.exc import SQLAlchemyError, OperationalError
from sqlalchemy.pool import QueuePool
from flask import current_app
from app import db

logger = logging.getLogger(__name__)

class DatabaseManager:
    """Database connection and management utilities"""
    
    def __init__(self, app=None):
        self.app = app
        self.engine = None
        if app is not None:
            self.init_app(app)
    
    def init_app(self, app):
        """Initialize database manager with Flask app"""
        self.app = app
        self.engine = create_engine(
            app.config['SQLALCHEMY_DATABASE_URI'],
            poolclass=QueuePool,
            pool_size=10,
            max_overflow=20,
            pool_pre_ping=True,
            pool_recycle=3600,
            echo=app.config.get('SQLALCHEMY_ECHO', False)
        )
    
    @contextmanager
    def get_connection(self):
        """Get database connection with automatic cleanup"""
        connection = None
        try:
            connection = self.engine.connect()
            yield connection
        except Exception as e:
            if connection:
                connection.rollback()
            logger.error(f"Database connection error: {str(e)}")
            raise
        finally:
            if connection:
                connection.close()
    
    def test_connection(self):
        """Test database connectivity"""
        try:
            with self.get_connection() as conn:
                result = conn.execute(text("SELECT 1"))
                return result.fetchone()[0] == 1
        except Exception as e:
            logger.error(f"Database connection test failed: {str(e)}")
            return False
    
    def create_database_if_not_exists(self):
        """Create database if it doesn't exist"""
        try:
            # Extract database name from URI
            db_uri = self.app.config['SQLALCHEMY_DATABASE_URI']
            db_name = db_uri.split('/')[-1].split('?')[0]
            
            # Create connection without database name
            base_uri = db_uri.rsplit('/', 1)[0]
            temp_engine = create_engine(base_uri)
            
            with temp_engine.connect() as conn:
                # Check if database exists
                result = conn.execute(text(f"SHOW DATABASES LIKE '{db_name}'"))
                if not result.fetchone():
                    conn.execute(text(f"CREATE DATABASE {db_name} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"))
                    logger.info(f"Created database: {db_name}")
                else:
                    logger.info(f"Database {db_name} already exists")
            
            temp_engine.dispose()
            return True
            
        except Exception as e:
            logger.error(f"Failed to create database: {str(e)}")
            return False
    
    def execute_schema_file(self, schema_file_path):
        """Execute SQL schema file"""
        try:
            if not os.path.exists(schema_file_path):
                logger.error(f"Schema file not found: {schema_file_path}")
                return False
            
            with open(schema_file_path, 'r') as f:
                schema_sql = f.read()
            
            # Split by semicolon and execute each statement
            statements = [stmt.strip() for stmt in schema_sql.split(';') if stmt.strip()]
            
            with self.get_connection() as conn:
                for statement in statements:
                    if statement and not statement.startswith('--'):
                        try:
                            conn.execute(text(statement))
                        except Exception as e:
                            # Log but continue with other statements
                            logger.warning(f"Statement execution warning: {str(e)}")
                
                conn.commit()
            
            logger.info(f"Schema file executed successfully: {schema_file_path}")
            return True
            
        except Exception as e:
            logger.error(f"Failed to execute schema file: {str(e)}")
            return False
    
    def initialize_database(self, schema_file_path=None):
        """Initialize database with schema and default data"""
        try:
            # Create database if it doesn't exist
            if not self.create_database_if_not_exists():
                return False
            
            # Test connection
            if not self.test_connection():
                logger.error("Database connection test failed")
                return False
            
            # Execute schema file if provided
            if schema_file_path and os.path.exists(schema_file_path):
                if not self.execute_schema_file(schema_file_path):
                    logger.warning("Schema file execution failed, trying SQLAlchemy create_all")
            
            # Create tables using SQLAlchemy
            with self.app.app_context():
                db.create_all()
                logger.info("Database tables created successfully")
            
            # Create default admin user if it doesn't exist
            self.create_default_admin()
            
            return True
            
        except Exception as e:
            logger.error(f"Database initialization failed: {str(e)}")
            return False
    
    def create_default_admin(self):
        """Create default admin user if it doesn't exist"""
        try:
            with self.app.app_context():
                from app.models import User
                admin_user = User.query.filter_by(username='admin').first()
                if not admin_user:
                    admin_user = User(
                        username='admin',
                        email='admin@fixture-daemon.local',
                        is_admin=True,
                        is_active=True
                    )
                    admin_user.set_password('admin123')  # Change in production!
                    db.session.add(admin_user)
                    db.session.commit()
                    logger.info("Default admin user created (username: admin, password: admin123)")
                else:
                    logger.info("Default admin user already exists")
            
        except Exception as e:
            logger.error(f"Failed to create default admin user: {str(e)}")
    
    def get_database_stats(self):
        """Get database statistics"""
        try:
            with self.app.app_context():
                from app.models import User, Match, MatchOutcome, FileUpload, SystemLog, UserSession
                stats = {
                    'users': User.query.count(),
                    'matches': Match.query.count(),
                    'active_matches': Match.query.filter_by(active_status=True).count(),
                    'match_outcomes': MatchOutcome.query.count(),
                    'file_uploads': FileUpload.query.count(),
                    'system_logs': SystemLog.query.count(),
                    'user_sessions': UserSession.query.filter_by(is_active=True).count()
                }
                return stats
        except Exception as e:
            logger.error(f"Failed to get database stats: {str(e)}")
            return {}
    
    def cleanup_expired_sessions(self):
        """Clean up expired user sessions"""
        try:
            with self.app.app_context():
                from datetime import datetime
                from app.models import UserSession
                expired_sessions = UserSession.query.filter(
                    UserSession.expires_at < datetime.utcnow()
                ).all()
                
                count = len(expired_sessions)
                for session in expired_sessions:
                    db.session.delete(session)
                
                db.session.commit()
                logger.info(f"Cleaned up {count} expired sessions")
                return count
                
        except Exception as e:
            logger.error(f"Failed to cleanup expired sessions: {str(e)}")
            return 0
    
    def cleanup_old_logs(self, days=30):
        """Clean up old system logs"""
        try:
            with self.app.app_context():
                from datetime import datetime, timedelta
                from app.models import SystemLog
                cutoff_date = datetime.utcnow() - timedelta(days=days)
                
                old_logs = SystemLog.query.filter(
                    SystemLog.created_at < cutoff_date
                ).all()
                
                count = len(old_logs)
                for log in old_logs:
                    db.session.delete(log)
                
                db.session.commit()
                logger.info(f"Cleaned up {count} old log entries")
                return count
                
        except Exception as e:
            logger.error(f"Failed to cleanup old logs: {str(e)}")
            return 0
    
    def backup_database(self, backup_path):
        """Create database backup using mysqldump"""
        try:
            import subprocess
            
            # Extract connection details
            db_uri = self.app.config['SQLALCHEMY_DATABASE_URI']
            # Parse mysql+pymysql://user:pass@host:port/database
            uri_parts = db_uri.replace('mysql+pymysql://', '').split('/')
            db_name = uri_parts[-1]
            auth_host = uri_parts[0]
            
            if '@' in auth_host:
                auth, host_port = auth_host.split('@')
                if ':' in auth:
                    user, password = auth.split(':', 1)
                else:
                    user, password = auth, ''
            else:
                user, password = 'root', ''
                host_port = auth_host
            
            if ':' in host_port:
                host, port = host_port.split(':')
            else:
                host, port = host_port, '3306'
            
            # Build mysqldump command
            cmd = [
                'mysqldump',
                f'--host={host}',
                f'--port={port}',
                f'--user={user}',
                '--single-transaction',
                '--routines',
                '--triggers',
                db_name
            ]
            
            if password:
                cmd.append(f'--password={password}')
            
            # Execute backup
            with open(backup_path, 'w') as backup_file:
                result = subprocess.run(cmd, stdout=backup_file, stderr=subprocess.PIPE, text=True)
            
            if result.returncode == 0:
                logger.info(f"Database backup created: {backup_path}")
                return True
            else:
                logger.error(f"Database backup failed: {result.stderr}")
                return False
                
        except Exception as e:
            logger.error(f"Database backup failed: {str(e)}")
            return False

# Global database manager instance
db_manager = DatabaseManager()

def init_database_manager(app):
    """Initialize database manager with Flask app"""
    db_manager.init_app(app)
    return db_manager

def get_db_manager():
    """Get database manager instance"""
    return db_manager