<?php

namespace App\Core;

use PDO;
use PDOException;

/**
 * PDO Database wrapper using Singleton pattern.
 */
class Database
{
    private static ?PDO $instance = null;

    /**
     * Get active PDO database instance
     *
     * @return PDO
     * @throws PDOException
     */
    public static function getConnection(): PDO
    {
        if (self::$instance === null) {
            $host = getenv('DB_HOST') ?: '127.0.0.1';
            $port = getenv('DB_PORT') ?: '3306';
            $dbName = getenv('DB_DATABASE') ?: 'nabeh_master';
            $username = getenv('DB_USERNAME') ?: 'root';
            $password = getenv('DB_PASSWORD') ?: '';

            $dsn = "mysql:host={$host};port={$port};dbname={$dbName};charset=utf8mb4";

            $options = [
                PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES   => false,
            ];

            try {
                self::$instance = new PDO($dsn, $username, $password, $options);
            } catch (PDOException $e) {
                // Log the exact error internally but hide sensitive DSN on production
                error_log("Database Connection Error: " . $e->getMessage());
                throw new PDOException("Could not connect to the database. Check database settings.");
            }
        }

        return self::$instance;
    }

    /**
     * Shorthand execute statement with parameters
     *
     * @param string $sql
     * @param array $params
     * @return \PDOStatement
     */
    public static function query(string $sql, array $params = []): \PDOStatement
    {
        $pdo = self::getConnection();
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt;
    }

    /**
     * Retrieve all matching records
     */
    public static function select(string $sql, array $params = []): array
    {
        return self::query($sql, $params)->fetchAll();
    }

    /**
     * Retrieve single matching record
     */
    public static function selectOne(string $sql, array $params = [])
    {
        return self::query($sql, $params)->fetch() ?: null;
    }

    /**
     * Insert record and return last inserted ID
     */
    public static function insert(string $sql, array $params = []): string
    {
        $pdo = self::getConnection();
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
        return $pdo->lastInsertId();
    }

    /**
     * Execute generic non-query SQL (Update/Delete) and return affected rows
     */
    public static function execute(string $sql, array $params = []): int
    {
        return self::query($sql, $params)->rowCount();
    }
}
