<?php

/**
 * Class SqlModel
 * 
 * Model for executing raw SQL queries
 */
class SqlModel
{
    /**
     * Execute a SQL query and return the result
     * @param string $database_name
     * @param string $sql_query
     * @param int $user_id
     * @return array
     */
    public static function executeQuery($database_name, $sql_query, $user_id = null)
    {
        $start_time = microtime(true);
        
        // Save query to history if user_id is provided
        if ($user_id) {
            self::saveQueryToHistory($user_id, $database_name, $sql_query);
        }
        
        try {
            $database = DatabaseFactory::getFactory()->getConnection();
            
            // Determine query type
            $query_type = self::getQueryType($sql_query);
            
            // Execute the query
            $query = $database->prepare($sql_query);
            $query->execute();
            
            $execution_time = number_format((microtime(true) - $start_time) * 1000, 2);
            
            // Handle different query types
            if ($query_type === 'SELECT' || $query_type === 'SHOW' || $query_type === 'DESCRIBE' || $query_type === 'EXPLAIN') {
                // Return result set
                $result = $query->fetchAll(PDO::FETCH_ASSOC);
                $message = 'Query executed successfully. ' . count($result) . ' rows returned.';
                
                return array(
                    'success' => true,
                    'message' => $message,
                    'result' => $result,
                    'query_type' => $query_type,
                    'execution_time' => $execution_time,
                    'affected_rows' => 0
                );
            } else {
                // Return affected rows count
                $affected_rows = $query->rowCount();
                $message = 'Query executed successfully. ' . $affected_rows . ' row(s) affected.';
                
                return array(
                    'success' => true,
                    'message' => $message,
                    'query_type' => $query_type,
                    'execution_time' => $execution_time,
                    'affected_rows' => $affected_rows,
                    'result' => array()
                );
            }
        } catch (PDOException $e) {
            return array(
                'success' => false,
                'message' => 'Query execution failed',
                'error' => $e->getMessage(),
                'query_type' => 'ERROR',
                'execution_time' => 0,
                'result' => array()
            );
        }
    }

    /**
     * Save query to history
     * @param int $user_id
     * @param string $database_name
     * @param string $sql_query
     * @return bool
     */
    private static function saveQueryToHistory($user_id, $database_name, $sql_query)
    {
        // Create history table if it doesn't exist
        self::createHistoryTableIfNotExists();
        
        $database = DatabaseFactory::getFactory()->getConnection();
        
        try {
            $sql = "INSERT INTO sql_query_history (user_id, database_name, query_text, query_timestamp) 
                    VALUES (:user_id, :database_name, :query_text, NOW())";
            $query = $database->prepare($sql);
            $query->execute(array(
                ':user_id' => $user_id,
                ':database_name' => $database_name,
                ':query_text' => $sql_query
            ));
            
            // Keep only last 50 queries per user
            $sql = "DELETE FROM sql_query_history 
                    WHERE user_id = :user_id 
                    AND id NOT IN (
                        SELECT id FROM (
                            SELECT id FROM sql_query_history 
                            WHERE user_id = :user_id 
                            ORDER BY query_timestamp DESC 
                            LIMIT 50
                        ) AS temp
                    )";
            $query = $database->prepare($sql);
            $query->execute(array(':user_id' => $user_id));
            
            return true;
        } catch (PDOException $e) {
            return false;
        }
    }

    /**
     * Create SQL query history table if it doesn't exist
     */
    private static function createHistoryTableIfNotExists()
    {
        $database = DatabaseFactory::getFactory()->getConnection();
        
        try {
            $sql = "CREATE TABLE IF NOT EXISTS sql_query_history (
                        id INT AUTO_INCREMENT PRIMARY KEY,
                        user_id INT NOT NULL,
                        database_name VARCHAR(64) NOT NULL,
                        query_text TEXT NOT NULL,
                        query_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                        INDEX idx_user_timestamp (user_id, query_timestamp)
                    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
            $database->exec($sql);
        } catch (PDOException $e) {
            // Table creation failed
        }
    }

    /**
     * Get query history for a user
     * @param int $user_id
     * @param int $limit
     * @return array
     */
    public static function getQueryHistory($user_id, $limit = 50)
    {
        $database = DatabaseFactory::getFactory()->getConnection();
        
        try {
            $sql = "SELECT database_name, query_text, query_timestamp 
                    FROM sql_query_history 
                    WHERE user_id = :user_id 
                    ORDER BY query_timestamp DESC 
                    LIMIT :limit";
            $query = $database->prepare($sql);
            $query->bindValue(':user_id', $user_id, PDO::PARAM_INT);
            $query->bindValue(':limit', $limit, PDO::PARAM_INT);
            $query->execute();
            
            return $query->fetchAll(PDO::FETCH_ASSOC);
        } catch (PDOException $e) {
            return array();
        }
    }

