<?php
declare(strict_types=1);

require_once __DIR__ . '/auth.php';
require_once __DIR__ . '/conexao.php';
require_once __DIR__ . '/telecom_helpers.php';

date_default_timezone_set('America/Sao_Paulo');

if ($mysqli instanceof mysqli) {
    $mysqli->set_charset('utf8mb4');
}

if (session_status() !== PHP_SESSION_ACTIVE) {
    session_start();
}

$usuarioEhCynthia = telecomEhCynthia();

function e(mixed $valor): string
{
    return htmlspecialchars((string) $valor, ENT_QUOTES, 'UTF-8');
}

function dataBr(?string $data): string
{
    if (!$data) {
        return 'Não informado';
    }

    $timestamp = strtotime($data);

    return $timestamp !== false
        ? date('d/m/Y H:i', $timestamp)
        : 'Data inválida';
}

function responderJson(array $dados, int $status = 200): never
{
    http_response_code($status);
    header('Content-Type: application/json; charset=utf-8');

    echo json_encode(
        $dados,
        JSON_UNESCAPED_UNICODE |
        JSON_UNESCAPED_SLASHES |
        JSON_HEX_TAG |
        JSON_HEX_APOS |
        JSON_HEX_QUOT |
        JSON_HEX_AMP
    );

    exit;
}

function definirFlash(string $tipo, string $mensagem): void
{
    $_SESSION['inventario_tonner_flash'] = [
        'tipo' => $tipo,
        'mensagem' => $mensagem
    ];
}

function validarCsrf(string $token): bool
{
    $sessao = (string) ($_SESSION['csrf_inventario_tonner'] ?? '');

    return (
        $token !== '' &&
        $sessao !== '' &&
        hash_equals($sessao, $token)
    );
}

