<?php

namespace classes;

use Exception;
use mysqli;
use objects\orders_o;

class db
{
    public mysqli $conn;
    private string $host;
    private string $user;
    private string $password;
    private string $database;
    private string $ssl_mode = 'DISABLED'; // mysqldump SSL mode (e.g., DISABLED, PREFERRED, REQUIRED, VERIFY_CA, VERIFY_IDENTITY)

    public function __construct(array $config)
    {
        $this->host = $config['host'];
        $this->user = $config['user'];
        $this->password = $config['password'];
        $this->database = $config['database'];
        if (isset($config['ssl_mode']) && is_string($config['ssl_mode']) && $config['ssl_mode'] !== '') {
            $this->ssl_mode = $config['ssl_mode'];
        }
    }

    public static function getPDO(): \PDO
    {
        global $config;
        $dsn = "mysql:host={$config['db']['host']};dbname={$config['db']['database']};charset=utf8mb4";
        return new \PDO($dsn, $config['db']['user'], $config['db']['password'], [
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
            \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
            \PDO::ATTR_EMULATE_PREPARES => false,
        ]);
    }

    public function connect(): void
    {
        global $response;
        try {
            $this->conn = new mysqli($this->host, $this->user, $this->password, $this->database);
        } catch (Exception $e) {
            $response->internal_server_error($e->getMessage());
        }
    }

    public function escape_string(string $string): string
    {
        return $this->conn->real_escape_string($string);
    }

    public function close(): void
    {
        $this->conn->close();
    }

    public function get(string $table, int $id)
    {
        $sql = "SELECT * FROM $table WHERE id = $id";
        $result = $this->query($sql);
        return $this->fetch_assoc($result);
    }

    public function query(string $sql): \mysqli_result|bool
    {
        // If the connection is not established, connect
        return $this->conn->query($sql);
    }

    public function fetch_assoc($result)
    {
        return $result->fetch_assoc();
    }

    public function list_objects(string $table): array
    {
        $sql = "SELECT * FROM $table";
        $result = $this->query($sql);
        return $this->fetch_all($result);
    }

    public function fetch_all($result)
    {
        return $result->fetch_all(MYSQLI_ASSOC);
    }

    public function list_objects_paginated(string $table, int $page, int $limit): array
    {
        $offset = ($page - 1) * $limit;
        $sql = "SELECT * FROM $table LIMIT $limit OFFSET $offset";
        $result = $this->query($sql);
        return $this->fetch_all($result);
    }

    public function count_objects(string $table): int
    {
        $sql = "SELECT COUNT(*) FROM $table";
        $result = $this->query($sql);
        return $result->fetch_row()[0];
    }

    public function insert_id(): int
    {
        return $this->conn->insert_id;
    }

    public function conn(): mysqli
    {
        return $this->conn;
    }

    public function prepare(string $sql): false|\mysqli_stmt
    {
        return $this->conn->prepare($sql);
    }

    public function num_rows(\mysqli_result|bool $result): int|string
    {
        return $result->num_rows;
    }

    public function getUsername()
    {
        return $this->user;
    }

    public function getPassword()
    {
        return $this->password;
    }

    public function getHost()
    {
        return $this->host;
    }

    public function getDatabase()
    {
        return $this->database;
    }

    public function backupDatabase(string $path): bool
    {
        // Save the database to the path
        // Build a safe mysqldump command with configurable SSL (MariaDB-compatible flags)
        $mode = strtoupper(trim($this->ssl_mode));
        // Map ssl_mode to MariaDB client flags
        // DISABLED => --skip-ssl (no TLS)
        // PREFERRED => (no flag; client decides)
        // REQUIRED/VERIFY_* => --ssl (enable TLS without strict verification unless CA materials provided)
        $sslFlag = '';
        switch ($mode) {
            case 'DISABLED':
                $sslFlag = '--skip-ssl';
                break;
            case 'PREFERRED':
                $sslFlag = '';
                break;
            case 'REQUIRED':
            case 'VERIFY_CA':
            case 'VERIFY_IDENTITY':
            default:
                $sslFlag = '--ssl';
                break;
        }
        $host = escapeshellarg($this->host);
        $user = escapeshellarg($this->user);
        $pass = escapeshellarg($this->password);
        $db   = escapeshellarg($this->database);
        $outfile = escapeshellarg($path);
        $sslPart = $sslFlag !== '' ? ($sslFlag . ' ') : '';
        $command = "mysqldump {$sslPart}-h $host -u $user --password=$pass $db > $outfile 2>&1";
        exec($command, $output, $return);
        // Check if the command was successful
        return $return === 0;
    }

    public function getView(string $view): array
    {
        $sql = "SELECT * FROM $view";
        $result = $this->query($sql);
        return $this->fetch_all($result);
    }

    /**
     * Generate a fake ID for a table.
     * Fake ids are not stored in the database, they are generated on every request starting from -1.
     * This is useful for testing purposes.
     * @see orders_o::simulateOrderFromXLVask()
     * @param string $table
     * @return int
     */
    public function getNextFakeId(string $table): int
    {
        // This is a static variable that will be shared across all instances of the class
        static $fakeId = 0; // Start from 0 and decrement on each call
        $fakeId--;
        return $fakeId;
    }


}