<?php
/**
 * ===========================================
 * FLOWBOT DCI - DATABASE CONNECTION
 * ===========================================
 */

declare(strict_types=1);

namespace FlowbotDCI\Core;

use PDO;
use PDOException;

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

    public function __construct(array $config)
    {
        // Validate required configuration
        $required = ['host', 'name', 'user', 'password'];
        foreach ($required as $key) {
            if (!isset($config[$key])) {
                throw new \InvalidArgumentException("Database config missing required key: {$key}");
            }
        }

        // Set default charset if not provided
        if (!isset($config['charset'])) {
            $config['charset'] = 'utf8mb4';
        }

        $this->config = $config;
    }

    /**
     * Get PDO instance (singleton pattern)
     */
    public function getConnection(): PDO
    {
        if (self::$instance === null) {
            self::$instance = $this->createConnection();
        }
        return self::$instance;
    }

    /**
     * Create new PDO connection
     */
    private function createConnection(): PDO
    {
        $dsn = sprintf(
            "mysql:host=%s;dbname=%s;charset=%s",
            $this->config['host'],
            $this->config['name'],
            $this->config['charset']
        );

        $options = [
            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES   => false,
            PDO::ATTR_TIMEOUT            => 5, // 5 second connection timeout
        ];

        try {
            $pdo = new PDO($dsn, $this->config['user'], $this->config['password'], $options);

            // Set connection options
            $pdo->exec("SET NAMES " . $this->config['charset']);

            return $pdo;
        } catch (PDOException $e) {
            $message = "Database connection failed to {$this->config['host']}/{$this->config['name']}: " . $e->getMessage();
            error_log($message);
            throw new PDOException($message, (int)$e->getCode(), $e);
        }
    }

    /**
     * Close connection
     */
    public static function close(): void
    {
        self::$instance = null;
    }

    /**
     * Begin transaction
     */
    public function beginTransaction(): bool
    {
        return $this->getConnection()->beginTransaction();
    }

    /**
     * Commit transaction
     */
    public function commit(): bool
    {
        return $this->getConnection()->commit();
    }

    /**
     * Rollback transaction
     */
    public function rollback(): bool
    {
        return $this->getConnection()->rollBack();
    }

    /**
     * Execute query with prepared statement
     */
    public function query(string $sql, array $params = []): \PDOStatement
    {
        $stmt = $this->getConnection()->prepare($sql);
        $stmt->execute($params);
        return $stmt;
    }

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