<?php
/*
 * PDO Database Class
 * Connects to the database using credentials from config.php.
 * Creates prepared statements to securely execute queries.
 * Binds values to prevent SQL injection.
 * Returns rows and results.
 */
class Database {
    private $host = DB_HOST;
    private $user = DB_USER;
    private $pass = DB_PASS;
    private $dbname = DB_NAME;

    private $dbh; // Database Handler
    private $stmt; // Statement
    private $error;

    public function __construct(){
        // Set DSN (Data Source Name)
        $dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbname . ';charset=utf8mb4';
        $options = [
            PDO::ATTR_PERSISTENT => true, // Persistent connection to improve performance
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // Throw exceptions on errors
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ, // Fetch results as objects
            PDO::ATTR_EMULATE_PREPARES => false, // Use native prepared statements
        ];

        // Create PDO instance
        try {
            $this->dbh = new PDO($dsn, $this->user, $this->pass, $options);
        } catch(PDOException $e){
            $this->error = $e->getMessage();
            // In a real app, you'd log this error, not echo it
            die('Database Connection Error: ' . $this->error);
        }
    }

    // Prepare statement with query
    public function query($sql){
        $this->stmt = $this->dbh->prepare($sql);
    }

    // Bind values to the prepared statement
    public function bind($param, $value, $type = null){
        if(is_null($type)){
            switch(true){
                case is_int($value):
                    $type = PDO::PARAM_INT;
                    break;
                case is_bool($value):
                    $type = PDO::PARAM_BOOL;
                    break;
                case is_null($value):
                    $type = PDO::PARAM_NULL;
                    break;
                default:
                    $type = PDO::PARAM_STR;
            }
        }
        $this->stmt->bindValue($param, $value, $type);
    }

    // Execute the prepared statement
    public function execute($params = null){
        return $this->stmt->execute($params);
    }

    // Get result set as an array of objects
    public function resultSet($params = null){
        $this->stmt->execute($params);
        return $this->stmt->fetchAll();
    }

    // Get a single record as an object
    public function single(){
        $this->execute();
        return $this->stmt->fetch();
    }

    // Get the last inserted ID
    public function lastInsertId(){
        return $this->dbh->lastInsertId();
    }

    // Get row count
    public function rowCount(){
        return $this->stmt->rowCount();
    }

    // Start a transaction
    public function beginTransaction(){
        if (!$this->dbh->inTransaction()) {
            return $this->dbh->beginTransaction();
        }
        return true;
    }

    // Commit a transaction
    public function commit(){
        if ($this->dbh->inTransaction()) {
            return $this->dbh->commit();
        }
        return false;
    }

    // Roll back a transaction
    public function rollBack(){
        if ($this->dbh->inTransaction()) {
            return $this->dbh->rollBack();
        }
        return false;
    }

    // Check if inside a transaction
    public function inTransaction(){
        return $this->dbh->inTransaction();
    }
}
?>