<?php
/**
 * Database - PDO Singleton
 * Aegean Dominance - İzmir Tenteci V2
 */

declare(strict_types=1);

class Database
{
    private static ?Database $instance = null;
    private PDO $connection;

    private function __construct()
    {
        try {
            $dsn = sprintf(
                'mysql:host=%s;dbname=%s;charset=%s',
                DB_HOST,
                DB_NAME,
                DB_CHARSET
            );

            $options = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false,
                PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_turkish_ci"
            ];

            $this->connection = new PDO($dsn, DB_USER, DB_PASS, $options);
        } catch (PDOException $e) {
            if (APP_DEBUG) {
                throw new Exception("Database Connection Error: " . $e->getMessage());
            }
            error_log("Database Error: " . $e->getMessage());
            die('Veritabanı bağlantı hatası. Lütfen site yöneticisi ile iletişime geçin.');
        }
    }

    public static function getInstance(): self
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function getConnection(): PDO
    {
        return $this->connection;
    }

    /**
     * Execute a query and return all results
     */
    public function fetchAll(string $sql, array $params = []): array
    {
        try {
            $stmt = $this->connection->prepare($sql);
            $stmt->execute($params);
            return $stmt->fetchAll();
        } catch (PDOException $e) {
            error_log("DB fetchAll error: " . $e->getMessage() . " | SQL: " . $sql);
            if (defined('APP_DEBUG') && APP_DEBUG) {
                throw $e;
            }
            return [];
        }
    }

    /**
     * Execute a query and return single row
     */
    public function fetchOne(string $sql, array $params = []): ?array
    {
        try {
            $stmt = $this->connection->prepare($sql);
            $stmt->execute($params);
            $result = $stmt->fetch();
            return $result ?: null;
        } catch (PDOException $e) {
            error_log("DB fetchOne error: " . $e->getMessage() . " | SQL: " . $sql);
            if (defined('APP_DEBUG') && APP_DEBUG) {
                throw $e;
            }
            return null;
        }
    }

    /**
     * Execute a query and return single value
     */
    public function fetchColumn(string $sql, array $params = []): mixed
    {
        try {
            $stmt = $this->connection->prepare($sql);
            $stmt->execute($params);
            return $stmt->fetchColumn();
        } catch (PDOException $e) {
            error_log("DB fetchColumn error: " . $e->getMessage() . " | SQL: " . $sql);
            if (defined('APP_DEBUG') && APP_DEBUG) {
                throw $e;
            }
            return false;
        }
    }

    /**
     * Execute insert/update/delete
     */
    public function execute(string $sql, array $params = []): int
    {
        try {
            $stmt = $this->connection->prepare($sql);
            $stmt->execute($params);
            return $stmt->rowCount();
        } catch (PDOException $e) {
            error_log("DB execute error: " . $e->getMessage() . " | SQL: " . $sql);
            if (defined('APP_DEBUG') && APP_DEBUG) {
                throw $e;
            }
            return 0;
        }
    }

    /**
     * Get last insert ID
     */
    public function lastInsertId(): string
    {
        return $this->connection->lastInsertId();
    }

    /**
     * Get setting value
     */
    public function getSetting(string $key, string $default = ''): string
    {
        static $cache = [];
        
        if (isset($cache[$key])) {
            return $cache[$key];
        }

        $value = $this->fetchColumn(
            "SELECT setting_value FROM settings WHERE setting_key = ? AND is_active = 1",
            [$key]
        );

        $cache[$key] = $value !== false ? (string)$value : $default;
        return $cache[$key];
    }

    /**
     * Get all settings by category
     */
    public function getSettingsByCategory(string $category): array
    {
        return $this->fetchAll(
            "SELECT setting_key, setting_value FROM settings WHERE category = ? AND is_active = 1",
            [$category]
        );
    }

    // Prevent cloning
    private function __clone() {}

    // Prevent unserialization
    public function __wakeup(): void
    {
        throw new Exception("Cannot unserialize singleton");
    }
}

/**
 * Helper function to get database instance
 */
function db(): Database
{
    return Database::getInstance();
}

/**
 * Helper function to get setting
 */
function setting(string $key, string $default = ''): string
{
    return db()->getSetting($key, $default);
}