function metricas(mysqli $mysqli, int $inventarioId): array
{
    $stmt = $mysqli->prepare("
        SELECT
            COUNT(*) AS total,
            SUM(CASE WHEN conferido = 1 THEN 1 ELSE 0 END) AS conferidos,
            SUM(
                CASE
                    WHEN conferido = 1
                     AND quantidade_contada = quantidade_sistema
                    THEN 1 ELSE 0
                END
            ) AS corretos,
            SUM(
                CASE
                    WHEN conferido = 1
                     AND quantidade_contada <> quantidade_sistema
                    THEN 1 ELSE 0
                END
            ) AS divergencias,
            SUM(
                CASE
                    WHEN conferido = 1
                     AND quantidade_contada < quantidade_sistema
                    THEN quantidade_sistema - quantidade_contada
                    ELSE 0
                END
            ) AS faltantes,
            SUM(
                CASE
                    WHEN conferido = 1
                     AND quantidade_contada > quantidade_sistema
                    THEN quantidade_contada - quantidade_sistema
                    ELSE 0
                END
            ) AS sobras,
            COALESCE(SUM(quantidade_sistema), 0) AS unidades_sistema,
            COALESCE(
                SUM(
                    CASE
                        WHEN conferido = 1
                        THEN quantidade_contada
                        ELSE 0
                    END
                ),
                0
            ) AS unidades_contadas
        FROM tonner_inventario_itens
        WHERE inventario_id = ?
    ");

    if (!$stmt) {
        return [
            'total' => 0,
            'conferidos' => 0,
            'corretos' => 0,
            'divergencias' => 0,
            'faltantes' => 0,
            'sobras' => 0,
            'unidades_sistema' => 0,
            'unidades_contadas' => 0,
            'percentual' => 0
        ];
    }

    $stmt->bind_param('i', $inventarioId);
    $stmt->execute();

    $r = $stmt->get_result()->fetch_assoc() ?: [];
    $stmt->close();

    $total = (int) ($r['total'] ?? 0);
    $conferidos = (int) ($r['conferidos'] ?? 0);

    return [
        'total' => $total,
        'conferidos' => $conferidos,
        'corretos' => (int) ($r['corretos'] ?? 0),
        'divergencias' => (int) ($r['divergencias'] ?? 0),
        'faltantes' => (int) ($r['faltantes'] ?? 0),
        'sobras' => (int) ($r['sobras'] ?? 0),
        'unidades_sistema' => (int) ($r['unidades_sistema'] ?? 0),
        'unidades_contadas' => (int) ($r['unidades_contadas'] ?? 0),
        'percentual' => $total > 0
            ? (int) round(($conferidos / $total) * 100)
            : 0
    ];
}

function buscarItem(
    mysqli $mysqli,
    int $inventarioId,
    int $itemId
): ?array {
    $stmt = $mysqli->prepare("
        SELECT *
        FROM tonner_inventario_itens
        WHERE id = ?
          AND inventario_id = ?
        LIMIT 1
    ");

    if (!$stmt) {
        return null;
    }

    $stmt->bind_param('ii', $itemId, $inventarioId);
    $stmt->execute();

    $item = $stmt->get_result()->fetch_assoc() ?: null;
    $stmt->close();

    return $item;
}

function itemFormatado(array $item): array
{
    $sistema = (int) ($item['quantidade_sistema'] ?? 0);
    $contada = (int) ($item['quantidade_contada'] ?? 0);
    $conferido = (int) ($item['conferido'] ?? 0) === 1;

    $status = 'pendente';
    $rotulo = 'Não conferido';
    $diferenca = 0;

    if ($conferido) {
        $diferenca = $contada - $sistema;

        if ($diferenca === 0) {
            $status = 'correto';
            $rotulo = 'Quantidade confere';
        } elseif ($diferenca < 0) {
            $status = 'faltando';
            $rotulo = 'Faltando ' . abs($diferenca);
        } else {
            $status = 'sobrando';
            $rotulo = 'Sobrando ' . $diferenca;
        }
    }

    return [
        'id' => (int) ($item['id'] ?? 0),
        'modelo' => (string) ($item['modelo'] ?? ''),
        'codigo_barras' => (string) ($item['codigo_barras'] ?? ''),
        'quantidade_sistema' => $sistema,
        'quantidade_contada' => $contada,
        'conferido' => $conferido,
        'diferenca' => $diferenca,
        'status' => $status,
        'rotulo' => $rotulo,
        'atualizado_em' => (string) ($item['atualizado_em'] ?? '')
    ];
}

/*
|--------------------------------------------------------------------------
| Banco
|--------------------------------------------------------------------------
*/

$mysqli->query("
    CREATE TABLE IF NOT EXISTS tonner_inventarios (
        id INT AUTO_INCREMENT PRIMARY KEY,
        usuario VARCHAR(120) NOT NULL,
        status ENUM('ABERTO','CONCLUIDO','CANCELADO')
            NOT NULL DEFAULT 'ABERTO',
        observacao VARCHAR(500) NULL,
        total_modelos INT NOT NULL DEFAULT 0,
        total_conferidos INT NOT NULL DEFAULT 0,
        total_divergencias INT NOT NULL DEFAULT 0,
        ajustes_aplicados TINYINT(1) NOT NULL DEFAULT 0,
        iniciado_em DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        concluido_em DATETIME NULL,
        INDEX idx_inv_status (status),
        INDEX idx_inv_usuario (usuario),
        INDEX idx_inv_data (iniciado_em)
    ) ENGINE=InnoDB
      DEFAULT CHARSET=utf8mb4
      COLLATE=utf8mb4_unicode_ci
");

$mysqli->query("
    CREATE TABLE IF NOT EXISTS tonner_inventario_itens (
        id INT AUTO_INCREMENT PRIMARY KEY,
        inventario_id INT NOT NULL,
        modelo VARCHAR(100) NOT NULL,
        codigo_barras VARCHAR(120) NULL,
        quantidade_sistema INT NOT NULL DEFAULT 0,
        quantidade_contada INT NULL,
        conferido TINYINT(1) NOT NULL DEFAULT 0,
        atualizado_em DATETIME NULL,
        UNIQUE KEY uq_inv_modelo (inventario_id, modelo),
        INDEX idx_inv_item (inventario_id),
        INDEX idx_inv_codigo (codigo_barras)
    ) ENGINE=InnoDB
      DEFAULT CHARSET=utf8mb4
      COLLATE=utf8mb4_unicode_ci
");

if (empty($_SESSION['csrf_inventario_tonner'])) {
    $_SESSION['csrf_inventario_tonner'] = bin2hex(random_bytes(24));
}

$csrf = (string) $_SESSION['csrf_inventario_tonner'];
$usuario = trim((string) ($_SESSION['usuario'] ?? 'Servidor da TI'));

$flash = $_SESSION['inventario_tonner_flash'] ?? null;
unset($_SESSION['inventario_tonner_flash']);

/*
|--------------------------------------------------------------------------
| AJAX
|--------------------------------------------------------------------------
*/

if (
    $_SERVER['REQUEST_METHOD'] === 'POST' &&
    isset($_POST['ajax'])
) {
    if (!validarCsrf((string) ($_POST['csrf_token'] ?? ''))) {
        responderJson([
            'sucesso' => false,
            'erro' => 'A sessão expirou. Atualize a página.'
        ], 419);
    }

    $acao = trim((string) ($_POST['acao'] ?? ''));
    $inventarioId = max(0, (int) ($_POST['inventario_id'] ?? 0));

    $stmtInv = $mysqli->prepare("
        SELECT status
        FROM tonner_inventarios
        WHERE id = ?
        LIMIT 1
    ");

    if (!$stmtInv) {
        responderJson([
            'sucesso' => false,
            'erro' => 'Não foi possível consultar o inventário.'
        ], 500);
    }

    $stmtInv->bind_param('i', $inventarioId);
    $stmtInv->execute();

    $inv = $stmtInv->get_result()->fetch_assoc();
    $stmtInv->close();

    if (!$inv) {
        responderJson([
            'sucesso' => false,
            'erro' => 'Inventário não encontrado.'
        ], 404);
    }

    if ((string) $inv['status'] !== 'ABERTO') {
        responderJson([
            'sucesso' => false,
            'erro' => 'Este inventário já foi encerrado.'
        ], 409);
    }

    try {
        if ($acao === 'bipar') {
            $codigo = trim((string) ($_POST['codigo'] ?? ''));

            if ($codigo === '') {
                responderJson([
                    'sucesso' => false,
                    'erro' => 'Bipe ou digite um código.'
                ], 422);
            }

            $stmt = $mysqli->prepare("
                SELECT *
                FROM tonner_inventario_itens
                WHERE inventario_id = ?
                  AND codigo_barras = ?
                LIMIT 1
            ");

            if (!$stmt) {
                throw new RuntimeException(
                    'Não foi possível pesquisar o código.'
                );
            }

            $stmt->bind_param('is', $inventarioId, $codigo);
            $stmt->execute();

            $item = $stmt->get_result()->fetch_assoc();
            $stmt->close();

            if (!$item) {
                responderJson([
                    'sucesso' => false,
                    'erro' =>
                        'Código não encontrado. Configure o código no estoque de toner.'
                ], 404);
            }

            $nova = (int) ($item['quantidade_contada'] ?? 0) + 1;
            $itemId = (int) $item['id'];

            $stmt = $mysqli->prepare("
                UPDATE tonner_inventario_itens
                SET
                    quantidade_contada = ?,
                    conferido = 1,
                    atualizado_em = NOW()
                WHERE id = ?
                  AND inventario_id = ?
            ");

            if (!$stmt) {
                throw new RuntimeException(
                    'Não foi possível salvar a leitura.'
                );
            }

            $stmt->bind_param('iii', $nova, $itemId, $inventarioId);
            $stmt->execute();
            $stmt->close();

            $atualizado = buscarItem($mysqli, $inventarioId, $itemId);

            responderJson([
                'sucesso' => true,
                'item' => itemFormatado($atualizado ?: $item),
                'metricas' => metricas($mysqli, $inventarioId)
            ]);
        }

        if ($acao === 'definir') {
            $itemId = max(0, (int) ($_POST['item_id'] ?? 0));
            $quantidade = max(0, (int) ($_POST['quantidade'] ?? 0));

            $stmt = $mysqli->prepare("
                UPDATE tonner_inventario_itens
                SET
                    quantidade_contada = ?,
                    conferido = 1,
                    atualizado_em = NOW()
                WHERE id = ?
                  AND inventario_id = ?
            ");

            if (!$stmt) {
                throw new RuntimeException(
                    'Não foi possível atualizar a quantidade.'
                );
            }

            $stmt->bind_param(
                'iii',
                $quantidade,
                $itemId,
                $inventarioId
            );

            $stmt->execute();
            $stmt->close();

            $item = buscarItem($mysqli, $inventarioId, $itemId);

            responderJson([
                'sucesso' => true,
                'item' => itemFormatado($item ?: []),
                'metricas' => metricas($mysqli, $inventarioId)
            ]);
        }

        if ($acao === 'somar') {
            $itemId = max(0, (int) ($_POST['item_id'] ?? 0));
            $valor = (int) ($_POST['valor'] ?? 0);

            if (!in_array($valor, [-1, 1], true)) {
                responderJson([
                    'sucesso' => false,
                    'erro' => 'Operação inválida.'
                ], 422);
            }

            $item = buscarItem($mysqli, $inventarioId, $itemId);

            if (!$item) {
                responderJson([
                    'sucesso' => false,
                    'erro' => 'Item não encontrado.'
                ], 404);
            }

            $nova = max(
                0,
                (int) ($item['quantidade_contada'] ?? 0) + $valor
            );

            $stmt = $mysqli->prepare("
                UPDATE tonner_inventario_itens
                SET
                    quantidade_contada = ?,
                    conferido = 1,
                    atualizado_em = NOW()
                WHERE id = ?
                  AND inventario_id = ?
            ");

            if (!$stmt) {
                throw new RuntimeException(
                    'Não foi possível atualizar a contagem.'
                );
            }

            $stmt->bind_param('iii', $nova, $itemId, $inventarioId);
            $stmt->execute();
            $stmt->close();

            $atualizado = buscarItem($mysqli, $inventarioId, $itemId);

            responderJson([
                'sucesso' => true,
                'item' => itemFormatado($atualizado ?: $item),
                'metricas' => metricas($mysqli, $inventarioId)
            ]);
        }

        if ($acao === 'limpar') {
            $itemId = max(0, (int) ($_POST['item_id'] ?? 0));

            $stmt = $mysqli->prepare("
                UPDATE tonner_inventario_itens
                SET
                    quantidade_contada = NULL,
                    conferido = 0,
                    atualizado_em = NOW()
                WHERE id = ?
                  AND inventario_id = ?
            ");

            if (!$stmt) {
                throw new RuntimeException(
                    'Não foi possível limpar a conferência.'
                );
            }

            $stmt->bind_param('ii', $itemId, $inventarioId);
            $stmt->execute();
            $stmt->close();

            $item = buscarItem($mysqli, $inventarioId, $itemId);

            responderJson([
                'sucesso' => true,
                'item' => itemFormatado($item ?: []),
                'metricas' => metricas($mysqli, $inventarioId)
            ]);
        }

        responderJson([
            'sucesso' => false,
            'erro' => 'Ação inválida.'
        ], 400);
    } catch (Throwable $erroAjax) {
        responderJson([
            'sucesso' => false,
            'erro' => $erroAjax->getMessage()
        ], 500);
    }
}

/*
|--------------------------------------------------------------------------
| POST comum
|--------------------------------------------------------------------------
*/

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!validarCsrf((string) ($_POST['csrf_token'] ?? ''))) {
        definirFlash(
            'erro',
            'A sessão expirou. Atualize a página e tente novamente.'
        );

        header('Location: inventario_tonner.php');
        exit;
    }

    $acao = trim((string) ($_POST['acao'] ?? ''));

    if ($acao === 'iniciar') {
        try {
            $mysqli->begin_transaction();

            $stmt = $mysqli->prepare("
                INSERT INTO tonner_inventarios (
                    usuario,
                    status
                )
                VALUES (?, 'ABERTO')
            ");

            if (!$stmt) {
                throw new RuntimeException(
                    'Não foi possível iniciar o inventário.'
                );
            }

            $stmt->bind_param('s', $usuario);
            $stmt->execute();

            $novoId = (int) $stmt->insert_id;
            $stmt->close();

            $stmt = $mysqli->prepare("
                INSERT INTO tonner_inventario_itens (
                    inventario_id,
                    modelo,
                    codigo_barras,
                    quantidade_sistema
                )
                SELECT
                    ?,
                    modelo,
                    codigo_barras,
                    quantidade
                FROM tonner_estoque
                ORDER BY modelo
            ");

            if (!$stmt) {
                throw new RuntimeException(
                    'Não foi possível fotografar o estoque atual.'
                );
            }

            $stmt->bind_param('i', $novoId);
            $stmt->execute();

            $total = $stmt->affected_rows;
            $stmt->close();

            if ($total < 1) {
                throw new RuntimeException(
                    'Não existem modelos cadastrados no estoque.'
                );
            }

            $stmt = $mysqli->prepare("
                UPDATE tonner_inventarios
                SET total_modelos = ?
                WHERE id = ?
            ");

            if ($stmt) {
                $stmt->bind_param('ii', $total, $novoId);
                $stmt->execute();
                $stmt->close();
            }

            $mysqli->commit();

            definirFlash(
                'sucesso',
                'Inventário iniciado. O estoque foi fotografado e está pronto para conferência.'
            );

            header(
                'Location: inventario_tonner.php?id=' . $novoId
            );

            exit;
        } catch (Throwable $erro) {
            try {
                $mysqli->rollback();
            } catch (Throwable) {
            }

            definirFlash('erro', $erro->getMessage());

            header('Location: inventario_tonner.php');
            exit;
        }
    }

    if ($acao === 'cancelar') {
        $inventarioId = max(0, (int) ($_POST['inventario_id'] ?? 0));

        $stmt = $mysqli->prepare("
            UPDATE tonner_inventarios
            SET
                status = 'CANCELADO',
                concluido_em = NOW()
            WHERE id = ?
              AND status = 'ABERTO'
        ");

        if ($stmt) {
            $stmt->bind_param('i', $inventarioId);
            $stmt->execute();
            $stmt->close();
        }

        definirFlash(
            'sucesso',
            'Inventário cancelado. O estoque não foi alterado.'
        );

        header('Location: inventario_tonner.php');
        exit;
    }

    if ($acao === 'concluir') {
        $inventarioId = max(0, (int) ($_POST['inventario_id'] ?? 0));
        $observacao = trim((string) ($_POST['observacao'] ?? ''));

        $aplicar =
            isset($_POST['aplicar_ajustes']) &&
            (string) $_POST['aplicar_ajustes'] === '1';

        $m = metricas($mysqli, $inventarioId);

        if ($m['total'] <= 0 || $m['conferidos'] < $m['total']) {
            definirFlash(
                'erro',
                'Confira todos os modelos antes de concluir. Para modelos sem nenhuma unidade física, use “Confirmar zero”.'
            );

            header(
                'Location: inventario_tonner.php?id=' . $inventarioId
            );

            exit;
        }

        try {
            $mysqli->begin_transaction();

            $stmt = $mysqli->prepare("
                SELECT status
                FROM tonner_inventarios
                WHERE id = ?
                LIMIT 1
                FOR UPDATE
            ");

            if (!$stmt) {
                throw new RuntimeException(
                    'Não foi possível bloquear o inventário.'
                );
            }

            $stmt->bind_param('i', $inventarioId);
            $stmt->execute();

            $inv = $stmt->get_result()->fetch_assoc();
            $stmt->close();

            if (!$inv || (string) $inv['status'] !== 'ABERTO') {
                throw new RuntimeException(
                    'Este inventário já foi encerrado.'
                );
            }

            if ($aplicar && $m['divergencias'] > 0) {
                $stmt = $mysqli->prepare("
                    SELECT
                        modelo,
                        quantidade_contada
                    FROM tonner_inventario_itens
                    WHERE inventario_id = ?
                      AND conferido = 1
                      AND quantidade_contada <> quantidade_sistema
                    ORDER BY modelo
                ");

                if (!$stmt) {
                    throw new RuntimeException(
                        'Não foi possível consultar as divergências.'
                    );
                }

                $stmt->bind_param('i', $inventarioId);
                $stmt->execute();

                $divergentes = $stmt
                    ->get_result()
                    ->fetch_all(MYSQLI_ASSOC);

                $stmt->close();

                foreach ($divergentes as $item) {
                    $modelo = (string) $item['modelo'];
                    $contada = max(
                        0,
                        (int) $item['quantidade_contada']
                    );

                    $stmtEstoque = $mysqli->prepare("
                        SELECT quantidade
                        FROM tonner_estoque
                        WHERE modelo = ?
                        LIMIT 1
                        FOR UPDATE
                    ");

                    if (!$stmtEstoque) {
                        throw new RuntimeException(
                            'Falha ao consultar ' . $modelo . '.'
                        );
                    }

                    $stmtEstoque->bind_param('s', $modelo);
                    $stmtEstoque->execute();

                    $estoque = $stmtEstoque
                        ->get_result()
                        ->fetch_assoc();

                    $stmtEstoque->close();

                    if (!$estoque) {
                        throw new RuntimeException(
                            'O modelo ' . $modelo .
                            ' não existe mais no estoque.'
                        );
                    }

                    $anterior = (int) $estoque['quantidade'];
                    $diferenca = $contada - $anterior;

                    if ($diferenca === 0) {
                        continue;
                    }

                    $stmtAtualiza = $mysqli->prepare("
                        UPDATE tonner_estoque
                        SET quantidade = ?
                        WHERE modelo = ?
                    ");

                    if (!$stmtAtualiza) {
                        throw new RuntimeException(
                            'Não foi possível ajustar ' . $modelo . '.'
                        );
                    }

                    $stmtAtualiza->bind_param('is', $contada, $modelo);
                    $stmtAtualiza->execute();
                    $stmtAtualiza->close();

                    $tipo = 'AJUSTE';
                    $quantidadeMovimento = abs($diferenca);

                    $textoAjuste = sprintf(
                        'Ajuste do inventário #%d. Diferença física: %s%d unidade(s).',
                        $inventarioId,
                        $diferenca > 0 ? '+' : '',
                        $diferenca
                    );

                    $stmtMov = $mysqli->prepare("
                        INSERT INTO tonner_movimentacoes (
                            modelo,
                            tipo,
                            quantidade,
                            estoque_anterior,
                            estoque_posterior,
                            responsavel,
                            responsavel_entrega,
                            destino,
                            observacao,
                            usuario_sistema
                        )
                        VALUES (
                            ?,
                            ?,
                            ?,
                            ?,
                            ?,
                            ?,
                            ?,
                            'INVENTÁRIO',
                            ?,
                            ?
                        )
                    ");

                    if (!$stmtMov) {
                        throw new RuntimeException(
                            'Não foi possível registrar o ajuste de ' .
                            $modelo . '.'
                        );
                    }

                    $stmtMov->bind_param(
                        'ssiiissss',
                        $modelo,
                        $tipo,
                        $quantidadeMovimento,
                        $anterior,
                        $contada,
                        $usuario,
                        $usuario,
                        $textoAjuste,
                        $usuario
                    );

                    $stmtMov->execute();
                    $stmtMov->close();
                }
            }

            $ajustes = $aplicar ? 1 : 0;

            $stmt = $mysqli->prepare("
                UPDATE tonner_inventarios
                SET
                    status = 'CONCLUIDO',
                    observacao = NULLIF(?, ''),
                    total_modelos = ?,
                    total_conferidos = ?,
                    total_divergencias = ?,
                    ajustes_aplicados = ?,
                    concluido_em = NOW()
                WHERE id = ?
                  AND status = 'ABERTO'
            ");

            if (!$stmt) {
                throw new RuntimeException(
                    'Não foi possível concluir o inventário.'
                );
            }

            $stmt->bind_param(
                'siiiii',
                $observacao,
                $m['total'],
                $m['conferidos'],
                $m['divergencias'],
                $ajustes,
                $inventarioId
            );

            $stmt->execute();
            $stmt->close();

            $mysqli->commit();

            definirFlash(
                'sucesso',
                $aplicar
                    ? 'Inventário concluído e diferenças aplicadas ao estoque.'
                    : 'Inventário concluído sem alterar o estoque.'
            );

            header(
                'Location: inventario_tonner.php?id=' . $inventarioId
            );

            exit;
        } catch (Throwable $erro) {
            try {
                $mysqli->rollback();
            } catch (Throwable) {
            }

            definirFlash('erro', $erro->getMessage());

            header(
                'Location: inventario_tonner.php?id=' . $inventarioId
            );

            exit;
        }
    }
}

/*
|--------------------------------------------------------------------------
| Carregar inventário
|--------------------------------------------------------------------------
*/

$inventarioId = filter_input(
    INPUT_GET,
    'id',
    FILTER_VALIDATE_INT
) ?: 0;

if ($inventarioId <= 0) {
    $stmt = $mysqli->prepare("
        SELECT id
        FROM tonner_inventarios
        WHERE status = 'ABERTO'
          AND usuario = ?
        ORDER BY iniciado_em DESC, id DESC
        LIMIT 1
    ");

    if ($stmt) {
        $stmt->bind_param('s', $usuario);
        $stmt->execute();

        $aberto = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if ($aberto) {
            $inventarioId = (int) $aberto['id'];
        }
    }
}

$inventario = null;
$itens = [];
$m = [
    'total' => 0,
    'conferidos' => 0,
    'corretos' => 0,
    'divergencias' => 0,
    'faltantes' => 0,
    'sobras' => 0,
    'unidades_sistema' => 0,
    'unidades_contadas' => 0,
    'percentual' => 0
];

if ($inventarioId > 0) {
    $stmt = $mysqli->prepare("
        SELECT *
        FROM tonner_inventarios
        WHERE id = ?
        LIMIT 1
    ");

    if ($stmt) {
        $stmt->bind_param('i', $inventarioId);
        $stmt->execute();

        $inventario = $stmt->get_result()->fetch_assoc() ?: null;
        $stmt->close();
    }

    if ($inventario) {
        $stmt = $mysqli->prepare("
            SELECT *
            FROM tonner_inventario_itens
            WHERE inventario_id = ?
            ORDER BY
                conferido ASC,
                modelo ASC
        ");

        if ($stmt) {
            $stmt->bind_param('i', $inventarioId);
            $stmt->execute();

            $itens = $stmt
                ->get_result()
                ->fetch_all(MYSQLI_ASSOC);

            $stmt->close();
        }

        $m = metricas($mysqli, $inventarioId);
    }
}

$historico = [];

$resultado = $mysqli->query("
    SELECT
        id,
        usuario,
        status,
        total_modelos,
        total_conferidos,
        total_divergencias,
        ajustes_aplicados,
        iniciado_em,
        concluido_em
    FROM tonner_inventarios
    ORDER BY iniciado_em DESC, id DESC
    LIMIT 10
");

if ($resultado) {
    $historico = $resultado->fetch_all(MYSQLI_ASSOC);
    $resultado->free();
}

$aberto = (
    is_array($inventario) &&
    (string) ($inventario['status'] ?? '') === 'ABERTO'
);

$concluido = (
    is_array($inventario) &&
    (string) ($inventario['status'] ?? '') === 'CONCLUIDO'
);

$itensJson = json_encode(
    array_map(
        static fn(array $item): array => itemFormatado($item),
        $itens
    ),
    JSON_UNESCAPED_UNICODE |
    JSON_UNESCAPED_SLASHES |
    JSON_HEX_TAG |
    JSON_HEX_APOS |
    JSON_HEX_QUOT |
    JSON_HEX_AMP
);

$hora = (int) date('H');

$saudacao = match (true) {
    $hora >= 5 && $hora < 12 => 'Bom dia',
    $hora >= 12 && $hora < 18 => 'Boa tarde',
    default => 'Boa noite'
};
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<meta name="theme-color" content="#08396f">
<title>Inventário de Toner | Manutenção TI</title>

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">

<style>
:root{
    --primary:#08396f;
    --primary-dark:#05294f;
    --primary-light:#145b9f;
    --green:#087f5b;
    --green-soft:#e8f8f1;
    --yellow:#c97900;
    --yellow-soft:#fff7e6;
    --red:#bd263d;
    --red-soft:#fff0f3;
    --purple:#654bb7;
    --purple-soft:#f1edfb;
    --bg:#edf3f8;
    --surface:#fff;
    --soft:#f6f9fc;
    --text:#152236;
    --muted:#617086;
    --light:#8795a8;
    --border:#dce5ee;
    --border-soft:#e9eff5;
    --shadow-sm:0 10px 28px rgba(8,57,111,.06);
    --shadow-md:0 22px 58px rgba(8,57,111,.11);
    --shadow-lg:0 38px 95px rgba(5,41,79,.2);
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
    min-height:100vh;margin:0;overflow-x:hidden;
    font-family:"Inter",system-ui,sans-serif;color:var(--text);
    background:
        radial-gradient(circle at 5% 4%,rgba(20,91,159,.14),transparent 30rem),
        radial-gradient(circle at 96% 91%,rgba(8,127,91,.1),transparent 31rem),
        linear-gradient(145deg,#f8fbfd,var(--bg) 55%,#e7eff6);
}
a{text-decoration:none}
button,input,textarea,select{font:inherit}
.top-strip{
    position:fixed;inset:0 0 auto;z-index:1200;height:6px;
    background:linear-gradient(90deg,var(--primary) 0 58%,var(--green) 58% 88%,#e8ad16 88%)
}
.grid-bg{
    position:fixed;inset:0;pointer-events:none;z-index:0;
    background-image:
        linear-gradient(rgba(8,57,111,.026) 1px,transparent 1px),
        linear-gradient(90deg,rgba(8,57,111,.026) 1px,transparent 1px);
    background-size:55px 55px
}
.app{position:relative;z-index:2;padding-top:6px}
.header{
    position:relative;overflow:hidden;margin:18px 18px 0;padding:21px 23px;
    border:1px solid rgba(255,255,255,.17);border-radius:29px;color:#fff;
    background:
        radial-gradient(circle at 82% 0,rgba(255,255,255,.13),transparent 23rem),
        radial-gradient(circle at 0 100%,rgba(8,127,91,.26),transparent 25rem),
        linear-gradient(135deg,var(--primary-dark),var(--primary) 56%,#07547c);
    box-shadow:var(--shadow-lg),inset 0 1px 0 rgba(255,255,255,.12)
}
.header::before{
    content:"";position:absolute;top:-210px;right:-100px;width:430px;height:430px;
    border:42px solid rgba(255,255,255,.035);border-radius:50%;
    box-shadow:0 0 0 43px rgba(255,255,255,.018),0 0 0 86px rgba(255,255,255,.012);
    animation:orbit 31s linear infinite
}
@keyframes orbit{to{transform:rotate(360deg)}}
.header-inner{position:relative;z-index:2;display:flex;align-items:center;justify-content:space-between;gap:24px}
.brand{display:flex;align-items:center;gap:15px;min-width:0}
.logo{
    width:72px;height:72px;flex:0 0 72px;display:grid;place-items:center;padding:5px;
    border-radius:22px;background:linear-gradient(145deg,#fff,#dceaf5);
    box-shadow:0 19px 37px rgba(0,0,0,.18);animation:float 6s ease-in-out infinite
}
.logo img{max-width:58px;max-height:58px;object-fit:contain}
@keyframes float{50%{transform:translateY(-5px) rotateY(4deg)}}
.gov{
    display:inline-flex;align-items:center;gap:7px;margin-bottom:7px;padding:6px 10px;
    border:1px solid rgba(255,255,255,.15);border-radius:999px;
    color:rgba(255,255,255,.84);background:rgba(255,255,255,.08);
    font-size:9px;font-weight:850;letter-spacing:.65px;text-transform:uppercase
}
.gov i{color:#9cebd2}
.header h1{margin:0;font-size:clamp(23px,2.5vw,35px);line-height:1.04;letter-spacing:-1px;font-weight:900}
.header p{margin:7px 0 0;color:rgba(255,255,255,.68);font-size:11px;line-height:1.55}
.header-side{min-width:405px;display:flex;flex-direction:column;align-items:flex-end;gap:11px}
.user{display:flex;align-items:center;gap:10px;text-align:right}
.user strong{display:block;font-size:11px;font-weight:850}
.user span{display:block;margin-top:3px;color:rgba(255,255,255,.62);font-size:8px}
.avatar{width:42px;height:42px;display:grid;place-items:center;border-radius:14px;color:var(--primary);background:#fff;font-size:18px}
.header-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:7px}
.header-button{
    min-height:41px;display:inline-flex;align-items:center;justify-content:center;gap:7px;padding:0 13px;
    border:1px solid rgba(255,255,255,.16);border-radius:13px;color:#fff;background:rgba(255,255,255,.08);
    font-size:9px;font-weight:850;text-transform:uppercase;transition:.18s ease
}
.header-button:hover{color:#fff;background:rgba(255,255,255,.16);transform:translateY(-2px)}
.header-button.primary{color:var(--primary-dark);border-color:#fff;background:#fff}
.main{width:100%;max-width:1720px;margin:0 auto;padding:16px 18px 35px}
.flash{
    display:flex;align-items:center;gap:11px;margin-bottom:14px;padding:14px 16px;
    border:1px solid var(--border);border-radius:18px;background:#fff;box-shadow:var(--shadow-sm);
    font-size:10px;line-height:1.5;font-weight:700
}
.flash.sucesso{color:#076448;border-color:#c3e9dc;background:var(--green-soft)}
.flash.erro{color:#922138;border-color:#edc7cf;background:var(--red-soft)}
.flash-icon{width:38px;height:38px;display:grid;place-items:center;border-radius:13px;color:#fff;background:var(--primary);font-size:17px}
.flash.sucesso .flash-icon{background:var(--green)}
.flash.erro .flash-icon{background:var(--red)}
.start{
    min-height:470px;display:grid;grid-template-columns:minmax(0,1.25fr) minmax(330px,.75fr);
    align-items:center;gap:25px;padding:35px;border:1px solid rgba(255,255,255,.9);border-radius:32px;
    background:radial-gradient(circle at 92% 0,rgba(20,91,159,.1),transparent 25rem),rgba(255,255,255,.9);
    box-shadow:var(--shadow-md),inset 0 1px 0 #fff
}
.eyebrow{display:inline-flex;align-items:center;gap:7px;margin-bottom:12px;color:var(--primary);font-size:9px;font-weight:900;letter-spacing:.65px;text-transform:uppercase}
.start h2,.hero h2{margin:0;font-size:clamp(31px,4vw,54px);line-height:1.02;letter-spacing:-2px;font-weight:900}
.start h2 span,.hero h2 span{color:var(--primary)}
.start-text,.hero-text{max-width:820px;margin:16px 0 0;color:var(--muted);font-size:12px;line-height:1.7}
.steps{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:22px}
.step{padding:15px;border:1px solid var(--border);border-radius:18px;background:var(--soft)}
.step i{color:var(--primary);font-size:24px}
.step strong{display:block;margin-top:10px;font-size:11px;font-weight:900}
.step span{display:block;margin-top:5px;color:var(--muted);font-size:9px;line-height:1.5}
.start-card{
    min-height:350px;display:flex;flex-direction:column;justify-content:space-between;padding:25px;border-radius:27px;
    color:#fff;background:radial-gradient(circle at 88% 8%,rgba(255,255,255,.14),transparent 14rem),
    linear-gradient(145deg,var(--primary-dark),var(--primary));box-shadow:0 28px 60px rgba(8,57,111,.24);
    animation:float 6s ease-in-out infinite
}
.start-card i.main-icon{font-size:30px}
.start-card h3{margin:22px 0 0;font-size:21px;font-weight:900}
.start-card p{margin:8px 0 0;color:rgba(255,255,255,.66);font-size:10px;line-height:1.6}
.start-btn{
    width:100%;min-height:58px;display:flex;align-items:center;justify-content:center;gap:9px;border:0;border-radius:17px;
    color:var(--primary-dark);background:#fff;box-shadow:0 16px 32px rgba(0,0,0,.18);
    font-size:11px;font-weight:900;text-transform:uppercase
}
.hero{
    display:grid;grid-template-columns:minmax(0,1.25fr) minmax(330px,.75fr);gap:15px;padding:23px;
    border:1px solid rgba(255,255,255,.9);border-radius:30px;
    background:radial-gradient(circle at 90% 0,rgba(20,91,159,.08),transparent 22rem),rgba(255,255,255,.88);
    box-shadow:var(--shadow-md),inset 0 1px 0 #fff;transform-style:preserve-3d;transition:.2s ease
}
.hero h2{font-size:clamp(27px,3.2vw,45px);letter-spacing:-1.7px}
.tags{display:flex;flex-wrap:wrap;gap:7px;margin-top:16px}
.tag{display:inline-flex;align-items:center;gap:6px;padding:8px 10px;border:1px solid var(--border);border-radius:999px;color:#526176;background:#fff;box-shadow:var(--shadow-sm);font-size:8px;font-weight:800}
.progress-card{
    min-height:230px;display:flex;flex-direction:column;justify-content:space-between;padding:20px;border-radius:25px;
    color:#fff;background:radial-gradient(circle at 90% 10%,rgba(255,255,255,.13),transparent 12rem),
    linear-gradient(145deg,var(--primary-dark),var(--primary));box-shadow:0 24px 50px rgba(8,57,111,.22)
}
.progress-number{display:flex;align-items:flex-end;gap:4px;margin-top:17px}
.progress-number strong{font-size:55px;line-height:.9;letter-spacing:-2px;font-weight:900}
.progress-number span{color:rgba(255,255,255,.62);font-size:14px;font-weight:750}
.progress-track{height:9px;overflow:hidden;margin-top:16px;border-radius:999px;background:rgba(255,255,255,.13)}
.progress-track span{display:block;height:100%;border-radius:inherit;background:linear-gradient(90deg,#91ebcf,#fff);transition:.3s ease}
.kpis{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:11px;margin-top:14px}
.kpi{
    min-height:124px;padding:15px;border:1px solid var(--border);border-radius:21px;background:rgba(255,255,255,.92);
    box-shadow:var(--shadow-sm),inset 0 1px 0 #fff;transition:.2s ease
}
.kpi:hover{transform:translateY(-4px);box-shadow:var(--shadow-md)}
.kpi-top{display:flex;align-items:center;justify-content:space-between;gap:9px}
.kpi-icon{width:40px;height:40px;display:grid;place-items:center;border-radius:13px;color:var(--primary);background:#eaf4fc;font-size:17px}
.kpi.green .kpi-icon{color:var(--green);background:var(--green-soft)}
.kpi.red .kpi-icon{color:var(--red);background:var(--red-soft)}
.kpi.yellow .kpi-icon{color:var(--yellow);background:var(--yellow-soft)}
.kpi.purple .kpi-icon{color:var(--purple);background:var(--purple-soft)}
.kpi-value{font-size:31px;line-height:1;letter-spacing:-1px;font-weight:900}
.kpi-label{display:block;margin-top:13px;color:var(--muted);font-size:8px;font-weight:900;letter-spacing:.5px;text-transform:uppercase}
.kpi-note{display:block;margin-top:4px;color:var(--light);font-size:7px;line-height:1.4}
.completed{
    display:flex;align-items:flex-start;gap:13px;margin-top:14px;padding:18px;border:1px solid #c3e9dc;
    border-radius:23px;color:#076448;background:var(--green-soft);box-shadow:var(--shadow-sm)
}
.completed-icon{width:48px;height:48px;display:grid;place-items:center;border-radius:15px;color:#fff;background:var(--green);font-size:21px}
.completed strong{display:block;font-size:13px;font-weight:900}
.completed span{display:block;margin-top:5px;font-size:9px;line-height:1.55}
.scanner{
    position:sticky;top:10px;z-index:50;display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px;
    margin-top:14px;padding:15px;border:1px solid rgba(255,255,255,.92);border-radius:23px;
    background:rgba(255,255,255,.92);backdrop-filter:blur(18px);box-shadow:var(--shadow-md),inset 0 1px 0 #fff
}
.scanner-box{position:relative}
.scanner-box>i{position:absolute;top:50%;left:18px;color:var(--primary);font-size:22px;transform:translateY(-50%)}
.scanner-input{
    width:100%;height:63px;border:2px solid #cbdbe7;border-radius:19px;outline:0;color:var(--text);
    background:#fff;padding:0 145px 0 54px;box-shadow:var(--shadow-sm);font-size:15px;font-weight:800
}
.scanner-input:focus{border-color:var(--primary-light);box-shadow:0 0 0 5px rgba(20,91,159,.1),var(--shadow-sm)}
.ready{
    position:absolute;top:50%;right:12px;display:inline-flex;align-items:center;gap:7px;padding:8px 10px;
    border-radius:999px;color:#086247;background:var(--green-soft);font-size:8px;font-weight:900;text-transform:uppercase;
    transform:translateY(-50%)
}
.dot{width:8px;height:8px;border-radius:50%;background:var(--green);animation:pulse 1.45s ease-in-out infinite}
@keyframes pulse{50%{box-shadow:0 0 0 8px rgba(8,127,91,0)}0%,100%{box-shadow:0 0 0 0 rgba(8,127,91,.22)}}
.focus-btn{
    min-width:190px;min-height:63px;display:inline-flex;align-items:center;justify-content:center;gap:8px;border:0;
    border-radius:18px;color:#fff;background:linear-gradient(145deg,var(--primary-dark),var(--primary));
    box-shadow:0 16px 32px rgba(8,57,111,.22);font-size:10px;font-weight:900;text-transform:uppercase
}
.feedback{display:none;grid-column:1/-1;padding:12px 14px;border:1px solid var(--border);border-radius:15px;font-size:10px;line-height:1.5;font-weight:750}
.feedback.visible{display:block}
.feedback.success{color:#076448;border-color:#c3e9dc;background:var(--green-soft)}
.feedback.error{color:#922138;border-color:#edc7cf;background:var(--red-soft)}
.panel{
    overflow:hidden;margin-top:14px;border:1px solid rgba(255,255,255,.92);border-radius:29px;
    background:rgba(255,255,255,.92);box-shadow:var(--shadow-md),inset 0 1px 0 #fff
}
.toolbar{display:grid;grid-template-columns:minmax(220px,1fr) auto auto;gap:10px;padding:16px;border-bottom:1px solid var(--border-soft);background:#fbfdfe}
.search-box{position:relative}.search-box i{position:absolute;top:50%;left:15px;color:var(--primary);font-size:16px;transform:translateY(-50%)}
.search,.filter{height:49px;border:1px solid var(--border);border-radius:15px;outline:0;color:var(--text);background:var(--soft);font-size:10px;font-weight:700}
.search{width:100%;padding:0 14px 0 42px}.filter{min-width:180px;padding:0 12px}
.pending-btn{min-width:160px;min-height:49px;display:inline-flex;align-items:center;justify-content:center;gap:7px;border:1px solid var(--border);border-radius:15px;color:var(--primary);background:#fff;font-size:9px;font-weight:900;text-transform:uppercase}
.items{display:grid;grid-template-columns:repeat(auto-fill,minmax(335px,1fr));gap:12px;padding:16px}
.item{
    position:relative;overflow:hidden;min-height:285px;border:1px solid var(--border);border-radius:22px;background:#fff;
    box-shadow:var(--shadow-sm);transition:.2s ease
}
.item:hover{transform:translateY(-4px);box-shadow:var(--shadow-md)}
.item::before{content:"";position:absolute;top:0;bottom:0;left:0;width:6px;background:#aab8c7}
.item.correto::before{background:var(--green)}
.item.faltando::before{background:var(--red)}
.item.sobrando::before{background:var(--yellow)}
.item.flash{animation:highlight 1.1s ease}
@keyframes highlight{50%{box-shadow:0 0 0 10px rgba(20,91,159,0),var(--shadow-md)}}
.item-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:16px 16px 12px 19px;border-bottom:1px solid var(--border-soft);background:var(--soft)}
.item-title{margin:0;font-size:15px;line-height:1.35;font-weight:900}
.item-code{display:block;margin-top:5px;color:var(--light);font-size:8px;font-weight:700}
.status{
    display:inline-flex;align-items:center;gap:6px;padding:7px 9px;border:1px solid #d3dde6;border-radius:999px;
    color:#66768a;background:#fff;font-size:8px;font-weight:900;white-space:nowrap
}
.status.correto{color:#076448;border-color:#c3e9dc;background:var(--green-soft)}
.status.faltando{color:#922138;border-color:#edc7cf;background:var(--red-soft)}
.status.sobrando{color:#916000;border-color:#edd9aa;background:var(--yellow-soft)}
.item-body{padding:15px 16px 17px 19px}
.compare{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:10px}
.qty-box{min-height:92px;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:11px;border:1px solid var(--border);border-radius:17px;text-align:center;background:var(--soft)}
.qty-box.physical{border-color:#c8dce9;background:#edf7fc}
.qty-box span{color:var(--light);font-size:7px;font-weight:900;letter-spacing:.5px;text-transform:uppercase}
.qty-box strong{display:block;margin-top:5px;color:var(--primary);font-size:38px;line-height:1;letter-spacing:-1.5px;font-weight:900}
.compare-icon{width:36px;height:36px;display:grid;place-items:center;border-radius:12px;color:var(--primary);background:#eaf4fc;font-size:16px}
.controls{display:grid;grid-template-columns:48px minmax(80px,1fr) 48px;gap:8px;margin-top:12px}
.qty-btn{min-height:48px;display:grid;place-items:center;border:1px solid var(--border);border-radius:14px;color:var(--primary);background:#fff;font-size:21px;font-weight:900}
.qty-input{width:100%;min-height:48px;border:2px solid #c8d9e6;border-radius:14px;outline:0;text-align:center;color:var(--text);background:#fff;font-size:18px;font-weight:900}
.item-actions{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px}
.item-btn{min-height:43px;display:inline-flex;align-items:center;justify-content:center;gap:7px;border:1px solid var(--border);border-radius:13px;color:var(--muted);background:#fff;font-size:8px;font-weight:900;text-transform:uppercase}
.item-btn.zero{color:var(--red);border-color:#edc7cf;background:var(--red-soft)}
.updated{display:block;margin-top:10px;text-align:center;color:var(--light);font-size:7px}
.empty{grid-column:1/-1;display:none;padding:55px 20px;text-align:center;color:var(--muted)}
.finish-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(310px,.55fr);gap:14px;margin-top:14px}
.card{overflow:hidden;border:1px solid rgba(255,255,255,.92);border-radius:27px;background:rgba(255,255,255,.92);box-shadow:var(--shadow-md),inset 0 1px 0 #fff}
.card-head{display:flex;align-items:center;gap:11px;padding:17px 18px;border-bottom:1px solid var(--border-soft);background:#fbfdfe}
.card-icon{width:43px;height:43px;display:grid;place-items:center;border-radius:14px;color:#fff;background:linear-gradient(145deg,#066748,var(--green));font-size:18px}
.card-head h3{margin:0;font-size:15px;font-weight:900}.card-head p{margin:4px 0 0;color:var(--muted);font-size:8px}
.card-body{padding:18px}
.form-label{display:block;margin-bottom:7px;color:#526176;font-size:8px;font-weight:900;letter-spacing:.45px;text-transform:uppercase}
.form-control{min-height:49px;border:1px solid var(--border);border-radius:15px;color:var(--text);background:var(--soft);box-shadow:none;font-size:10px;font-weight:650}
textarea.form-control{min-height:96px;padding:12px;resize:vertical}
.adjust{display:flex;align-items:flex-start;gap:11px;margin-top:12px;padding:13px;border:1px solid #edd9aa;border-radius:16px;color:#805400;background:var(--yellow-soft);cursor:pointer}
.adjust input{width:19px;height:19px;flex:0 0 19px;margin-top:1px;accent-color:var(--yellow)}
.adjust strong{display:block;font-size:9px;font-weight:900}
.adjust span span{display:block;margin-top:4px;font-size:8px;line-height:1.5}
.finish-actions{display:flex;flex-wrap:wrap;justify-content:space-between;gap:9px;margin-top:14px}
.finish-btn{min-height:49px;display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:0 15px;border:1px solid var(--border);border-radius:15px;color:var(--muted);background:#fff;font-size:9px;font-weight:900;text-transform:uppercase}
.finish-btn.primary{flex:1;color:#fff;border-color:var(--green);background:linear-gradient(145deg,#066748,var(--green));box-shadow:0 16px 31px rgba(8,127,91,.21)}
.finish-btn.danger{color:var(--red);border-color:#edc7cf;background:var(--red-soft)}
.finish-btn:disabled{opacity:.5;cursor:not-allowed}
.history{display:flex;flex-direction:column;gap:8px;padding:13px}
.history-item{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:9px;padding:11px;border:1px solid var(--border-soft);border-radius:15px;background:var(--soft)}
.history-icon{width:38px;height:38px;display:grid;place-items:center;border-radius:12px;color:var(--primary);background:#eaf4fc;font-size:15px}
.history-item strong{display:block;font-size:9px;font-weight:900}
.history-item span{display:block;margin-top:3px;color:var(--light);font-size:7px;line-height:1.4}
.badge-status{padding:6px 8px;border-radius:999px;color:var(--primary);background:#eaf4fc;font-size:7px;font-weight:900;white-space:nowrap}
.badge-status.CONCLUIDO{color:#076448;background:var(--green-soft)}
.badge-status.CANCELADO{color:#922138;background:var(--red-soft)}
@media(max-width:1300px){.kpis{grid-template-columns:repeat(3,1fr)}}
@media(max-width:1050px){
    .header{margin:12px 10px 0}.header-inner{align-items:flex-start;flex-direction:column}.header-side{width:100%;min-width:0;align-items:flex-start}.user{text-align:left}
    .main{padding:14px 10px 30px}.start,.hero,.finish-grid{grid-template-columns:1fr}
}
@media(max-width:760px){
    .header-actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));width:100%}.header-button{width:100%}
    .steps{grid-template-columns:1fr}.kpis{grid-template-columns:repeat(2,1fr)}.scanner{position:static;grid-template-columns:1fr}.focus-btn{width:100%}
    .toolbar{grid-template-columns:1fr}.filter,.pending-btn{width:100%;min-width:0}.items{grid-template-columns:1fr}
}
@media(max-width:530px){
    .header{margin-left:7px;margin-right:7px;padding:15px;border-radius:21px}.main{padding-left:7px;padding-right:7px}.brand{align-items:flex-start;gap:10px}
    .logo{width:61px;height:61px;flex-basis:61px}.gov{font-size:7px}.header h1{font-size:22px}.start{min-height:0;padding:19px;border-radius:24px}
    .start h2{font-size:33px}.hero{padding:18px;border-radius:24px}.hero h2{font-size:29px}.kpis{grid-template-columns:1fr}
    .scanner-input{height:59px;padding-right:16px}.ready{display:none}.items{padding:10px}.item-head{flex-direction:column}
    .compare{grid-template-columns:1fr}.compare-icon{margin:auto;transform:rotate(90deg)}.finish-actions{display:grid}.finish-btn{width:100%}
}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}}
</style>
</head>

<body>
<div class="top-strip"></div>
<div class="grid-bg"></div>

<div class="app">

<header class="header">
    <div class="header-inner">

        <div class="brand">
            <div class="logo">
                <img
                    src="assets/logo_pref.jpg"
                    alt="Prefeitura de Extrema"
                    onerror="this.style.display='none';this.parentElement.innerHTML='<i class=&quot;bi bi-buildings-fill text-primary fs-2&quot;></i>'"
                >
            </div>

            <div>
                <div class="gov">
                    <i class="bi bi-shield-check"></i>
                    Prefeitura de Extrema • Gerência de Tecnologia
                </div>

                <h1>INVENTÁRIO INTELIGENTE DE TONER</h1>

                <p>
                    Conferência física por bipador, comparação imediata
                    e histórico completo.
                </p>
            </div>
        </div>

        <div class="header-side">
            <div class="user">
                <div>
                    <strong><?= e($saudacao) ?>, <?= e($usuario) ?></strong>
                    <span id="clock">Carregando data e horário...</span>
                </div>

                <div class="avatar">
                    <i class="bi bi-person-fill"></i>
                </div>
            </div>

            <nav class="header-actions">
                <a href="tonner.php" class="header-button primary">
                    <i class="bi bi-arrow-left-circle-fill"></i>
                    Estoque de toner
                </a>

                <?php if ($aberto): ?>
                    <button
                        type="button"
                        class="header-button"
                        id="headerScanner"
                    >
                        <i class="bi bi-upc-scan"></i>
                        Ativar bipador
                    </button>
                <?php endif; ?>

                <?php if ($usuarioEhCynthia): ?>
                    <a
                        href="dashboard_cynthia.php"
                        class="header-button"
                    >
                        <i class="bi bi-grid-1x2-fill"></i>
                        Meu painel
                    </a>
                <?php else: ?>
                    <a href="dashboard.php" class="header-button">
                        <i class="bi bi-grid-1x2-fill"></i>
                        Dashboard
                    </a>
                <?php endif; ?>
            </nav>
        </div>

    </div>
</header>

<main class="main">

<?php if (is_array($flash)): ?>
    <div class="flash <?= e((string) ($flash['tipo'] ?? '')) ?>">
        <div class="flash-icon">
            <i class="bi <?= ($flash['tipo'] ?? '') === 'sucesso'
                ? 'bi-check-circle-fill'
                : 'bi-exclamation-triangle-fill' ?>"></i>
        </div>

        <span><?= e((string) ($flash['mensagem'] ?? '')) ?></span>
    </div>
<?php endif; ?>

<?php if (!$inventario): ?>

    <section class="start">
        <div>
            <div class="eyebrow">
                <i class="bi bi-clipboard2-check-fill"></i>
                Conferência física guiada
            </div>

            <h2>
                Conte os toners com
                <span>segurança e tranquilidade.</span>
            </h2>

            <p class="start-text">
                O sistema registra uma fotografia das quantidades atuais.
                Depois, basta bipar cada unidade física. A tela informa
                imediatamente se bateu, se está faltando ou se existe sobra.
            </p>

            <div class="steps">
                <article class="step">
                    <i class="bi bi-1-circle-fill"></i>
                    <strong>Inicie</strong>
                    <span>Todos os modelos entram no inventário automaticamente.</span>
                </article>

                <article class="step">
                    <i class="bi bi-upc-scan"></i>
                    <strong>Bipe as caixas</strong>
                    <span>Cada leitura soma uma unidade no modelo correspondente.</span>
                </article>

                <article class="step">
                    <i class="bi bi-check2-all"></i>
                    <strong>Revise e conclua</strong>
                    <span>Confira as diferenças antes de aplicar qualquer ajuste.</span>
                </article>
            </div>
        </div>

        <aside class="start-card">
            <div>
                <i class="bi bi-boxes main-icon"></i>
                <h3>Novo inventário</h3>
                <p>
                    Pode ser realizado sempre que necessário.
                    Nada será alterado sem confirmação.
                </p>
            </div>

            <form method="POST">
                <input type="hidden" name="csrf_token" value="<?= e($csrf) ?>">
                <input type="hidden" name="acao" value="iniciar">

                <button class="start-btn" type="submit">
                    <i class="bi bi-play-circle-fill"></i>
                    Iniciar inventário agora
                </button>
            </form>
        </aside>
    </section>

<?php else: ?>

    <section class="hero" id="hero">
        <div>
            <div class="eyebrow">
                <i class="bi bi-clipboard-data-fill"></i>
                Inventário #<?= (int) $inventario['id'] ?>
                • <?= e((string) $inventario['status']) ?>
            </div>

            <h2>
                Conferência do
                <span>estoque físico de toner.</span>
            </h2>

            <p class="hero-text">
                Bipe cada caixa encontrada. Cada leitura acrescenta uma
                unidade. Quando não existir nenhuma unidade física de um
                modelo, use o botão <strong>Confirmar zero</strong>.
            </p>

            <div class="tags">
                <span class="tag">
                    <i class="bi bi-person-badge-fill"></i>
                    <?= e((string) $inventario['usuario']) ?>
                </span>

                <span class="tag">
                    <i class="bi bi-calendar-event-fill"></i>
                    <?= e(dataBr($inventario['iniciado_em'] ?? null)) ?>
                </span>

                <span class="tag">
                    <i class="bi bi-stack"></i>
                    <?= $m['unidades_sistema'] ?> unidades no sistema
                </span>

                <span class="tag">
                    <i class="bi bi-box-seam-fill"></i>
                    <?= $m['total'] ?> modelos
                </span>
            </div>
        </div>

        <aside class="progress-card">
            <div>
                <div class="eyebrow" style="color:#9cebd2;">
                    <i class="bi bi-speedometer2"></i>
                    Progresso da conferência
                </div>

                <div class="progress-number">
                    <strong id="progressNumber"><?= $m['percentual'] ?></strong>
                    <span>%</span>
                </div>

                <p id="progressDescription">
                    <?= $m['conferidos'] ?> de <?= $m['total'] ?>
                    modelos conferidos.
                </p>
            </div>

            <div class="progress-track">
                <span
                    id="progressBar"
                    style="width:<?= $m['percentual'] ?>%;"
                ></span>
            </div>
        </aside>
    </section>

    <?php if ($concluido): ?>
        <div class="completed">
            <div class="completed-icon">
                <i class="bi bi-check2-all"></i>
            </div>

            <div>
                <strong>
                    Inventário concluído em
                    <?= e(dataBr($inventario['concluido_em'] ?? null)) ?>
                </strong>

                <span>
                    <?= $m['total'] ?> modelos conferidos,
                    <?= $m['divergencias'] ?> divergência(s).
                    <?= (int) ($inventario['ajustes_aplicados'] ?? 0) === 1
                        ? 'As diferenças foram aplicadas ao estoque.'
                        : 'O estoque não foi alterado.' ?>
                </span>
            </div>
        </div>
    <?php endif; ?>

    <section class="kpis">
        <article class="kpi">
            <div class="kpi-top">
                <div class="kpi-icon"><i class="bi bi-box-seam-fill"></i></div>
                <strong class="kpi-value" id="mTotal"><?= $m['total'] ?></strong>
            </div>
            <span class="kpi-label">Modelos</span>
            <span class="kpi-note">Fotografia inicial do estoque.</span>
        </article>

        <article class="kpi purple">
            <div class="kpi-top">
                <div class="kpi-icon"><i class="bi bi-clipboard-check-fill"></i></div>
                <strong class="kpi-value" id="mChecked"><?= $m['conferidos'] ?></strong>
            </div>
            <span class="kpi-label">Conferidos</span>
            <span class="kpi-note">Modelos já contados.</span>
        </article>

        <article class="kpi green">
            <div class="kpi-top">
                <div class="kpi-icon"><i class="bi bi-check-circle-fill"></i></div>
                <strong class="kpi-value" id="mCorrect"><?= $m['corretos'] ?></strong>
            </div>
            <span class="kpi-label">Corretos</span>
            <span class="kpi-note">Físico igual ao sistema.</span>
        </article>

        <article class="kpi red">
            <div class="kpi-top">
                <div class="kpi-icon"><i class="bi bi-exclamation-octagon-fill"></i></div>
                <strong class="kpi-value" id="mDiff"><?= $m['divergencias'] ?></strong>
            </div>
            <span class="kpi-label">Divergências</span>
            <span class="kpi-note">Modelos com falta ou sobra.</span>
        </article>

        <article class="kpi red">
            <div class="kpi-top">
                <div class="kpi-icon"><i class="bi bi-dash-circle-fill"></i></div>
                <strong class="kpi-value" id="mMissing"><?= $m['faltantes'] ?></strong>
            </div>
            <span class="kpi-label">Faltando</span>
            <span class="kpi-note">Unidades abaixo do sistema.</span>
        </article>

        <article class="kpi yellow">
            <div class="kpi-top">
                <div class="kpi-icon"><i class="bi bi-plus-circle-fill"></i></div>
                <strong class="kpi-value" id="mExtra"><?= $m['sobras'] ?></strong>
            </div>
            <span class="kpi-label">Sobrando</span>
            <span class="kpi-note">Unidades acima do sistema.</span>
        </article>
    </section>

    <?php if ($aberto): ?>
        <section class="scanner">
            <div class="scanner-box">
                <i class="bi bi-upc-scan"></i>

                <input
                    type="text"
                    id="scannerInput"
                    class="scanner-input"
                    placeholder="Bipe o código de cada caixa..."
                    autocomplete="off"
                    autofocus
                >

                <span class="ready">
                    <span class="dot"></span>
                    Leitor pronto
                </span>
            </div>

            <button
                type="button"
                class="focus-btn"
                id="focusScanner"
            >
                <i class="bi bi-crosshair"></i>
                Voltar ao bipador
            </button>

            <div class="feedback" id="feedback"></div>
        </section>
    <?php endif; ?>

    <section class="panel">
        <div class="toolbar">
            <div class="search-box">
                <i class="bi bi-search"></i>

                <input
                    type="search"
                    id="searchInput"
                    class="search"
                    placeholder="Pesquisar modelo ou código..."
                    autocomplete="off"
                >
            </div>

            <select id="statusFilter" class="filter">
                <option value="">Todos os modelos</option>
                <option value="pendente">Não conferidos</option>
                <option value="correto">Quantidade correta</option>
                <option value="faltando">Está faltando</option>
                <option value="sobrando">Está sobrando</option>
            </select>

            <button type="button" class="pending-btn" id="nextPending">
                <i class="bi bi-arrow-down-circle-fill"></i>
                Próximo pendente
            </button>
        </div>

        <div class="items" id="itemsGrid">
            <?php foreach ($itens as $item): ?>
                <?php $d = itemFormatado($item); ?>

                <article
                    class="item <?= e($d['status']) ?>"
                    data-card
                    data-item-id="<?= $d['id'] ?>"
                    data-status="<?= e($d['status']) ?>"
                    data-search="<?= e(
                        mb_strtolower(
                            $d['modelo'] . ' ' . $d['codigo_barras'],
                            'UTF-8'
                        )
                    ) ?>"
                    id="card<?= $d['id'] ?>"
                >
                    <div class="item-head">
                        <div>
                            <h3 class="item-title"><?= e($d['modelo']) ?></h3>

                            <span class="item-code">
                                <i class="bi bi-upc-scan me-1"></i>
                                <?= $d['codigo_barras'] !== ''
                                    ? e($d['codigo_barras'])
                                    : 'Código não configurado' ?>
                            </span>
                        </div>

                        <span
                            class="status <?= e($d['status']) ?>"
                            id="status<?= $d['id'] ?>"
                        >
                            <i class="bi <?= match ($d['status']) {
                                'correto' => 'bi-check-circle-fill',
                                'faltando' => 'bi-dash-circle-fill',
                                'sobrando' => 'bi-plus-circle-fill',
                                default => 'bi-hourglass-split'
                            } ?>"></i>

                            <span><?= e($d['rotulo']) ?></span>
                        </span>
                    </div>

                    <div class="item-body">
                        <div class="compare">
                            <div class="qty-box">
                                <span>Sistema</span>
                                <strong><?= $d['quantidade_sistema'] ?></strong>
                            </div>

                            <div class="compare-icon">
                                <i class="bi bi-arrow-left-right"></i>
                            </div>

                            <div class="qty-box physical">
                                <span>Contagem física</span>
                                <strong id="physical<?= $d['id'] ?>">
                                    <?= $d['conferido']
                                        ? $d['quantidade_contada']
                                        : '—' ?>
                                </strong>
                            </div>
                        </div>

                        <?php if ($aberto): ?>
                            <div class="controls">
                                <button
                                    type="button"
                                    class="qty-btn"
                                    data-minus
                                    data-id="<?= $d['id'] ?>"
                                >−</button>

                                <input
                                    type="number"
                                    min="0"
                                    class="qty-input"
                                    data-input
                                    data-id="<?= $d['id'] ?>"
                                    value="<?= $d['conferido']
                                        ? $d['quantidade_contada']
                                        : '' ?>"
                                    placeholder="0"
                                    inputmode="numeric"
                                >

                                <button
                                    type="button"
                                    class="qty-btn"
                                    data-plus
                                    data-id="<?= $d['id'] ?>"
                                >+</button>
                            </div>

                            <div class="item-actions">
                                <button
                                    type="button"
                                    class="item-btn zero"
                                    data-zero
                                    data-id="<?= $d['id'] ?>"
                                >
                                    <i class="bi bi-0-circle-fill"></i>
                                    Confirmar zero
                                </button>

                                <button
                                    type="button"
                                    class="item-btn"
                                    data-clear
                                    data-id="<?= $d['id'] ?>"
                                >
                                    <i class="bi bi-arrow-counterclockwise"></i>
                                    Limpar contagem
                                </button>
                            </div>
                        <?php endif; ?>

                        <span class="updated" id="updated<?= $d['id'] ?>">
                            <?= $d['conferido']
                                ? 'Conferido em ' .
                                    e(dataBr($item['atualizado_em'] ?? null))
                                : 'Aguardando conferência física' ?>
                        </span>
                    </div>
                </article>
            <?php endforeach; ?>

            <div class="empty" id="emptyResult">
                <i class="bi bi-search fs-1 d-block mb-2"></i>
                Nenhum modelo corresponde ao filtro.
            </div>
        </div>
    </section>

    <section class="finish-grid">
        <div class="card">
            <div class="card-head">
                <div class="card-icon">
                    <i class="bi bi-check2-all"></i>
                </div>

                <div>
                    <h3><?= $aberto ? 'Concluir inventário' : 'Resumo do inventário' ?></h3>
                    <p><?= $aberto
                        ? 'Revise as diferenças antes de encerrar.'
                        : 'Resultado registrado para consulta.' ?></p>
                </div>
            </div>

            <div class="card-body">
                <?php if ($aberto): ?>
                    <form method="POST" id="finishForm">
                        <input type="hidden" name="csrf_token" value="<?= e($csrf) ?>">
                        <input type="hidden" name="acao" value="concluir">
                        <input type="hidden" name="inventario_id" value="<?= (int) $inventario['id'] ?>">

                        <label class="form-label" for="observation">
                            Observação do inventário
                        </label>

                        <textarea
                            name="observacao"
                            id="observation"
                            class="form-control"
                            maxlength="500"
                            placeholder="Ex.: Inventário realizado no depósito principal..."
                        ></textarea>

                        <label class="adjust">
                            <input
                                type="checkbox"
                                name="aplicar_ajustes"
                                value="1"
                                id="applyAdjustments"
                            >

                            <span>
                                <strong>Aplicar diferenças no estoque</strong>
                                <span>
                                    Marque somente depois de revisar.
                                    O saldo do sistema será substituído pela
                                    quantidade física contada e o ajuste ficará
                                    registrado no histórico.
                                </span>
                            </span>
                        </label>

                        <div class="finish-actions">
                            <button
                                type="button"
                                class="finish-btn danger"
                                data-bs-toggle="modal"
                                data-bs-target="#cancelModal"
                            >
                                <i class="bi bi-x-octagon-fill"></i>
                                Cancelar inventário
                            </button>

                            <button
                                type="submit"
                                class="finish-btn primary"
                                id="finishButton"
                                <?= $m['conferidos'] < $m['total']
                                    ? 'disabled'
                                    : '' ?>
                            >
                                <i class="bi bi-check-circle-fill"></i>
                                Concluir inventário
                            </button>
                        </div>
                    </form>
                <?php else: ?>
                    <div class="row g-3">
                        <div class="col-md-4">
                            <div class="qty-box">
                                <span>Modelos conferidos</span>
                                <strong><?= $m['conferidos'] ?></strong>
                            </div>
                        </div>

                        <div class="col-md-4">
                            <div class="qty-box">
                                <span>Divergências</span>
                                <strong><?= $m['divergencias'] ?></strong>
                            </div>
                        </div>

                        <div class="col-md-4">
                            <div class="qty-box">
                                <span>Ajustes aplicados</span>
                                <strong style="font-size:24px;">
                                    <?= (int) ($inventario['ajustes_aplicados'] ?? 0) === 1
                                        ? 'SIM'
                                        : 'NÃO' ?>
                                </strong>
                            </div>
                        </div>
                    </div>

                    <?php if (trim((string) ($inventario['observacao'] ?? '')) !== ''): ?>
                        <div class="alert alert-info border-0 rounded-4 mt-3 mb-0">
                            <strong>Observação:</strong><br>
                            <?= nl2br(e((string) $inventario['observacao'])) ?>
                        </div>
                    <?php endif; ?>

                    <div class="finish-actions">
                        <a
                            href="inventario_tonner.php"
                            class="finish-btn primary"
                        >
                            <i class="bi bi-plus-circle-fill"></i>
                            Iniciar outro inventário
                        </a>
                    </div>
                <?php endif; ?>
            </div>
        </div>

        <aside class="card">
            <div class="card-head">
                <div class="card-icon" style="background:linear-gradient(145deg,var(--primary-dark),var(--primary));">
                    <i class="bi bi-clock-history"></i>
                </div>

                <div>
                    <h3>Últimos inventários</h3>
                    <p>Histórico rápido para consulta.</p>
                </div>
            </div>

            <div class="history">
                <?php if (empty($historico)): ?>
                    <div class="text-center text-muted py-4">
                        Nenhum inventário anterior.
                    </div>
                <?php endif; ?>

                <?php foreach ($historico as $h): ?>
                    <a
                        href="inventario_tonner.php?id=<?= (int) $h['id'] ?>"
                        class="history-item"
                    >
                        <div class="history-icon">
                            <i class="bi bi-clipboard-data-fill"></i>
                        </div>

                        <div>
                            <strong>Inventário #<?= (int) $h['id'] ?></strong>
                            <span>
                                <?= e((string) $h['usuario']) ?> •
                                <?= e(dataBr($h['iniciado_em'] ?? null)) ?>
                            </span>
                        </div>

                        <span class="badge-status <?= e((string) $h['status']) ?>">
                            <?= e((string) $h['status']) ?>
                        </span>
                    </a>
                <?php endforeach; ?>
            </div>
        </aside>
    </section>

<?php endif; ?>

</main>
</div>

<?php if ($aberto): ?>
<div class="modal fade" id="cancelModal" tabindex="-1">
    <div class="modal-dialog modal-dialog-centered">
        <div class="modal-content border-0" style="border-radius:24px;overflow:hidden;">
            <div class="modal-header border-0 text-white" style="background:linear-gradient(135deg,var(--red),#8d182b);">
                <h5 class="modal-title fw-bold">
                    <i class="bi bi-exclamation-triangle-fill me-2"></i>
                    Cancelar inventário
                </h5>

                <button
                    type="button"
                    class="btn-close btn-close-white"
                    data-bs-dismiss="modal"
                ></button>
            </div>

            <div class="modal-body p-4">
                <p class="mb-0">
                    Nenhuma quantidade do estoque será alterada.
                </p>
            </div>

            <div class="modal-footer border-0" style="background:#f9fbfd;">
                <button
                    type="button"
                    class="finish-btn"
                    data-bs-dismiss="modal"
                >
                    Voltar
                </button>

                <form method="POST">
                    <input type="hidden" name="csrf_token" value="<?= e($csrf) ?>">
                    <input type="hidden" name="acao" value="cancelar">
                    <input type="hidden" name="inventario_id" value="<?= (int) $inventario['id'] ?>">

                    <button type="submit" class="finish-btn danger">
                        <i class="bi bi-x-octagon-fill"></i>
                        Confirmar cancelamento
                    </button>
                </form>
            </div>
        </div>
    </div>
</div>
<?php endif; ?>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>

<script>
(() => {
    'use strict';

    const inventoryId = <?= (int) $inventarioId ?>;
    const inventoryOpen = <?= $aberto ? 'true' : 'false' ?>;
    const csrf = <?= json_encode(
        $csrf,
        JSON_UNESCAPED_UNICODE |
        JSON_HEX_TAG |
        JSON_HEX_APOS |
        JSON_HEX_QUOT |
        JSON_HEX_AMP
    ) ?>;

    const initialItems = <?= $itensJson ?: '[]' ?>;
    const items = new Map(
        initialItems.map(item => [Number(item.id), item])
    );

    const scanner = document.getElementById('scannerInput');
    const feedback = document.getElementById('feedback');
    const search = document.getElementById('searchInput');
    const filter = document.getElementById('statusFilter');
    const finishButton = document.getElementById('finishButton');
    const finishForm = document.getElementById('finishForm');
    const applyAdjustments = document.getElementById('applyAdjustments');

    let audioContext = null;
    let busy = false;

    function normalize(value) {
        return String(value ?? '')
            .normalize('NFD')
            .replace(/[\u0300-\u036f]/g, '')
            .toLowerCase()
            .trim();
    }

    function escapeHtml(value) {
        const div = document.createElement('div');
        div.textContent = String(value ?? '');
        return div.innerHTML;
    }

    function audio() {
        if (!audioContext) {
            const AC = window.AudioContext || window.webkitAudioContext;

            if (AC) {
                audioContext = new AC();
            }
        }

        return audioContext;
    }

    function beep(type = 'success') {
        const ctx = audio();

        if (!ctx) {
            return;
        }

        if (ctx.state === 'suspended') {
            ctx.resume();
        }

        const oscillator = ctx.createOscillator();
        const gain = ctx.createGain();

        oscillator.connect(gain);
        gain.connect(ctx.destination);

        const now = ctx.currentTime;

        if (type === 'error') {
            oscillator.frequency.setValueAtTime(190, now);
            oscillator.frequency.setValueAtTime(145, now + .13);
        } else if (type === 'warning') {
            oscillator.frequency.setValueAtTime(420, now);
            oscillator.frequency.setValueAtTime(350, now + .1);
        } else {
            oscillator.frequency.setValueAtTime(650, now);
            oscillator.frequency.setValueAtTime(880, now + .08);
        }

        gain.gain.setValueAtTime(.0001, now);
        gain.gain.exponentialRampToValueAtTime(.2, now + .015);
        gain.gain.exponentialRampToValueAtTime(.0001, now + .24);

        oscillator.start(now);
        oscillator.stop(now + .26);
    }

    function showFeedback(type, html) {
        if (!feedback) {
            return;
        }

        feedback.className = `feedback visible ${type}`;
        feedback.innerHTML = html;
    }

    async function action(acao, data = {}) {
        const body = new URLSearchParams({
            ajax: '1',
            acao,
            inventario_id: String(inventoryId),
            csrf_token: csrf
        });

        Object.entries(data).forEach(([key, value]) => {
            body.set(key, String(value));
        });

        const response = await fetch('inventario_tonner.php', {
            method: 'POST',
            headers: {
                'Content-Type':
                    'application/x-www-form-urlencoded;charset=UTF-8',
                'X-Requested-With': 'XMLHttpRequest'
            },
            body: body.toString()
        });

        const payload = await response.json().catch(() => ({}));

        if (!response.ok || payload.sucesso === false) {
            throw new Error(
                payload.erro ??
                'Não foi possível salvar a conferência.'
            );
        }

        return payload;
    }

    function icon(status) {
        return {
            correto: 'bi-check-circle-fill',
            faltando: 'bi-dash-circle-fill',
            sobrando: 'bi-plus-circle-fill',
            pendente: 'bi-hourglass-split'
        }[status] ?? 'bi-hourglass-split';
    }

    function updateItem(item, highlight = false) {
        items.set(Number(item.id), item);

        const card = document.getElementById(`card${item.id}`);
        const status = document.getElementById(`status${item.id}`);
        const physical = document.getElementById(`physical${item.id}`);
        const input = document.querySelector(
            `[data-input][data-id="${item.id}"]`
        );

        const updated = document.getElementById(`updated${item.id}`);

        if (card) {
            card.classList.remove(
                'pendente',
                'correto',
                'faltando',
                'sobrando'
            );

            card.classList.add(item.status);
            card.dataset.status = item.status;

            if (highlight) {
                card.classList.remove('flash');

                requestAnimationFrame(() => {
                    card.classList.add('flash');
                });

                card.scrollIntoView({
                    behavior: 'smooth',
                    block: 'center'
                });
            }
        }

        if (status) {
            status.className = `status ${item.status}`;
            status.innerHTML = `
                <i class="bi ${icon(item.status)}"></i>
                <span>${escapeHtml(item.rotulo)}</span>
            `;
        }

        if (physical) {
            physical.textContent = item.conferido
                ? String(item.quantidade_contada)
                : '—';
        }

        if (input) {
            input.value = item.conferido
                ? String(item.quantidade_contada)
                : '';
        }

        if (updated) {
            updated.textContent = item.conferido
                ? 'Contagem salva agora'
                : 'Aguardando conferência física';
        }

        filterCards();
    }

    function updateMetrics(m) {
        const map = {
            mTotal: m.total,
            mChecked: m.conferidos,
            mCorrect: m.corretos,
            mDiff: m.divergencias,
            mMissing: m.faltantes,
            mExtra: m.sobras,
            progressNumber: m.percentual
        };

        Object.entries(map).forEach(([id, value]) => {
            const el = document.getElementById(id);

            if (el) {
                el.textContent = String(value);
            }
        });

        const bar = document.getElementById('progressBar');
        const desc = document.getElementById('progressDescription');

        if (bar) {
            bar.style.width = `${m.percentual}%`;
        }

        if (desc) {
            desc.textContent =
                `${m.conferidos} de ${m.total} modelos conferidos.`;
        }

        if (finishButton) {
            finishButton.disabled =
                Number(m.conferidos) < Number(m.total);
        }
    }

    async function scanCode(code) {
        const value = String(code ?? '').trim();

        if (!value || busy || !inventoryOpen) {
            return;
        }

        busy = true;

        showFeedback(
            'success',
            '<span class="spinner-border spinner-border-sm me-2"></span>' +
            'Registrando leitura...'
        );

        try {
            const payload = await action('bipar', {
                codigo: value
            });

            beep('success');
            updateItem(payload.item, true);
            updateMetrics(payload.metricas);

            showFeedback(
                'success',
                `<i class="bi bi-check-circle-fill me-2"></i>` +
                `<strong>${escapeHtml(payload.item.modelo)}</strong>: ` +
                `${payload.item.quantidade_contada} unidade(s). ` +
                `<strong>${escapeHtml(payload.item.rotulo)}</strong>.`
            );

            scanner.value = '';
            scanner.focus();
        } catch (error) {
            beep('error');

            showFeedback(
                'error',
                `<i class="bi bi-x-octagon-fill me-2"></i>` +
                escapeHtml(error.message)
            );

            scanner?.select();
        } finally {
            busy = false;
        }
    }

    scanner?.addEventListener('keydown', event => {
        if (event.key === 'Enter') {
            event.preventDefault();
            scanCode(scanner.value);
        }
    });

    function focusScanner() {
        scanner?.focus();
        scanner?.select();
        beep('success');
    }

    document
        .getElementById('focusScanner')
        ?.addEventListener('click', focusScanner);

    document
        .getElementById('headerScanner')
        ?.addEventListener('click', focusScanner);

    window.addEventListener('keydown', event => {
        if (event.key === 'F2' && inventoryOpen) {
            event.preventDefault();
            focusScanner();
        }
    });

    async function setQuantity(id, quantity) {
        try {
            const payload = await action('definir', {
                item_id: id,
                quantidade: Math.max(0, Number(quantity) || 0)
            });

            beep(
                payload.item.status === 'correto'
                    ? 'success'
                    : 'warning'
            );

            updateItem(payload.item);
            updateMetrics(payload.metricas);
        } catch (error) {
            beep('error');
            window.alert(error.message);
        }
    }

    async function addQuantity(id, value) {
        try {
            const payload = await action('somar', {
                item_id: id,
                valor: value
            });

            beep(
                payload.item.status === 'correto'
                    ? 'success'
                    : 'warning'
            );

            updateItem(payload.item);
            updateMetrics(payload.metricas);
        } catch (error) {
            beep('error');
            window.alert(error.message);
        }
    }

    async function clearItem(id) {
        try {
            const payload = await action('limpar', {
                item_id: id
            });

            updateItem(payload.item);
            updateMetrics(payload.metricas);
        } catch (error) {
            beep('error');
            window.alert(error.message);
        }
    }

    document.querySelectorAll('[data-plus]').forEach(button => {
        button.addEventListener('click', () => {
            addQuantity(Number(button.dataset.id), 1);
        });
    });

    document.querySelectorAll('[data-minus]').forEach(button => {
        button.addEventListener('click', () => {
            addQuantity(Number(button.dataset.id), -1);
        });
    });

    document.querySelectorAll('[data-zero]').forEach(button => {
        button.addEventListener('click', () => {
            setQuantity(Number(button.dataset.id), 0);
        });
    });

    document.querySelectorAll('[data-clear]').forEach(button => {
        button.addEventListener('click', () => {
            clearItem(Number(button.dataset.id));
        });
    });

    document.querySelectorAll('[data-input]').forEach(input => {
        let timer = null;

        input.addEventListener('input', () => {
            clearTimeout(timer);

            timer = setTimeout(() => {
                if (input.value === '') {
                    return;
                }

                setQuantity(
                    Number(input.dataset.id),
                    Number(input.value)
                );
            }, 550);
        });
    });

    function filterCards() {
        const term = normalize(search?.value);
        const status = filter?.value ?? '';

        const cards = Array.from(
            document.querySelectorAll('[data-card]')
        );

        let visible = 0;

        cards.forEach(card => {
            const matchesTerm =
                term === '' ||
                normalize(card.dataset.search).includes(term);

            const matchesStatus =
                status === '' ||
                card.dataset.status === status;

            const show = matchesTerm && matchesStatus;

            card.style.display = show ? '' : 'none';

            if (show) {
                visible++;
            }
        });

        const empty = document.getElementById('emptyResult');

        if (empty) {
            empty.style.display =
                visible === 0 && cards.length > 0
                    ? 'block'
                    : 'none';
        }
    }

    search?.addEventListener('input', filterCards);
    filter?.addEventListener('change', filterCards);

    document
        .getElementById('nextPending')
        ?.addEventListener('click', () => {
            const pending = Array.from(
                document.querySelectorAll(
                    '[data-card][data-status="pendente"]'
                )
            ).find(card => card.style.display !== 'none');

            if (!pending) {
                beep('success');
                window.alert(
                    'Todos os modelos visíveis já foram conferidos.'
                );
                return;
            }

            pending.scrollIntoView({
                behavior: 'smooth',
                block: 'center'
            });

            pending.classList.remove('flash');

            requestAnimationFrame(() => {
                pending.classList.add('flash');
            });
        });

    finishForm?.addEventListener('submit', event => {
        if (finishButton?.disabled) {
            event.preventDefault();
            window.alert('Ainda existem modelos sem conferência.');
            return;
        }

        const divergences = Number(
            document.getElementById('mDiff')?.textContent ?? 0
        );

        const applying = Boolean(applyAdjustments?.checked);

        let message = 'Confirma a conclusão deste inventário?';

        if (divergences > 0 && applying) {
            message =
                `Existem ${divergences} modelo(s) com divergência. ` +
                'As quantidades do estoque serão substituídas pelas ' +
                'contagens físicas. Confirma?';
        } else if (divergences > 0) {
            message =
                `Existem ${divergences} modelo(s) com divergência. ` +
                'O inventário será concluído sem alterar o estoque. Confirma?';
        }

        if (!window.confirm(message)) {
            event.preventDefault();
            return;
        }

        finishButton.disabled = true;
        finishButton.innerHTML = `
            <span class="spinner-border spinner-border-sm"></span>
            Concluindo...
        `;
    });

    function updateClock() {
        const el = document.getElementById('clock');

        if (!el) {
            return;
        }

        const now = new Date();

        const date = now.toLocaleDateString('pt-BR', {
            weekday: 'long',
            day: '2-digit',
            month: 'long',
            year: 'numeric'
        });

        const time = now.toLocaleTimeString('pt-BR', {
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit'
        });

        el.textContent =
            date.charAt(0).toUpperCase() +
            date.slice(1) +
            ' • ' +
            time;
    }

    const hero = document.getElementById('hero');

    if (
        hero &&
        window.matchMedia('(pointer:fine)').matches &&
        !window.matchMedia('(prefers-reduced-motion:reduce)').matches
    ) {
        hero.addEventListener('mousemove', event => {
            const rect = hero.getBoundingClientRect();
            const x = event.clientX - rect.left;
            const y = event.clientY - rect.top;

            const ry =
                ((x - rect.width / 2) / (rect.width / 2)) * .45;

            const rx =
                (((rect.height / 2) - y) / (rect.height / 2)) * .28;

            hero.style.transform =
                `perspective(1600px) rotateX(${rx}deg) rotateY(${ry}deg)`;
        });

        hero.addEventListener('mouseleave', () => {
            hero.style.transform =
                'perspective(1600px) rotateX(0deg) rotateY(0deg)';
        });
    }

    updateClock();
    setInterval(updateClock, 1000);

    window.addEventListener('load', () => {
        if (inventoryOpen) {
            setTimeout(() => scanner?.focus(), 350);
        }
    });
})();
</script>
</body>
</html>
