<?php

declare(strict_types=1);

class Usuario extends Model
{
    public function buscarPorEmail(string $email): ?array
    {
        $stmt = $this->db->prepare("SELECT * FROM usuarios WHERE email = :email AND ativo = 1 LIMIT 1");
        $stmt->execute(['email' => $email]);

        $usuario = $stmt->fetch();
        if (!$usuario) {
            return null;
        }

        $usuario['servicos_ids'] = $this->servicosIds((int) $usuario['id']);
        $usuario['servicos_nomes'] = $this->servicosNomes((int) $usuario['id']);

        return $usuario;
    }

    public function todos(): array
    {
        $sql = "SELECT u.*,
                       (
                           SELECT GROUP_CONCAT(c.nome ORDER BY c.nome SEPARATOR ', ')
                           FROM usuario_servicos us
                           INNER JOIN categorias c ON c.id = us.categoria_id
                           WHERE us.usuario_id = u.id
                       ) AS servicos_nomes
                FROM usuarios u
                ORDER BY u.nome ASC";
        return $this->db->query($sql)->fetchAll();
    }

    public function buscarPorId(int $id): ?array
    {
        $stmt = $this->db->prepare("SELECT * FROM usuarios WHERE id = :id LIMIT 1");
        $stmt->execute(['id' => $id]);
        $usuario = $stmt->fetch();

        if (!$usuario) {
            return null;
        }

        $usuario['servicos_ids'] = $this->servicosIds($id);
        $usuario['servicos_nomes'] = $this->servicosNomes($id);

        return $usuario;
    }

    public function emailEmUso(string $email, ?int $ignorarId = null): bool
    {
        $sql = "SELECT id FROM usuarios WHERE email = :email";
        $params = ['email' => $email];

        if ($ignorarId !== null) {
            $sql .= " AND id <> :id";
            $params['id'] = $ignorarId;
        }

        $sql .= " LIMIT 1";
        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);

        return (bool) $stmt->fetch();
    }

    public function criar(array $dados): int
    {
        $sql = "INSERT INTO usuarios (
                    nome, email, senha, perfil, setor_id, ativo,
                    pode_visualizar_ocorrencias, visualiza_todas_ocorrencias, pode_editar_ocorrencias,
                    criado_em, atualizado_em
                ) VALUES (
                    :nome, :email, :senha, :perfil, :setor_id, :ativo,
                    :pode_visualizar_ocorrencias, :visualiza_todas_ocorrencias, :pode_editar_ocorrencias,
                    NOW(), NOW()
                )";

        $stmt = $this->db->prepare($sql);
        $stmt->bindValue(':nome', $dados['nome']);
        $stmt->bindValue(':email', $dados['email']);
        $stmt->bindValue(':senha', $dados['senha']);
        $stmt->bindValue(':perfil', $dados['perfil']);
        if ($dados['setor_id'] === null) {
            $stmt->bindValue(':setor_id', null, PDO::PARAM_NULL);
        } else {
            $stmt->bindValue(':setor_id', (int) $dados['setor_id'], PDO::PARAM_INT);
        }
        $stmt->bindValue(':ativo', (int) $dados['ativo'], PDO::PARAM_INT);
        $stmt->bindValue(':pode_visualizar_ocorrencias', (int) $dados['pode_visualizar_ocorrencias'], PDO::PARAM_INT);
        $stmt->bindValue(':visualiza_todas_ocorrencias', (int) $dados['visualiza_todas_ocorrencias'], PDO::PARAM_INT);
        $stmt->bindValue(':pode_editar_ocorrencias', (int) $dados['pode_editar_ocorrencias'], PDO::PARAM_INT);
        $stmt->execute();

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

    public function atualizar(int $id, array $dados): void
    {
        $campos = [
            'nome = :nome',
            'email = :email',
            'perfil = :perfil',
            'setor_id = :setor_id',
            'ativo = :ativo',
            'pode_visualizar_ocorrencias = :pode_visualizar_ocorrencias',
            'visualiza_todas_ocorrencias = :visualiza_todas_ocorrencias',
            'pode_editar_ocorrencias = :pode_editar_ocorrencias',
            'atualizado_em = NOW()',
        ];

        if (!empty($dados['senha'])) {
            $campos[] = 'senha = :senha';
        }

        $sql = "UPDATE usuarios SET " . implode(', ', $campos) . " WHERE id = :id";
        $stmt = $this->db->prepare($sql);
        $stmt->bindValue(':id', $id, PDO::PARAM_INT);
        $stmt->bindValue(':nome', $dados['nome']);
        $stmt->bindValue(':email', $dados['email']);
        $stmt->bindValue(':perfil', $dados['perfil']);
        if ($dados['setor_id'] === null) {
            $stmt->bindValue(':setor_id', null, PDO::PARAM_NULL);
        } else {
            $stmt->bindValue(':setor_id', (int) $dados['setor_id'], PDO::PARAM_INT);
        }
        $stmt->bindValue(':ativo', (int) $dados['ativo'], PDO::PARAM_INT);
        $stmt->bindValue(':pode_visualizar_ocorrencias', (int) $dados['pode_visualizar_ocorrencias'], PDO::PARAM_INT);
        $stmt->bindValue(':visualiza_todas_ocorrencias', (int) $dados['visualiza_todas_ocorrencias'], PDO::PARAM_INT);
        $stmt->bindValue(':pode_editar_ocorrencias', (int) $dados['pode_editar_ocorrencias'], PDO::PARAM_INT);
        if (!empty($dados['senha'])) {
            $stmt->bindValue(':senha', $dados['senha']);
        }
        $stmt->execute();
    }

    public function syncServicos(int $usuarioId, array $categoriaIds): void
    {
        $categoriaIds = array_values(array_unique(array_filter(array_map('intval', $categoriaIds), static function ($id) {
            return $id > 0;
        })));

        $this->db->prepare("DELETE FROM usuario_servicos WHERE usuario_id = :usuario_id")
            ->execute(['usuario_id' => $usuarioId]);

        if (empty($categoriaIds)) {
            return;
        }

        $stmt = $this->db->prepare("INSERT INTO usuario_servicos (usuario_id, categoria_id) VALUES (:usuario_id, :categoria_id)");
        foreach ($categoriaIds as $categoriaId) {
            $stmt->execute([
                'usuario_id' => $usuarioId,
                'categoria_id' => $categoriaId,
            ]);
        }
    }

    public function servicosIds(int $usuarioId): array
    {
        $stmt = $this->db->prepare("SELECT categoria_id FROM usuario_servicos WHERE usuario_id = :usuario_id ORDER BY categoria_id ASC");
        $stmt->execute(['usuario_id' => $usuarioId]);
        return array_map('intval', array_column($stmt->fetchAll(), 'categoria_id'));
    }

    public function servicosNomes(int $usuarioId): string
    {
        $stmt = $this->db->prepare("SELECT c.nome
                                    FROM usuario_servicos us
                                    INNER JOIN categorias c ON c.id = us.categoria_id
                                    WHERE us.usuario_id = :usuario_id
                                    ORDER BY c.nome ASC");
        $stmt->execute(['usuario_id' => $usuarioId]);
        return implode(', ', array_column($stmt->fetchAll(), 'nome'));
    }
}
