<?php

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

class Database {
    private static $instance = null;
    private $db;
    private $tables = [
        'users' => [
            'id' => 'INTEGER PRIMARY KEY AUTOINCREMENT',
            'username' => 'TEXT UNIQUE',
            'password' => 'TEXT',
        ],
        
        'dns' => [
            'id' => 'INTEGER PRIMARY KEY AUTOINCREMENT',
            'dns_code' => 'TEXT',
            'dns_name' => 'TEXT',
            'dns_url' => 'TEXT',
            'dns_message' => 'TEXT',
            'dns_background' => 'TEXT',
            'dns_logo' => 'TEXT',
            'dns_intro' => 'TEXT'
        ],
    ];

    private function __construct($dbname) {
        try {
            $this->db = new SQLite3($dbname);
            $this->initializeTables();
            $this->initializeDefaultCredentials();
        } catch (Exception $e) {
            error_log("Unable to open database: " . $e->getMessage());
        }
    }

    public static function getInstance($dbname) {
        if (self::$instance === null) {
            self::$instance = new Database($dbname);
        }
        return self::$instance;
    }

    private function initializeTables() {
        foreach ($this->tables as $tableName => $columns) {
            $this->createTable($tableName, $columns);
        }
    }

    private function createTable($tableName, $columns) {
        $columnsDef = implode(', ', array_map(function($col, $type) {
            return "$col $type";
        }, array_keys($columns), $columns));
        $sql = "CREATE TABLE IF NOT EXISTS $tableName ($columnsDef)";
        if (!$this->execute($sql)) {
            error_log("Failed to create table: $tableName");
        }
    }

    private function initializeDefaultCredentials() {
        $userCount = $this->count('users');
        if ($userCount == 0) {
            $this->insert('users', [
                'username' => 'admin',
                'password' => 'admin123',
            ]);
        }
    }

    public function insert($tableName, $data) {
        $data = array_map([$this, 'sanitize'], $data);
        $columns = implode(', ', array_keys($data));
        $placeholders = ':' . implode(', :', array_keys($data));
        $sql = "INSERT INTO $tableName ($columns) VALUES ($placeholders)";
        return $this->execute($sql, $data);
    }

    public function update($tableName, $data, $where) {
        $data = array_map([$this, 'sanitize'], $data);
        $setClause = implode(', ', array_map(function($col) {
            return "$col = :$col";
        }, array_keys($data)));
        $whereClause = implode(' AND ', array_map(function($col) {
            return "$col = :where_$col";
        }, array_keys($where)));
        $params = array_merge($data, array_combine(array_map(function($k) {
            return "where_$k";
        }, array_keys($where)), $where));
        $sql = "UPDATE $tableName SET $setClause WHERE $whereClause";

        try {
            return $this->execute($sql, $params);
        } catch (Exception $e) {
            error_log("Update failed: " . $e->getMessage());
            return false;
        }
    }

    public function delete($tableName, $where = []) {
        if (empty($where)) {
            $sql = "DELETE FROM $tableName";
        } else {
            $whereClause = implode(' AND ', array_map(function($col) {
                return "$col = :$col";
            }, array_keys($where)));
            $sql = "DELETE FROM $tableName WHERE $whereClause";
        }

        return $this->execute($sql, $where);
    }

    public function select($tableName, $columns = '*', $where = [], $fetchAll = true) {
        $columns = is_array($columns) ? implode(', ', $columns) : $columns;
        $sql = "SELECT $columns FROM $tableName";
        if ($where) {
            $whereClause = implode(' AND ', array_map(function($col) {
                return "$col = :$col";
            }, array_keys($where)));
            $sql .= " WHERE $whereClause";
        }
        $result = $this->execute($sql, $where);
        return $fetchAll ? $this->fetchAll($result) : $this->fetchOne($result);
    }

    private function execute($sql, $params = []) {
        try {
            $stmt = $this->db->prepare($sql);
            if ($params) {
                foreach ($params as $key => $value) {
                    $stmt->bindValue(':' . $key, $value);
                }
            }
            $result = $stmt->execute();
            if (!$result) {
                throw new Exception($this->db->lastErrorMsg());
            }
            return $result;
        } catch (Exception $e) {
            error_log("SQL execution failed: " . $e->getMessage());
            return false;
        }
    }

    private function fetchAll($result) {
        $rows = [];
        if ($result) {
            while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
                $rows[] = $row;
            }
        }
        return $rows;
    }

    private function fetchOne($result) {
        if ($result) {
            return $result->fetchArray(SQLITE3_ASSOC);
        }
        return false;
    }

    private function sanitize($value) {
        return htmlspecialchars(strip_tags($value));
    }

    public function getUserByUsername($username) {
        $stmt = $this->db->prepare('SELECT * FROM users WHERE username = :username');
        $stmt->bindValue(':username', $username, SQLITE3_TEXT);
        $result = $stmt->execute();
        
        if ($result) {
            $user = $result->fetchArray(SQLITE3_ASSOC);
            return $user ? $user : false; 
        } else {
            error_log('Query Error: ' . $this->db->lastErrorMsg());
            return false;
        }
    }

    public function count($tableName, $where = []) {
        $sql = "SELECT COUNT(*) as count FROM $tableName";
        if ($where) {
            $whereClause = implode(' AND ', array_map(function($col) {
                return "$col = :$col";
            }, array_keys($where)));
            $sql .= " WHERE $whereClause";
        }
        $result = $this->execute($sql, $where);
        if ($result) {
            $row = $result->fetchArray(SQLITE3_ASSOC);
            return $row['count'];
        }
        return 0;
    }

    public function customQuery($sql, $params = []) {
        $result = $this->execute($sql, $params);
        return $this->fetchAll($result);
    }

    public function getUserById($userId) {
        $stmt = $this->db->prepare('SELECT * FROM users WHERE id = :id');
        $stmt->bindValue(':id', $userId, SQLITE3_INTEGER);
        $result = $stmt->execute();

        if ($result) {
            $user = $result->fetchArray(SQLITE3_ASSOC);
            return $user ? $user : false;
        } else {
            error_log('Query Error: ' . $this->db->lastErrorMsg());
            return false;
        }
    }

    public function close() {
        $this->db->close();
    }
}
function logoutUser() {
    if (session_status() === PHP_SESSION_NONE) {
        session_start();
    }

    $_SESSION = [];

    if (ini_get("session.use_cookies")) {
        $params = session_get_cookie_params();
        setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"]);
    }
    session_destroy();
    header('Location: index.php');
    exit();
}
$db = Database::getInstance(__DIR__ . '/../api/86hax.db'); 
?>
