<?php

declare(strict_types=1);

namespace App\Framework\Database\Driver;

use PDO;

/**
 * PostgreSQL driver with optimized connection settings
 *
 * Features:
 * - Native prepared statements (no emulation)
 * - UTF-8 client encoding
 * - Application name for pg_stat_activity monitoring
 * - Connection timeout and retry logic ready
 */
final readonly class PostgresDriver implements Driver
{
    public string $dsn;

    public array $options;

    public function __construct(
        public DriverConfig $config,
    ) {
        $this->dsn = $this->createDsn();
        $this->options = $this->getOptions();
    }

    private function createDsn(): string
    {
        $parts = [
            'host' => $this->config->host,
            'port' => $this->config->port,
            'dbname' => $this->config->database,
        ];

        // Add optional DSN parameters
        if ($this->config->charset !== 'utf8mb4') {
            // PostgreSQL uses 'UTF8' instead of 'utf8'
            $encoding = match($this->config->charset) {
                'utf8', 'utf8mb4' => 'UTF8',
                default => strtoupper($this->config->charset)
            };
            $parts['options'] = "--client_encoding={$encoding}";
        }

        // Application name for pg_stat_activity monitoring
        $appName = $_ENV['APP_NAME'] ?? 'custom-php-framework';
        $parts['application_name'] = $appName;

        // Connect timeout (5 seconds default)
        $parts['connect_timeout'] = '5';

        $dsnParts = [];
        foreach ($parts as $key => $value) {
            // Convert to string for checking
            $valueStr = (string) $value;

            // Quote values that contain spaces or special characters
            if (str_contains($valueStr, ' ') || str_contains($valueStr, ';') || str_contains($valueStr, '=')) {
                $value = "'" . str_replace("'", "\\'", $valueStr) . "'";
            }
            $dsnParts[] = "{$key}={$value}";
        }

        return 'pgsql:' . implode(';', $dsnParts);
    }

    private function getOptions(): array
    {
        return [
            // Error handling
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,

            // Fetch mode
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,

            // No prepared statement emulation (PostgreSQL native)
            PDO::ATTR_EMULATE_PREPARES => false,

            // Persistent connections disabled by default (better for connection pooling)
            PDO::ATTR_PERSISTENT => false,

            // Statement class (for custom statement handling)
            PDO::ATTR_STATEMENT_CLASS => [\PDOStatement::class],

            // String handling
            PDO::ATTR_STRINGIFY_FETCHES => false,  // Keep native types

            // NULL handling
            PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,

            // Case handling for column names
            PDO::ATTR_CASE => PDO::CASE_NATURAL,

            // Timeout for queries (30 seconds)
            PDO::ATTR_TIMEOUT => 30,
        ];
    }
}
