<?php

declare(strict_types=1);

namespace App\Repositories;

use PDO;

final class UserRepository
{
    public function __construct(private PDO $pdo)
    {
    }

    public function allCashboxes(): array
    {
        return $this->pdo->query("SELECT id, name FROM cashboxes WHERE is_active=1 ORDER BY name")->fetchAll() ?: [];
    }

    public function allRoles(): array
    {
        return $this->pdo->query("SELECT id, name FROM roles ORDER BY is_system DESC, name")->fetchAll() ?: [];
    }

    public function allUsersWithRoles(): array
    {
        return $this->pdo->query("
            SELECT u.id, u.username, u.full_name, u.is_active, u.created_at, u.cashbox_id, cb.name cashbox_name,
                   GROUP_CONCAT(r.name ORDER BY r.name SEPARATOR ', ') roles
            FROM users u
            LEFT JOIN cashboxes cb ON cb.id=u.cashbox_id
            LEFT JOIN user_roles ur ON ur.user_id=u.id
            LEFT JOIN roles r ON r.id=ur.role_id
            GROUP BY u.id
            ORDER BY u.id DESC
        ")->fetchAll() ?: [];
    }

    public function findById(int $id): array|false
    {
        $st = $this->pdo->prepare("SELECT id, username, full_name, is_active, cashbox_id FROM users WHERE id=?");
        $st->execute([$id]);
        return $st->fetch();
    }

    public function roleIdsForUser(int $id): array
    {
        $st = $this->pdo->prepare("SELECT role_id FROM user_roles WHERE user_id=?");
        $st->execute([$id]);
        $out = [];
        foreach (($st->fetchAll() ?: []) as $r) {
            $out[] = (int)$r['role_id'];
        }
        return $out;
    }


    public function usernameExists(string $username, ?int $excludeId = null): bool
    {
        if ($excludeId !== null && $excludeId > 0) {
            $st = $this->pdo->prepare("SELECT COUNT(*) FROM users WHERE username = ? AND id <> ?");
            $st->execute([$username, $excludeId]);
            return (int)$st->fetchColumn() > 0;
        }

        $st = $this->pdo->prepare("SELECT COUNT(*) FROM users WHERE username = ?");
        $st->execute([$username]);
        return (int)$st->fetchColumn() > 0;
    }

    public function create(array $data): int
    {
        $st = $this->pdo->prepare("INSERT INTO users (username, password_hash, full_name, is_active, cashbox_id) VALUES (?,?,?,?,?)");
        $st->execute([
            $data['username'],
            $data['password_hash'],
            $data['full_name'] ?: null,
            $data['is_active'],
            $data['cashbox_id'] > 0 ? $data['cashbox_id'] : null,
        ]);

        return (int)$this->pdo->lastInsertId();
    }

    public function update(int $id, array $data): void
    {
        if (!empty($data['password_hash'])) {
            $this->pdo->prepare("UPDATE users SET username=?, full_name=?, is_active=?, cashbox_id=?, password_hash=? WHERE id=?")
                ->execute([
                    $data['username'],
                    $data['full_name'] ?: null,
                    $data['is_active'],
                    $data['cashbox_id'] > 0 ? $data['cashbox_id'] : null,
                    $data['password_hash'],
                    $id,
                ]);
            return;
        }

        $this->pdo->prepare("UPDATE users SET username=?, full_name=?, is_active=?, cashbox_id=? WHERE id=?")
            ->execute([
                $data['username'],
                $data['full_name'] ?: null,
                $data['is_active'],
                $data['cashbox_id'] > 0 ? $data['cashbox_id'] : null,
                $id,
            ]);
    }

    public function replaceRoles(int $userId, array $roleIds): void
    {
        $this->pdo->prepare("DELETE FROM user_roles WHERE user_id=?")->execute([$userId]);
        $ins = $this->pdo->prepare("INSERT IGNORE INTO user_roles (user_id, role_id) VALUES (?,?)");
        foreach ($roleIds as $rid) {
            $ins->execute([$userId, (int)$rid]);
        }
    }

    public function delete(int $id): void
    {
        $this->pdo->prepare("DELETE FROM users WHERE id=?")->execute([$id]);
    }
}
