<?php
/**
 * Tenant-scoped Base Model
 * All child models automatically filter by tenant_id
 */
abstract class Model {
    protected static string $table = '';
    protected static ?int   $tenantId = null;

    protected static function tenantId(): int {
        if (static::$tenantId !== null) return static::$tenantId;
        $id = Auth::tenantId();
        if (!$id) throw new RuntimeException('No tenant context in model query.');
        return $id;
    }

    /** Override tenant scope (used by super admin) */
    public static function forTenant(int $tenantId): void {
        static::$tenantId = $tenantId;
    }

    public static function resetTenant(): void {
        static::$tenantId = null;
    }

    // ── Find by ID (tenant-scoped) ──────────────────────────
    public static function find(int $id): ?array {
        $stmt = db()->prepare("SELECT * FROM `".static::$table."` WHERE id = ? AND tenant_id = ? LIMIT 1");
        $stmt->execute([$id, static::tenantId()]);
        return $stmt->fetch() ?: null;
    }

    // ── Find all (tenant-scoped + optional conditions) ──────
    public static function all(string $orderBy = 'id DESC', int $limit = 0, int $offset = 0): array {
        $sql = "SELECT * FROM `".static::$table."` WHERE tenant_id = ? ORDER BY {$orderBy}";
        if ($limit > 0) $sql .= " LIMIT {$limit} OFFSET {$offset}";
        $stmt = db()->prepare($sql);
        $stmt->execute([static::tenantId()]);
        return $stmt->fetchAll();
    }

    // ── Count all (tenant-scoped) ───────────────────────────
    public static function count(string $where = '', array $params = []): int {
        $sql = "SELECT COUNT(*) FROM `".static::$table."` WHERE tenant_id = ?";
        if ($where) $sql .= " AND ({$where})";
        $stmt = db()->prepare($sql);
        $stmt->execute(array_merge([static::tenantId()], $params));
        return (int)$stmt->fetchColumn();
    }

    // ── Insert ──────────────────────────────────────────────
    public static function create(array $data): int {
        $data['tenant_id'] = static::tenantId();
        $cols = implode(',', array_map(fn($c) => "`{$c}`", array_keys($data)));
        $vals = implode(',', array_fill(0, count($data), '?'));
        $stmt = db()->prepare("INSERT INTO `".static::$table."` ({$cols}) VALUES ({$vals})");
        $stmt->execute(array_values($data));
        return (int)db()->lastInsertId();
    }

    // ── Update ──────────────────────────────────────────────
    public static function update(int $id, array $data): bool {
        $sets = implode(',', array_map(fn($c) => "`{$c}` = ?", array_keys($data)));
        $stmt = db()->prepare("UPDATE `".static::$table."` SET {$sets} WHERE id = ? AND tenant_id = ?");
        return $stmt->execute([...array_values($data), $id, static::tenantId()]);
    }

    // ── Delete (soft or hard) ───────────────────────────────
    public static function delete(int $id): bool {
        $cols = db()->query("SHOW COLUMNS FROM `".static::$table."` LIKE 'is_active'")->fetchAll();
        if (!empty($cols)) {
            return static::update($id, ['is_active' => 0]);
        }
        $stmt = db()->prepare("DELETE FROM `".static::$table."` WHERE id = ? AND tenant_id = ?");
        return $stmt->execute([$id, static::tenantId()]);
    }

    // ── Raw query (tenant-aware) ────────────────────────────
    public static function query(string $sql, array $params = []): array {
        // Auto-inject tenant_id if :tenant_id placeholder exists
        if (str_contains($sql, ':tenant_id')) {
            $params[':tenant_id'] = static::tenantId();
        }
        $stmt = db()->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll();
    }

    public static function queryOne(string $sql, array $params = []): ?array {
        $results = static::query($sql, $params);
        return $results[0] ?? null;
    }

    public static function execute(string $sql, array $params = []): bool {
        if (str_contains($sql, ':tenant_id')) {
            $params[':tenant_id'] = static::tenantId();
        }
        return db()->prepare($sql)->execute($params);
    }

    // ── Paginate ────────────────────────────────────────────
    public static function paginate(int $page, int $perPage, string $where = '', array $params = [], string $orderBy = 'id DESC'): array {
        $perPage = $_GET['per_page'] ?? $perPage;
        $pp = $perPage === 'all' ? PHP_INT_MAX : (int)$perPage;
        $offset = ($page - 1) * $pp;
        $total  = static::count($where, $params);
        $sql    = "SELECT * FROM `".static::$table."` WHERE tenant_id = ?";
        if ($where) $sql .= " AND ({$where})";
        $sql .= " ORDER BY {$orderBy} LIMIT {$pp} OFFSET {$offset}";
        $stmt = db()->prepare($sql);
        $stmt->execute(array_merge([static::tenantId()], $params));
        return [
            'data'       => $stmt->fetchAll(),
            'total'      => $total,
            'page'       => $page,
            'per_page'   => $perPage,
            'last_page'  => $perPage === 'all' ? 1 : (int)ceil($total / $pp),
        ];
    }
}
