<?php
declare(strict_types=1);

function osPublicoTextoMinusculo(string $texto): string
{
    $texto = trim($texto);

    if (function_exists('mb_strtolower')) {
        return mb_strtolower($texto, 'UTF-8');
    }

    return strtolower($texto);
}

function osPublicoNormalizar(string $texto): string
{
    return strtr(osPublicoTextoMinusculo($texto), [
        'á' => 'a', 'à' => 'a', 'â' => 'a', 'ã' => 'a', 'ä' => 'a',
        'é' => 'e', 'è' => 'e', 'ê' => 'e', 'ë' => 'e',
        'í' => 'i', 'ì' => 'i', 'î' => 'i', 'ï' => 'i',
        'ó' => 'o', 'ò' => 'o', 'ô' => 'o', 'õ' => 'o', 'ö' => 'o',
        'ú' => 'u', 'ù' => 'u', 'û' => 'u', 'ü' => 'u',
        'ç' => 'c'
    ]);
}

function osPublicoStatusCodigo(string $status): string
{
    $normalizado = osPublicoNormalizar($status);

    if (str_contains($normalizado, 'cancel')) {
        return 'cancelado';
    }

    if (str_contains($normalizado, 'finaliz')) {
        return 'entregue';
    }

    if (
        str_contains($normalizado, 'pendente') &&
        str_contains($normalizado, 'retirada')
    ) {
        return 'pronto_retirada';
    }

    if (str_contains($normalizado, 'aguardando') && str_contains($normalizado, 'peca')) {
        return 'aguardando_material';
    }

    if (str_contains($normalizado, 'teste')) {
        return 'testes';
    }

    return 'em_analise';
}

function osPublicoStatusDados(string $status): array
{
    return match (osPublicoStatusCodigo($status)) {
        'entregue' => [
            'codigo' => 'entregue',
            'rotulo' => 'Equipamento entregue',
            'descricao' => 'O atendimento foi concluído e o equipamento foi entregue ao responsável.',
            'icone' => 'bi-check-circle-fill',
            'classe' => 'success',
            'etapa' => 4
        ],
        'pronto_retirada' => [
            'codigo' => 'pronto_retirada',
            'rotulo' => 'Pronto para retirada',
            'descricao' => 'O serviço técnico foi concluído e o equipamento está disponível para retirada.',
            'icone' => 'bi-box-arrow-up-right',
            'classe' => 'ready',
            'etapa' => 3
        ],
        'aguardando_material' => [
            'codigo' => 'aguardando_material',
            'rotulo' => 'Aguardando material',
            'descricao' => 'O atendimento está aguardando material ou peça compatível para continuidade.',
            'icone' => 'bi-hourglass-split',
            'classe' => 'warning',
            'etapa' => 2
        ],
        'testes' => [
            'codigo' => 'testes',
            'rotulo' => 'Em testes finais',
            'descricao' => 'A manutenção foi executada e o equipamento está passando por validações finais.',
            'icone' => 'bi-clipboard2-pulse-fill',
            'classe' => 'info',
            'etapa' => 2
        ],
        'cancelado' => [
            'codigo' => 'cancelado',
            'rotulo' => 'Atendimento encerrado',
            'descricao' => 'A ordem de serviço foi encerrada. Entre em contato com a Gerência de Tecnologia para mais informações.',
            'icone' => 'bi-x-octagon-fill',
            'classe' => 'danger',
            'etapa' => 1
        ],
        default => [
            'codigo' => 'em_analise',
            'rotulo' => 'Em análise técnica',
            'descricao' => 'A equipe de Tecnologia está analisando e executando os procedimentos necessários.',
            'icone' => 'bi-tools',
            'classe' => 'progress',
            'etapa' => 2
        ]
    };
}

function osPublicoGerarToken(): string
{
    return bin2hex(random_bytes(24));
}

