<?php
declare(strict_types=1);

namespace App\Models;

use App\Core\Auth;
use App\Core\Database;

abstract class BaseModel
{
    protected static string $table = '';
    protected static bool $tenantScoped = true;
    protected static bool $softDelete = false;

    protected static function db(): Database
    {
        return Database::instance();
    }

    protected static function tenantId(): int
    {
        $id = Auth::instance()->tenantId();
        if (!$id) {
            throw new \RuntimeException('No tenant in session.');
        }
        return $id;
    }

    public static function find(int $id): ?array
    {
        $sql = 'SELECT * FROM `' . static::$table . '` WHERE id = :id';
        $params = ['id' => $id];
        if (static::$tenantScoped) {
            $sql .= ' AND tenant_id = :tenant_id';
            $params['tenant_id'] = static::tenantId();
        }
        if (static::$softDelete) {
            $sql .= ' AND deleted_at IS NULL';
        }
        return static::db()->fetch($sql, $params);
    }

    public static function create(array $data): int
    {
        if (static::$tenantScoped && empty($data['tenant_id'])) {
            $data['tenant_id'] = static::tenantId();
        }
        $cols = array_keys($data);
        $fields = implode(',', array_map(static fn($c) => "`$c`", $cols));
        $place = implode(',', array_map(static fn($c) => ':' . $c, $cols));
        static::db()->query(
            'INSERT INTO `' . static::$table . "` ($fields) VALUES ($place)",
            $data
        );
        return (int) static::db()->lastId();
    }

    public static function update(int $id, array $data): void
    {
        unset($data['id'], $data['tenant_id']);
        if ($data === []) {
            return;
        }
        $sets = [];
        foreach ($data as $col => $val) {
            $sets[] = "`$col` = :$col";
        }
        $data['id'] = $id;
        $sql = 'UPDATE `' . static::$table . '` SET ' . implode(',', $sets) . ' WHERE id = :id';
        if (static::$tenantScoped) {
            $sql .= ' AND tenant_id = :tenant_id';
            $data['tenant_id'] = static::tenantId();
        }
        static::db()->query($sql, $data);
    }

    public static function softDelete(int $id): void
    {
        $sql = 'UPDATE `' . static::$table . '` SET deleted_at = NOW() WHERE id = :id';
        $params = ['id' => $id];
        if (static::$tenantScoped) {
            $sql .= ' AND tenant_id = :tenant_id';
            $params['tenant_id'] = static::tenantId();
        }
        static::db()->query($sql, $params);
    }
}