    /**
     * Clear query history for a user
     * @param int $user_id
     * @return bool
     */
    public static function clearQueryHistory($user_id)
    {
        $database = DatabaseFactory::getFactory()->getConnection();
        
        try {
            $sql = "DELETE FROM sql_query_history WHERE user_id = :user_id";
            $query = $database->prepare($sql);
            return $query->execute(array(':user_id' => $user_id));
        } catch (PDOException $e) {
            return false;
        }
    }

    /**
     * Get database schema for autocomplete
     * @param string $database_name
     * @return array
     */
    public static function getDatabaseSchema($database_name)
    {
        $database = DatabaseFactory::getFactory()->getConnection();
        $schema = array();
        
        try {
            // Get all tables
            $sql = "SHOW TABLES FROM " . $database_name;
            $query = $database->prepare($sql);
            $query->execute();
            $tables = $query->fetchAll(PDO::FETCH_COLUMN);
            
            foreach ($tables as $table) {
                // Get columns for each table
                $sql = "SHOW COLUMNS FROM " . $database_name . "." . $table;
                $query = $database->prepare($sql);
                $query->execute();
                $columns = $query->fetchAll(PDO::FETCH_ASSOC);
                
                $schema[$table] = array_map(function($column) {
                    return $column['Field'];
                }, $columns);
            }
            
            return $schema;
        } catch (PDOException $e) {
            return array();
        }
    }

    /**
     * Format SQL query (basic formatting)
     * @param string $query
     * @return string
     */
    public static function formatQuery($query)
    {
        // Basic SQL formatting
        $query = trim($query);
        
        // Uppercase SQL keywords
        $keywords = array(
            'SELECT', 'FROM', 'WHERE', 'AND', 'OR', 'ORDER BY', 'GROUP BY', 
            'HAVING', 'LIMIT', 'OFFSET', 'INSERT', 'INTO', 'VALUES', 
            'UPDATE', 'SET', 'DELETE', 'CREATE', 'TABLE', 'ALTER', 'DROP',
            'INDEX', 'PRIMARY KEY', 'FOREIGN KEY', 'REFERENCES', 'JOIN', 
            'INNER JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'ON', 'AS', 'DISTINCT',
            'COUNT', 'SUM', 'AVG', 'MIN', 'MAX', 'EXISTS', 'IN', 'BETWEEN',
            'LIKE', 'IS NULL', 'IS NOT NULL', 'UNION', 'ALL'
        );
        
        foreach ($keywords as $keyword) {
            $query = preg_replace('/\b' . preg_quote($keyword) . '\b/i', $keyword, $query);
        }
        
        // Add line breaks for better readability
        $query = preg_replace('/\b(FROM|WHERE|GROUP BY|ORDER BY|HAVING|LIMIT|UNION)\b/', "\n$1", $query);
        $query = preg_replace('/,\s*(\w)/', ",\n    $1", $query);
        
        return $query;
    }

    /**
     * Determine the type of SQL query
     * @param string $sql_query
     * @return string
     */
    private static function getQueryType($sql_query)
    {
        $query = strtoupper(trim($sql_query));
        
        if (strpos($query, 'SELECT') === 0) {
            return 'SELECT';
        } elseif (strpos($query, 'INSERT') === 0) {
            return 'INSERT';
        } elseif (strpos($query, 'UPDATE') === 0) {
            return 'UPDATE';
        } elseif (strpos($query, 'DELETE') === 0) {
            return 'DELETE';
        } elseif (strpos($query, 'CREATE') === 0) {
            return 'CREATE';
        } elseif (strpos($query, 'ALTER') === 0) {
            return 'ALTER';
        } elseif (strpos($query, 'DROP') === 0) {
            return 'DROP';
        } elseif (strpos($query, 'SHOW') === 0) {
            return 'SHOW';
        } elseif (strpos($query, 'DESCRIBE') === 0) {
            return 'DESCRIBE';
        } elseif (strpos($query, 'EXPLAIN') === 0) {
            return 'EXPLAIN';
        } else {
            return 'OTHER';
        }
    }
}