function osPublicoGarantirToken(mysqli $mysqli, int $osId): string
{
    $stmt = $mysqli->prepare("
        SELECT token_acompanhamento
        FROM ordens_servico
        WHERE id = ?
        LIMIT 1
    ");

    if (!$stmt) {
        throw new RuntimeException('Não foi possível consultar o acompanhamento da OS.');
    }

    $stmt->bind_param('i', $osId);
    $stmt->execute();
    $linha = $stmt->get_result()->fetch_assoc();
    $stmt->close();

    if (!$linha) {
        throw new RuntimeException('Ordem de serviço não encontrada.');
    }

    $tokenAtual = trim((string) ($linha['token_acompanhamento'] ?? ''));

    if ($tokenAtual !== '') {
        return $tokenAtual;
    }

    for ($tentativa = 0; $tentativa < 5; $tentativa++) {
        $token = osPublicoGerarToken();

        $upd = $mysqli->prepare("
            UPDATE ordens_servico
            SET
                token_acompanhamento = ?,
                acompanhamento_ativo = 1
            WHERE id = ?
              AND (
                    token_acompanhamento IS NULL
                 OR token_acompanhamento = ''
              )
        ");

        if (!$upd) {
            throw new RuntimeException('Não foi possível preparar o link público.');
        }

        $upd->bind_param('si', $token, $osId);

        if ($upd->execute()) {
            $alteradas = $upd->affected_rows;
            $upd->close();

            if ($alteradas > 0) {
                return $token;
            }

            return osPublicoGarantirToken($mysqli, $osId);
        }

        $erro = $upd->errno;
        $upd->close();

        if ($erro !== 1062) {
            throw new RuntimeException('Não foi possível gerar o link público.');
        }
    }

    throw new RuntimeException('Não foi possível gerar um token exclusivo.');
}

function osPublicoRegistrarAtualizacao(
    mysqli $mysqli,
    int $osId,
    string $titulo,
    string $mensagem,
    string $statusPublico,
    string $publicadoPor,
    int $visivel = 1
): int {
    $stmt = $mysqli->prepare("
        INSERT INTO os_atualizacoes_publicas (
            os_id,
            titulo,
            mensagem,
            status_publico,
            publicado_por,
            visivel
        ) VALUES (?, ?, NULLIF(?, ''), ?, NULLIF(?, ''), ?)
    ");

    if (!$stmt) {
        throw new RuntimeException('Não foi possível preparar a atualização pública.');
    }

    $stmt->bind_param(
        'issssi',
        $osId,
        $titulo,
        $mensagem,
        $statusPublico,
        $publicadoPor,
        $visivel
    );

    if (!$stmt->execute()) {
        $erro = $stmt->error;
        $stmt->close();
        throw new RuntimeException('Erro ao registrar atualização pública: ' . $erro);
    }

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

    return $id;
}

function osPublicoBaseUrl(): string
{
    $https = (
        (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
        strtolower((string) ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '')) === 'https'
    );

    $scheme = $https ? 'https' : 'http';
    $host = (string) ($_SERVER['HTTP_HOST'] ?? 'localhost');

    if (!preg_match('/^[A-Za-z0-9.:-]+$/', $host)) {
        $host = 'localhost';
    }

    $script = str_replace('\\', '/', (string) ($_SERVER['SCRIPT_NAME'] ?? '/'));
    $dir = rtrim(dirname($script), '/.');

    return $scheme . '://' . $host . ($dir !== '' ? $dir : '');
}

function osPublicoUrl(string $token): string
{
    return osPublicoBaseUrl() . '/acompanhar_os.php?token=' . rawurlencode($token);
}

function osPublicoNomeSeguro(string $nome): string
{
    $partes = preg_split('/\s+/u', trim($nome)) ?: [];

    if (!$partes) {
        return 'Solicitante';
    }

    $primeiro = array_shift($partes);
    $iniciais = [];

    foreach ($partes as $parte) {
        if ($parte === '') {
            continue;
        }

        $iniciais[] = function_exists('mb_substr')
            ? mb_substr($parte, 0, 1, 'UTF-8') . '.'
            : substr($parte, 0, 1) . '.';
    }

    return trim($primeiro . ' ' . implode(' ', $iniciais));
}

function osPublicoPatrimonioSeguro(string $patrimonio): string
{
    $patrimonio = trim($patrimonio);

    if ($patrimonio === '') {
        return 'Não informado';
    }

    $tamanho = function_exists('mb_strlen')
        ? mb_strlen($patrimonio, 'UTF-8')
        : strlen($patrimonio);

    $visiveis = min(4, $tamanho);
    $final = function_exists('mb_substr')
        ? mb_substr($patrimonio, -$visiveis, null, 'UTF-8')
        : substr($patrimonio, -$visiveis);

    return str_repeat('•', max(3, $tamanho - $visiveis)) . $final;
}

function osPublicoDataBr(?string $data, string $vazio = 'Não informado'): string
{
    $data = trim((string) $data);

    if ($data === '') {
        return $vazio;
    }

    $timestamp = strtotime($data);

    return $timestamp !== false
        ? date('d/m/Y \à\s H:i', $timestamp)
        : $vazio;
}

function osPublicoCodigoAcompanhamento(string $token): string
{
    $limpo = preg_replace(
        '/[^a-f0-9]/i',
        '',
        strtolower(trim($token))
    ) ?? '';

    $prefixo = strtoupper(substr($limpo, 0, 12));

    if ($prefixo === '') {
        return 'NÃO-GERADO';
    }

    return implode('-', str_split($prefixo, 4));
}

function osPublicoCodigoPrefixo(string $codigo): string
{
    return strtolower(
        substr(
            preg_replace('/[^a-f0-9]/i', '', $codigo) ?? '',
            0,
            12
        )
    );
}

