<?php
/**
 * Base Model
 */

require_once __DIR__ . '/../../database/Database.php';

abstract class Model {
    protected PDO $db;
    protected string $table = '';
    protected string $primaryKey = 'id';

    public function __construct() {
        $this->db = Database::getInstance();
    }

    public function findById($id): ?array {
        $stmt = $this->db->prepare("SELECT * FROM `{$this->table}` WHERE `{$this->primaryKey}` = :id LIMIT 1");
        $stmt->execute([':id' => $id]);
        $result = $stmt->fetch();
        return $result ?: null;
    }

    public function query(string $sql, array $params = []): PDOStatement {
        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        return $stmt;
    }

    public function fetchAll(string $sql, array $params = []): array {
        return $this->query($sql, $params)->fetchAll();
    }

    public function fetchOne(string $sql, array $params = []): ?array {
        $res = $this->query($sql, $params)->fetch();
        return $res ?: null;
    }

    public function insert(array $data): int {
        $fields = array_keys($data);
        $placeholders = array_map(fn($f) => ':' . $f, $fields);

        $sql = sprintf(
            "INSERT INTO `%s` (`%s`) VALUES (%s)",
            $this->table,
            implode('`, `', $fields),
            implode(', ', $placeholders)
        );

        $bindings = [];
        foreach ($data as $key => $val) {
            $bindings[':' . $key] = $val;
        }

        $this->query($sql, $bindings);
        return (int)$this->db->lastInsertId();
    }

    public function update($id, array $data): bool {
        $setClauses = [];
        $bindings = [':id' => $id];

        foreach ($data as $field => $val) {
            $setClauses[] = "`{$field}` = :{$field}";
            $bindings[':' . $field] = $val;
        }

        $sql = sprintf(
            "UPDATE `%s` SET %s WHERE `%s` = :id",
            $this->table,
            implode(', ', $setClauses),
            $this->primaryKey
        );

        $this->query($sql, $bindings);
        return true;
    }

    public function delete($id): bool {
        $sql = "DELETE FROM `{$this->table}` WHERE `{$this->primaryKey}` = :id";
        $this->query($sql, [':id' => $id]);
        return true;
    }
}
