<?php
declare(strict_types=1);

namespace App;

final class Database
{
    public static function createPdo(Config $config): ?\PDO
    {
        if (!$config->dbEnabled) {
            return null;
        }

        $db = $config->db;
        $driver = (string)($db['driver'] ?? '');

        if ($driver === '') {
            throw new \RuntimeException('DB enabled but config/db.php missing "driver"');
        }

        $dsn = match ($driver) {
            'mysql'  => self::buildMysqlDsn($db),
            'pgsql'  => self::buildPgsqlDsn($db),
            'sqlite' => self::buildSqliteDsn($db),
            default  => throw new \RuntimeException('Unsupported PDO driver: ' . $driver),
        };

        try {
            $pdo = new \PDO(
                $dsn,
                // sqlite braucht user/pass nicht, PDO ignoriert es aber; wir geben leer zurück
                (string)($db['user'] ?? ''),
                (string)($db['password'] ?? ''),
                (array)($db['options'] ?? [])
            );

            // Optional: PostgreSQL schema/search_path setzen
            if ($driver === 'pgsql' && !empty($db['schema'])) {
                // Minimaler Schutz gegen Injection über schema
                $schema = preg_replace('/[^a-zA-Z0-9_]/', '', (string)$db['schema']);
                if ($schema !== '') {
                    $pdo->exec('SET search_path TO ' . $schema);
                }
            }

            return $pdo;
        } catch (\PDOException $e) {
            // In Prod würdest du loggen; hier minimal
            http_response_code(500);
            echo 'Database connection error.';
            exit;
        }
    }

    private static function buildMysqlDsn(array $db): string
    {
        if (empty($db['dbname'])) {
            throw new \RuntimeException('MySQL config missing "dbname"');
        }

        $charset = (string)($db['charset'] ?? 'utf8mb4');

        // Unix socket takes precedence
        if (!empty($db['unix_socket'])) {
            return sprintf(
                'mysql:unix_socket=%s;dbname=%s;charset=%s',
                (string)$db['unix_socket'],
                (string)$db['dbname'],
                $charset
            );
        }

        $host = (string)($db['host'] ?? 'localhost');
        $port = (int)($db['port'] ?? 3306);

        return sprintf(
            'mysql:host=%s;port=%d;dbname=%s;charset=%s',
            $host,
            $port,
            (string)$db['dbname'],
            $charset
        );
    }

    private static function buildPgsqlDsn(array $db): string
    {
        if (empty($db['dbname'])) {
            throw new \RuntimeException('PostgreSQL config missing "dbname"');
        }

        $host = (string)($db['host'] ?? 'localhost');
        $port = (int)($db['port'] ?? 5432);

        // Hinweis: charset gehört bei pgsql nicht in den DSN
        return sprintf(
            'pgsql:host=%s;port=%d;dbname=%s',
            $host,
            $port,
            (string)$db['dbname']
        );
    }

    private static function buildSqliteDsn(array $db): string
    {
        // SQLite kann :memory: oder einen Pfad nutzen
        $path = (string)($db['path'] ?? '');

        if ($path === '') {
            // Default: Memory-DB
            $path = ':memory:';
        }

        // Wenn es ein Pfad ist, stelle sicher, dass das Verzeichnis existiert.
        if ($path !== ':memory:') {
            $dir = \dirname($path);
            if ($dir && !is_dir($dir)) {
                @mkdir($dir, 0775, true);
            }
        }

        return 'sqlite:' . $path;
    }
}
