<?php
// ARQUIVO: gestao_ponto/api.php
// VERSÃO: CORREÇÃO DEFINITIVA (JUSTIFICATIVAS INTEGRADAS)

// 1. Configurações de Segurança e Erro
ini_set('display_errors', 0); // Não mostra erros na tela (quebra o JSON)
ini_set('log_errors', 1);     // Grava erros no log do servidor
error_reporting(E_ALL);

date_default_timezone_set('America/Sao_Paulo');
header('Content-Type: application/json; charset=utf-8');
header("Access-Control-Allow-Origin: *");

// 2. Conexão com Banco de Dados
$host = 'localhost';
$dbname = 'vini_vfsystem';
$user = 'vini_vfuser';
$pass = '5@;NwUBzhhRc'; // <--- VERIFIQUE SE A SENHA ESTÁ CERTA

try {
    $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->exec("SET time_zone = '-03:00'");
} catch (PDOException $e) {
    echo json_encode(['status' => 'erro', 'msg' => 'Erro Conexão: ' . $e->getMessage()]);
    exit;
}
// --- FUNÇÃO MESTRE: SOMA INTELIGENTE (IGUAL À TELA DO ADMIN) ---
function atualizar_saldo_mestre($pdo, $uid) {
    $stmtU = $pdo->prepare("SELECT nivel_acesso FROM usuarios WHERE id = ?");
    $stmtU->execute([$uid]);
    $nivel = mb_strtolower($stmtU->fetchColumn() ?: '', 'UTF-8');
    $ehHorista = (strpos($nivel, 'horista') !== false || strpos($nivel, 'estagi') !== false);
    
    $stmt = $pdo->prepare("SELECT * FROM controle_ponto WHERE usuario_id = ?");
    $stmt->execute([$uid]);
    $registros = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
    $hoje = date('Y-m-d');
    $totalFinal = 0;
    
    foreach ($registros as $row) {
        $data = $row['data_registro'];
        $saldoDia = intval($row['saldo_minutos']);
        $obs = $row['observacao'] ?? '';
        $h = json_decode($row['horarios'], true);
        if (!is_array($h)) $h = ['', '', '', '', '', '', '', ''];
        
        $primeiraPalavra = mb_strtoupper($h[0] ?? '', 'UTF-8');
        
        // 1. Ignora dias Imunes
        if (strpos($primeiraPalavra, 'FÉRIAS') !== false || strpos($primeiraPalavra, 'FERIAS') !== false || 
            strpos($primeiraPalavra, 'ATESTADO') !== false || strpos($primeiraPalavra, 'FOLGA') !== false ||
            strpos($primeiraPalavra, 'LICENÇA') !== false) {
            continue; 
        }

        // 2. Não desconta via texto se for a linha pura de Pagamento
        if ($primeiraPalavra !== 'PAGAMENTO' && preg_match('/(?:PG:|Pagamento:)\s*(\d+):(\d+)/i', $obs, $m)) {
            $saldoDia -= (($m[1] * 60) + $m[2]);
        }
        
        $isFuturo = ($data > $hoje);
        $isHoje = ($data === $hoje);
        $fechado = (!empty($h[3]) && strlen($h[3]) >= 5);
        
        // 3. A CORREÇÃO: SE FOR PAGAMENTO, NUNCA IGNORA (PASSE LIVRE)
        if ($isFuturo && $saldoDia < 0 && $primeiraPalavra !== 'PAGAMENTO') continue;
        if ($isHoje && $saldoDia < 0 && !$fechado && !$ehHorista && $primeiraPalavra !== 'PAGAMENTO') continue;
        
        $totalFinal += $saldoDia;
    }
    
    $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = ? WHERE id = ?")->execute([$totalFinal, $uid]);
}
// ---------------------------------------------------------------

$input = json_decode(file_get_contents('php://input'), true);
$acao = $input['acao'] ?? '';

try {

   // --- 1. LER PONTO (CORREÇÃO MATEMÁTICA PARA O APP) ---
    if ($acao === 'ler_ponto_dia') {
        $uid = $input['usuario_id'];
        $dataApp = $input['data']; 
        $dataServidor = date('Y-m-d'); 
        
        // 1. Busca a Verdade Absoluta (Tabela Usuários)
        $stmtUser = $pdo->prepare("SELECT banco_atual_minutos, aniversario FROM usuarios WHERE id = ?");
        $stmtUser->execute([$uid]);
        $dadosUser = $stmtUser->fetch(PDO::FETCH_ASSOC);
        $bancoTotalAdmin = $dadosUser ? intval($dadosUser['banco_atual_minutos']) : 0;
        
        // 2. Busca o Dia
        $stmtDia = $pdo->prepare("SELECT * FROM controle_ponto WHERE usuario_id = ? AND data_registro = ?");
        $stmtDia->execute([$uid, $dataApp]);
        $dadosDia = $stmtDia->fetch(PDO::FETCH_ASSOC);

        // Prepara objeto visual limpo
        $viewFinal = [
            'id' => null, 'meta_minutos' => 0, 'saldo_minutos' => 0, 
            'observacao' => '', 'horarios' => array_fill(0, 8, ""), 'justificativas' => array_fill(0, 8, "")
        ];

        if ($dadosDia) {
            $viewFinal['id'] = $dadosDia['id'];
            $viewFinal['meta_minutos'] = intval($dadosDia['meta_minutos']);
            $viewFinal['saldo_minutos'] = intval($dadosDia['saldo_minutos']); // Valor do dia (inclui ajuste)
            $viewFinal['observacao'] = $dadosDia['observacao'];

            // Limpa horários para não quebrar JSON
            $hArr = json_decode($dadosDia['horarios'], true);
            if (!is_array($hArr)) $hArr = json_decode(stripslashes($dadosDia['horarios']), true);
            if (is_array($hArr)) {
                foreach($hArr as $k => $v) if ($k < 8) $viewFinal['horarios'][$k] = ($v === null || $v === 'null') ? "" : strval($v);
            }
            
            // Se tiver texto "Ajuste" ou "Manual" no banco antigo, LIMPA VISUALMENTE pro funcionário conseguir bater ponto
            if ($viewFinal['horarios'][0] === 'Ajuste' || $viewFinal['horarios'][0] === 'Manual') {
                $viewFinal['horarios'] = array_fill(0, 8, "");
            }

            // Justificativas
            $jArr = json_decode($dadosDia['justificativas'], true);
            if (is_array($jArr)) {
                foreach($jArr as $k => $v) if ($k < 8) $viewFinal['justificativas'][$k] = ($v === null || $v === 'null') ? "" : strval($v);
            }
        }

        // 3. CÁLCULO MÁGICO DA SINCRONIA
        // BancoAnterior (App) = TotalAdmin - SaldoDesteDia
        // Isso faz com que [Anterior + Dia] seja igual ao TotalAdmin.
        $acumuladoParaApp = $bancoTotalAdmin - $viewFinal['saldo_minutos'];

        // Aniversário
        $isNiver = false;
        if (!empty($dadosUser['aniversario'])) {
            $niverLimpo = preg_replace('/[^0-9]/', '', $dadosUser['aniversario']);
            if (substr($niverLimpo, 0, 4) === date('dm')) $isNiver = true;
        }

        // Justificativa Texto
        $justificativaTexto = implode(" | ", array_filter($viewFinal['justificativas']));
        if (empty($justificativaTexto) && !empty($viewFinal['observacao'])) $justificativaTexto = $viewFinal['observacao'];

        echo json_encode([
            'status' => 'sucesso', 
            'acumulado' => $acumuladoParaApp, // Agora manda o valor sincronizado
            'dados_hoje' => $viewFinal, 
            'justificativa' => $justificativaTexto,
            'is_aniversario' => $isNiver
        ], JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR);
    }

    // --- 2. REGISTRAR PONTO (COM ATUALIZAÇÃO DO SALDO FIXO) ---
    elseif ($acao === 'registrar_ponto') {
        $uid = $input['usuario_id'];
        $rawJustificativa = $input['justificativa_nova'] ?? ($input['obs'] ?? '');
        $dataHoje = date('Y-m-d'); 
        $horaAgora = date('H:i');

        // 1. Verifica Nível (Meta)
        $stmtUser = $pdo->prepare("SELECT nivel_acesso FROM usuarios WHERE id = ?");
        $stmtUser->execute([$uid]);
        $nivelReal = $stmtUser->fetchColumn();
        $ehHorista = ($nivelReal === 'horista' || $nivelReal === 'estagiario');

        if ($ehHorista) {
            $metaAtual = 0;
        } else {
            if (isset($input['meta'])) {
                $metaAtual = intval($input['meta']);
            } else {
                $diaSem = date('w', strtotime($dataHoje));
                $metaAtual = ($diaSem == 0) ? 0 : (($diaSem == 6) ? 240 : 480);
            }
        }

        // 2. Busca Registro Atual
        $sql = "SELECT id, horarios, justificativas, meta_minutos, saldo_minutos, observacao FROM controle_ponto WHERE usuario_id = ? AND data_registro = ?";
        $stmt = $pdo->prepare($sql);
        $stmt->execute([$uid, $dataHoje]);
        $registro = $stmt->fetch(PDO::FETCH_ASSOC);

        // Prepara Horários
        $horarios = array_fill(0, 8, "");
        $listaJust = array_fill(0, 8, "");
        $id_controle = null;
        $slotIndex = 0;
        $saldoAntigoDia = 0; // Para calcular a diferença

        if ($registro) {
            $id_controle = $registro['id'];
            $saldoAntigoDia = intval($registro['saldo_minutos']); // Salva o saldo ANTES de bater o ponto
            
            $lidoH = json_decode($registro['horarios'], true);
            if (!is_array($lidoH)) $lidoH = json_decode(stripslashes($registro['horarios']), true);
            if (is_array($lidoH)) {
                foreach($lidoH as $k => $v) if ($k < 8 && !empty($v) && $v !== 'null') $horarios[$k] = $v;
            }

            $lidoJ = json_decode($registro['justificativas'] ?? '[]', true);
            if (is_array($lidoJ)) {
                foreach($lidoJ as $k => $v) if ($k < 8 && !empty($v) && $v !== 'null') $listaJust[$k] = $v;
            }

            $found = false;
            for ($i = 0; $i < 8; $i++) {
                if (empty($horarios[$i])) { $slotIndex = $i; $found = true; break; }
            }
            if (!$found) { echo json_encode(['status' => 'erro', 'msg' => 'Dia fechado!']); exit; }
        }

        // 3. Grava Novo Horário
        $horarios[$slotIndex] = $horaAgora;
        if (!empty($rawJustificativa)) {
            $listaJust[$slotIndex] = str_replace(['"', "'", "\\"], '', $rawJustificativa);
        }

        // 4. Calcula Novo Saldo
        $trabalhados = 0;
        for ($i = 0; $i < 8; $i += 2) {
            $e = $horarios[$i]; $s = $horarios[$i+1];
            if (!empty($e) && !empty($s) && $e !== "FALTA" && $s !== "FALTA") {
                list($h1, $m1) = explode(':', $e); list($h2, $m2) = explode(':', $s);
                $minE = ($h1 * 60) + $m1; $minS = ($h2 * 60) + $m2;
                if ($minS > $minE) $trabalhados += ($minS - $minE);
            }
        }
        
        $novoSaldoDia = $trabalhados - $metaAtual;
        
        // Mantém descontos de pagamento na observação
        $obsExistente = $registro['observacao'] ?? '';
        if (preg_match_all('/\|\s*PG:\s*(\d+:\d+)/', $obsExistente, $matches)) {
            foreach($matches[1] as $tempoPg) {
                list($hP, $mP) = explode(':', $tempoPg);
                $novoSaldoDia -= (($hP * 60) + $mP);
            }
        }
        if ($metaAtual === 0 && $trabalhados === 0) $novoSaldoDia = 0;

        // 5. ATUALIZAÇÃO DELTA DO BANCO DE DADOS (O Segredo)
        // Calculamos a diferença que esse ponto gerou e aplicamos ao total do usuário
        $delta = $novoSaldoDia - $saldoAntigoDia;

        $pdo->beginTransaction();

        $jsonHor = json_encode($horarios);
        $jsonJust = json_encode($listaJust, JSON_UNESCAPED_UNICODE);

        if ($registro) {
            $stmtUp = $pdo->prepare("UPDATE controle_ponto SET horarios = ?, justificativas = ?, saldo_minutos = ?, meta_minutos = ? WHERE id = ?");
            $stmtUp->execute([$jsonHor, $jsonJust, $novoSaldoDia, $metaAtual, $id_controle]);
        } else {
            $stmtIns = $pdo->prepare("INSERT INTO controle_ponto (usuario_id, data_registro, horarios, justificativas, saldo_minutos, meta_minutos, observacao) VALUES (?, ?, ?, ?, ?, ?, '')");
            $stmtIns->execute([$uid, $dataHoje, $jsonHor, $jsonJust, $novoSaldoDia, $metaAtual]);
        }

        // Atualiza o saldo total do usuário com a diferença
        if ($delta !== 0) {
            $upUser = $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = banco_atual_minutos + ? WHERE id = ?");
            $upUser->execute([$delta, $uid]);
        }

        $pdo->commit();
        echo json_encode(['status' => 'sucesso', 'msg' => 'Registrado: ' . $horaAgora, 'horarios' => $horarios]);
    }

    // =================================================================================
    // 3. EDIÇÃO MANUAL / GESTÃO / DASHBOARD (MANTIDOS)
    // =================================================================================
    
    elseif ($acao === 'salvar_ponto') { 
        $uid = $input['usuario_id'];
        $data = $input['data'];
        $horarios = json_encode($input['horarios']); 
        $meta = $input['meta'];
        $saldo = $input['saldo'];
        
        $txtJust = $input['justificativa_nova'] ?? ($input['obs'] ?? '');
        $jsonJust = null;
        
        if(!empty($txtJust)) {
            // Busca existente
            $check = $pdo->prepare("SELECT justificativas FROM controle_ponto WHERE usuario_id = ? AND data_registro = ?");
            $check->execute([$uid, $data]);
            $existente = $check->fetchColumn();
            
            $lista = array_fill(0, 8, "");
            if($existente) {
                $dec = json_decode($existente, true);
                if(is_array($dec)) $lista = $dec;
            }
            
            // Adiciona no primeiro slot livre ou no 0
            if(empty($lista[0])) $lista[0] = $txtJust;
            else $lista[0] .= " | " . $txtJust;
            
            $jsonJust = json_encode($lista, JSON_UNESCAPED_UNICODE);
        }

        if ($jsonJust) {
            $sql = "INSERT INTO controle_ponto (usuario_id, data_registro, horarios, justificativas, meta_minutos, saldo_minutos) 
                    VALUES (:uid, :data, :hor, :jus, :meta, :saldo) 
                    ON DUPLICATE KEY UPDATE horarios = :hor, justificativas = :jus, meta_minutos = :meta, saldo_minutos = :saldo";
            $params = [':uid'=>$uid, ':data'=>$data, ':hor'=>$horarios, ':jus'=>$jsonJust, ':meta'=>$meta, ':saldo'=>$saldo];
        } else {
            $sql = "INSERT INTO controle_ponto (usuario_id, data_registro, horarios, meta_minutos, saldo_minutos) 
                    VALUES (:uid, :data, :hor, :meta, :saldo) 
                    ON DUPLICATE KEY UPDATE horarios = :hor, meta_minutos = :meta, saldo_minutos = :saldo";
            $params = [':uid'=>$uid, ':data'=>$data, ':hor'=>$horarios, ':meta'=>$meta, ':saldo'=>$saldo];
        }

        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
        echo json_encode(['status' => 'sucesso', 'msg' => 'Salvo com sucesso']);
    }

    elseif ($acao === 'listar_usuarios_rh') {
        $hoje = date('Y-m-d');
        
        // CORREÇÃO: Adicionamos o filtro "WHERE u.id NOT IN (11, 16)"
        // Isso diz ao banco: "Traga todos, EXCETO o 11 e o 16".
        
        $sql = "SELECT 
                    u.id, 
                    u.nome, 
                    u.aniversario, 
                    u.telefone, 
                    u.funcao as cargo, 
                    u.nivel_acesso,
                    u.banco_atual_minutos as banco, 
                    (SELECT COUNT(*) FROM controle_ponto WHERE usuario_id = u.id AND data_registro = '$hoje') as presente_hoje
                FROM usuarios u 
                WHERE u.id NOT IN (11, 16) 
                ORDER BY u.nome ASC";
                
        // Executa a consulta
        try {
            $stmt = $pdo->query($sql);
            echo json_encode(['status' => 'sucesso', 'data' => $stmt->fetchAll(PDO::FETCH_ASSOC)]);
        } catch (PDOException $e) {
            // Se der erro, mostra no console
            echo json_encode(['status' => 'erro', 'msg' => $e->getMessage()]);
        }
        exit;
    }
    // --- LISTAR HISTÓRICO PARA CÁLCULO REAL NO JS ---
    elseif ($acao === 'listar_tudo_para_calculo') {
        try {
            // --- A SOLUÇÃO "FORÇA BRUTA" ---
            // Usamos SELECT * para garantir que NENHUMA coluna fique de fora.
            // Isso resolve o problema de 'observacao' não chegar no JavaScript.
            $sql = "SELECT * FROM controle_ponto WHERE 1"; 
            
            $stmt = $pdo->query($sql);
            $dados = $stmt->fetchAll(PDO::FETCH_ASSOC);

            // --- PROTEÇÃO CONTRA TEXTO QUEBRADO (IMPORTANTE) ---
            // Se houver caracteres estranhos na observação, o json_encode pode falhar silenciosamente.
            // Vamos garantir que o JSON saia perfeito.
            $json = json_encode(['status' => 'sucesso', 'dados' => $dados], JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR);
            
            if ($json === false) {
                // Se falhar o encode, manda erro para sabermos
                echo json_encode(['status' => 'erro', 'msg' => 'Erro JSON: ' . json_last_error_msg()]);
            } else {
                echo $json;
            }

        } catch (PDOException $e) {
            echo json_encode(['status' => 'erro', 'msg' => $e->getMessage()]);
        }
    }

    elseif ($acao === 'historico_completo') {
        $uid = $input['usuario_id'];
        $sql = "SELECT * FROM controle_ponto WHERE usuario_id = ? ORDER BY data_registro DESC";
        $stmt = $pdo->prepare($sql);
        $stmt->execute([$uid]);
        $historico = $stmt->fetchAll(PDO::FETCH_ASSOC);

        foreach($historico as &$row) {
            if (isset($row['justificativas']) && !empty($row['justificativas'])) {
                $jArr = json_decode($row['justificativas'], true);
                if (is_array($jArr)) {
                    $reais = array_filter($jArr, function($val) { return !empty($val); });
                    $row['observacao'] = implode(" | ", $reais);
                }
            }
        }

        $stmtSum = $pdo->prepare("SELECT SUM(saldo_minutos) as total_geral FROM controle_ponto WHERE usuario_id = ?");
        $stmtSum->execute([$uid]);
        $resSum = $stmtSum->fetch(PDO::FETCH_ASSOC);
        echo json_encode(['status' => 'sucesso', 'historico' => $historico, 'saldo_total' => (int)($resSum['total_geral'] ?? 0)]);
    }
    
    elseif ($acao === 'dados_dashboard_completo') {
        $mesRef = $input['mes'] ?? date('m'); $anoRef = $input['ano'] ?? date('Y'); $filtroData = "$anoRef-$mesRef";
        $sqlRelatorios = "SELECT COUNT(DISTINCT u.id) as total_funcionarios, SUM(CASE WHEN p.saldo_minutos > 0 THEN p.saldo_minutos ELSE 0 END) as total_positivo, SUM(CASE WHEN p.saldo_minutos < 0 THEN p.saldo_minutos ELSE 0 END) as total_negativo FROM usuarios u LEFT JOIN controle_ponto p ON u.id = p.usuario_id WHERE u.funcao != 'Desenvolvedor'";
        $stmtRel = $pdo->query($sqlRelatorios);
        $dadosRelatorios = $stmtRel->fetch(PDO::FETCH_ASSOC);
        $sqlCalendario = "SELECT 
                            p.data_registro, 
                            COUNT(DISTINCT CASE WHEN p.horarios NOT LIKE '%F%rias%' THEN p.usuario_id END) as qtd_presentes, 
                            GROUP_CONCAT(DISTINCT CASE WHEN p.horarios NOT LIKE '%F%rias%' THEN u.nome END SEPARATOR ', ') as nomes_presentes, 
                            COUNT(DISTINCT CASE WHEN p.horarios LIKE '%F%rias%' THEN p.usuario_id END) as qtd_ferias, 
                            GROUP_CONCAT(DISTINCT CASE WHEN p.horarios LIKE '%F%rias%' THEN u.nome END SEPARATOR ', ') as nomes_ferias 
                          FROM controle_ponto p 
                          JOIN usuarios u ON u.id = p.usuario_id 
                          WHERE p.data_registro LIKE '$filtroData%' 
                          GROUP BY p.data_registro";
        $stmtCal = $pdo->query($sqlCalendario);
        $dadosCalendario = $stmtCal->fetchAll(PDO::FETCH_ASSOC);
        echo json_encode(['status' => 'sucesso', 'relatorios' => $dadosRelatorios, 'calendario' => $dadosCalendario]);
    }

    elseif ($acao === 'lancar_ajuste') {
        $uid = $input['usuario_id'];
        $dataInicial = $input['data'];
        $dias = (int)($input['qtde_dias'] ?? 1);
        $tipo = $input['tipo']; 
        $obs = $input['obs'] ?? '';
        
        // Pega valor do JS
        $saldoInputJS = isset($input['saldo_minutos']) ? intval($input['saldo_minutos']) : 0;

        $stmtCheck = $pdo->prepare("SELECT id, horarios, saldo_minutos, meta_minutos, observacao FROM controle_ponto WHERE usuario_id = ? AND data_registro = ?");
        $stmtUpsert = $pdo->prepare("INSERT INTO controle_ponto (usuario_id, data_registro, horarios, meta_minutos, saldo_minutos, observacao) 
                                     VALUES (:uid, :data, :hor, :meta, :saldo, :obs) 
                                     ON DUPLICATE KEY UPDATE horarios = :hor, meta_minutos = :meta, saldo_minutos = :saldo, observacao = :obs");
        $stmtUpdateBanco = $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = banco_atual_minutos + ? WHERE id = ?");

        $pdo->beginTransaction();

        try {
            for ($i = 0; $i < $dias; $i++) {
                $dataAtual = date('Y-m-d', strtotime($dataInicial . " + $i days"));
                
                $stmtCheck->execute([$uid, $dataAtual]);
                $existente = $stmtCheck->fetch(PDO::FETCH_ASSOC);
                $saldoAntigoNoBanco = $existente ? intval($existente['saldo_minutos']) : 0;
                
                // Configuração Padrão: VAZIO para liberar o ponto
                $horariosFinais = array_fill(0, 8, ""); 
                $metaFinal = 0;
                $saldoFinal = 0;
                $obsFinal = $obs;

                if ($tipo === 'Ajuste Manual') {
                    // Mantém horários existentes se houver trabalho
                    if ($existente) {
                        $hDb = json_decode($existente['horarios'], true);
                        if (is_array($hDb)) $horariosFinais = $hDb;
                        $metaFinal = intval($existente['meta_minutos']);
                        
                        if (!empty($existente['observacao'])) {
                            if (strpos($existente['observacao'], $obs) === false) $obsFinal = $existente['observacao'] . " | " . $obs;
                            else $obsFinal = $existente['observacao'];
                        }
                    } else {
                        // Se é dia novo, NÃO escrevemos nada nos horários.
                        // O dia fica livre para o funcionário bater ponto.
                        // Apenas a observação e o saldo mudam.
                        
                        // Define meta 0 ou 480 (CLT) só pra constar, mas o saldo é o que importa
                        $diaSem = date('w', strtotime($dataAtual));
                        $stmtNivel = $pdo->prepare("SELECT nivel_acesso FROM usuarios WHERE id = ?");
                        $stmtNivel->execute([$uid]);
                        $nivel = $stmtNivel->fetchColumn();
                        if ($nivel !== 'horista' && $diaSem != 0) $metaFinal = ($diaSem == 6) ? 240 : 480;
                    }
                    
                    // SOMA: Saldo Antigo + Ajuste Novo
                    $saldoFinal = $saldoAntigoNoBanco + $saldoInputJS;
                } 
                // Faltas e Atestados continuam bloqueando
                elseif (strpos($tipo, 'Falta') !== false) {
                
                // 1. Define a META do dia específico (Inteligência de Calendário)
                $diaSemana = date('w', strtotime($dataAtual)); // 0=Dom, 6=Sáb
                
                $metaDoDia = 480; // Padrão Dia Útil
                if ($diaSemana == 6) $metaDoDia = 240; // Sábado é 4h
                if ($diaSemana == 0) $metaDoDia = 0;   // Domingo é 0h
                
                // 2. Tenta recuperar o que já existia
                $hAnt = ["", "", "", "", "", "", "", ""];
                if ($existente && !empty($existente['horarios'])) {
                    $tmp = json_decode($existente['horarios'], true);
                    if (!is_array($tmp)) $tmp = json_decode(stripslashes($existente['horarios']), true);
                    if (is_array($tmp)) $hAnt = $tmp;
                }

                // 3. Aplica a Falta
                if ($tipo === 'Falta Tarde') {
                    $horariosFinais = [$hAnt[0], $hAnt[1], "Falta", "Tarde", "", "", "", ""];
                    $saldoFinal = -240; // Parcial é fixo em 4h (ou metade da meta?) Vamos fixar 4h para simplificar.
                } 
                elseif ($tipo === 'Falta Manha') {
                    $horariosFinais = ["Falta", "Manhã", $hAnt[2], $hAnt[3], "", "", "", ""];
                    $saldoFinal = -240; 
                } 
                else {
                    // Falta Integral: Desconta a META DO DIA
                    $horariosFinais = ["Falta", "Integral", "", "", "", "", "", ""];
                    $saldoFinal = -$metaDoDia; // Se for Sábado, desconta só 240. Se Domingo, 0.
                }
            } 
                elseif (in_array($tipo, ['Atestado', 'Férias', 'Folga'])) {
                    $saldoFinal = 0; $metaFinal = 0;
                    $horariosFinais = [$tipo, "Integral", "", "", "", "", "", ""];
                }

                $stmtUpsert->execute([
                    ':uid' => $uid, ':data' => $dataAtual, ':hor' => json_encode($horariosFinais),
                    ':meta' => $metaFinal, ':saldo' => $saldoFinal, ':obs' => $obsFinal
                ]);

                $delta = $saldoFinal - $saldoAntigoNoBanco;
                if ($delta !== 0) $stmtUpdateBanco->execute([$delta, $uid]);
            }
            
            $pdo->commit();
            echo json_encode(['status' => 'sucesso', 'msg' => 'Ajuste salvo! Ponto liberado.']);

        } catch (Exception $e) {
            $pdo->rollBack();
            echo json_encode(['status' => 'erro', 'msg' => $e->getMessage()]);
        }
    }

    elseif ($acao === 'pagar_horas') {
        $uid = intval($input['usuario_id'] ?? 0);
        $data = $input['data'];
        $horasStr = trim($input['horas']); 
        $obsUser = trim($input['obs'] ?? '');

        // 1. Converte HH:MM para minutos
        $partes = explode(':', $horasStr);
        $h = intval(preg_replace('/[^0-9]/', '', $partes[0] ?? '0')); 
        $m = intval(preg_replace('/[^0-9]/', '', $partes[1] ?? '0')); 
        $minutosPagos = ($h * 60) + $m;

        if ($uid <= 0 || $minutosPagos <= 0) {
            echo json_encode(['status' => 'erro', 'msg' => 'Valor inválido ou zerado.']);
            exit;
        }

        try {
            $pdo->beginTransaction();

            // 2. A MÁGICA DA "SENHA" PARA O CÁLCULO JS
            // O Javascript procura EXATAMENTE "PG: 10:00" para fazer a dedução na hora de somar!
            $tagPg = "PG: " . $horasStr;
            $obsFinal = $obsUser ? "$tagPg | $obsUser" : $tagPg;
            
            // Coloca a palavra PAGAMENTO no primeiro slot para a tela de Gerir ficar verde!
            $horariosJson = json_encode(['PAGAMENTO', '', '', '', '', '', '', '']);
            
            // O saldo fica negativo no histórico
            $saldoHistorico = $minutosPagos * -1; 

            // 3. REGISTRA NO HISTÓRICO
            $sqlHist = "INSERT INTO controle_ponto (usuario_id, data_registro, horarios, saldo_minutos, meta_minutos, observacao) 
                        VALUES (:uid, :data, :hor, :saldo, 0, :obs)
                        ON DUPLICATE KEY UPDATE 
                        saldo_minutos = saldo_minutos + :saldo, 
                        observacao = CONCAT(observacao, ' | ', :obs),
                        horarios = :hor";
            
            $stmtHist = $pdo->prepare($sqlHist);
            $stmtHist->execute([
                ':uid' => $uid,
                ':data' => $data,
                ':hor' => $horariosJson,
                ':saldo' => $saldoHistorico,
                ':obs' => $obsFinal
            ]);

            // 4. ATUALIZA O SALDO REAL IMEDIATAMENTE NO BANCO
            $stmtUpd = $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = banco_atual_minutos - ? WHERE id = ?");
            $stmtUpd->execute([$minutosPagos, $uid]);

            $pdo->commit();
            echo json_encode(['status' => 'sucesso', 'msg' => 'Pagamento registrado com sucesso!']);

        } catch (Exception $e) {
            $pdo->rollBack();
            echo json_encode(['status' => 'erro', 'msg' => 'Erro ao processar: ' . $e->getMessage()]);
        }
        exit;
    }
    // LER PONTOS DO USUÁRIO (MODAL GESTOR) - CORRIGIDO
    elseif ($acao === 'ler_pontos_usuario') {
        $uid = $input['usuario_id'];
        
        // Mantemos o SELECT * para garantir que tudo venha do banco
        $stmt = $pdo->prepare("SELECT * FROM controle_ponto WHERE usuario_id = ? ORDER BY data_registro ASC");
        $stmt->execute([$uid]);
        $dados = $stmt->fetchAll(PDO::FETCH_ASSOC);

        // Tratamento das Justificativas (SEM APAGAR O PAGAMENTO)
        foreach($dados as &$row) {
            $obsBanco = $row['observacao'] ?? ''; // Pega o que está no banco (Onde vive o PG:)
            $justificativaTexto = '';

            if (isset($row['justificativas']) && !empty($row['justificativas'])) {
                $jArr = json_decode($row['justificativas'], true);
                if (is_array($jArr)) {
                    $reais = array_filter($jArr, function($val) { return !empty($val); });
                    $justificativaTexto = implode(" | ", $reais);
                }
            }

            // --- A CORREÇÃO MÁGICA ---
            // Se tiver justificativa, nós JUNTAMOS com a observação do banco.
            // Assim o "PG: 136:00" sobrevive e chega no Javascript.
            if (!empty($justificativaTexto)) {
                $row['observacao'] = $obsBanco . " | " . $justificativaTexto;
            } else {
                $row['observacao'] = $obsBanco;
            }
        }
        
        // Adicionei proteção UTF-8 para garantir que não quebre com acentos
        echo json_encode(['status' => 'sucesso', 'dados' => $dados], JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR);
    }

    elseif ($acao === 'atualizar_registro_gestor') {
        $idReg = $input['id_registro'] ?? null;
        $novosHorarios = json_encode($input['novos_horarios']);
        $novoSaldo = intval($input['novo_saldo']); 
        $novaObs = $input['nova_obs'];
        
        $uid = $input['usuario_id'] ?? null;
        $dataRef = $input['data'] ?? null;

        $pdo->beginTransaction();

        try {
            // 1. Descobre quanto o dia valia ANTES
            $saldoAntigo = 0;
            if ($idReg && $idReg !== 'null') {
                $stmtGet = $pdo->prepare("SELECT saldo_minutos FROM controle_ponto WHERE id = ?");
                $stmtGet->execute([$idReg]);
                $saldoAntigo = intval($stmtGet->fetchColumn() ?: 0);
                
                // Update
                $stmt = $pdo->prepare("UPDATE controle_ponto SET horarios = ?, saldo_minutos = ?, observacao = ? WHERE id = ?");
                $stmt->execute([$novosHorarios, $novoSaldo, $novaObs, $idReg]);
            } else {
                // Insert (dia novo)
                $stmt = $pdo->prepare("INSERT INTO controle_ponto (usuario_id, data_registro, horarios, saldo_minutos, meta_minutos, observacao) VALUES (?, ?, ?, ?, ?, ?)");
                $stmt->execute([$uid, $dataRef, $novosHorarios, $novoSaldo, 480, $novaObs]);
            }

            // 2. ATUALIZA O BANCO TOTAL (ESTORNO)
            // Se limpou o dia, novoSaldo é 0.
            // Se o dia tinha -480 (falta), Delta = 0 - (-480) = +480. O banco recupera 8h.
            $delta = $novoSaldo - $saldoAntigo;

            if ($delta !== 0 && $uid) {
                $updUser = $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = banco_atual_minutos + ? WHERE id = ?");
                $updUser->execute([$delta, $uid]);
            }

            $pdo->commit();
            echo json_encode(['status' => 'sucesso']);

        } catch (Exception $e) {
            $pdo->rollBack();
            echo json_encode(['status' => 'erro', 'msg' => $e->getMessage()]);
        }
    }

    elseif ($acao === 'checar_permissao') {
        $uid = $input['usuario_id'];
        $stmt = $pdo->prepare("SELECT nivel_acesso FROM usuarios WHERE id = ?");
        $stmt->execute([$uid]);
        $nivel = $stmt->fetchColumn();
        
        echo json_encode(['status' => 'sucesso', 'nivel' => $nivel]);
    }

    // --- TRECHO OBRIGATÓRIO: SALVAR TELEFONE ---
    elseif ($acao === 'atualizar_telefone') {
        $uid = $input['usuario_id'];
        $tel = $input['telefone'];
        
        // Remove formatação para salvar limpo (opcional, mas bom)
        $telLimpo = preg_replace('/[^0-9]/', '', $tel);
        
        $stmt = $pdo->prepare("UPDATE usuarios SET telefone = ? WHERE id = ?");
        $stmt->execute([$telLimpo, $uid]);
        echo json_encode(['status' => 'sucesso', 'msg' => 'Telefone salvo!']);
    }

    // --- NOVO: SALVAR ANIVERSÁRIO ---
    elseif ($acao === 'atualizar_aniversario') {
        $uid = $input['usuario_id'];
        $niver = $input['niver']; // Espera algo como "20/01"
        
        // Limpeza básica: Garante que só tenha números e barra
        // E limita a 5 caracteres (dd/mm)
        $niverLimpo = substr(preg_replace('/[^0-9\/]/', '', $niver), 0, 5);
        
        $stmt = $pdo->prepare("UPDATE usuarios SET aniversario = ? WHERE id = ?");
        $stmt->execute([$niverLimpo, $uid]);
        echo json_encode(['status' => 'sucesso', 'msg' => 'Aniversário salvo!']);
    }
    

    elseif ($acao === 'admin_recalcular_horistas') {
        
        // 1. BUSCA ESPECÍFICA (COM TRIM PARA EVITAR ESPAÇOS)
        $stmt = $pdo->prepare("SELECT id, nome FROM usuarios WHERE TRIM(nome) = 'Teste'");
        $stmt->execute();
        $users = $stmt->fetchAll(PDO::FETCH_ASSOC);

        if (count($users) === 0) {
            echo json_encode(['status' => 'erro', 'msg' => 'ERRO: Usuário "Teste" não encontrado no banco. Verifique espaços no nome.']);
            exit;
        }

        $relatorio = [];
        $diasAlterados = 0;

        foreach ($users as $user) {
            $uid = $user['id'];
            $nome = $user['nome'];
            $relatorio[] = "Usuário: $nome (ID $uid)";

            // 2. BUSCA OS PONTOS
            $stmtPonto = $pdo->prepare("SELECT id, data_registro, horarios, saldo_minutos FROM controle_ponto WHERE usuario_id = ? ORDER BY data_registro DESC LIMIT 5"); 
            // LIMIT 5 para não estourar o alerta, vamos focar nos últimos dias
            $stmtPonto->execute([$uid]);
            $dias = $stmtPonto->fetchAll(PDO::FETCH_ASSOC);

            foreach ($dias as $dia) {
                $data = date('d/m', strtotime($dia['data_registro']));
                
                // 3. TENTATIVA DE LEITURA (JSON)
                $raw = $dia['horarios'];
                $horarios = json_decode($raw, true);
                
                // Debug de JSON Sujo
                if (!is_array($horarios)) {
                    $horarios = json_decode(stripslashes($raw), true);
                }
                if (!is_array($horarios)) {
                    $clean = str_replace(['\\', '"'], '', $raw); // Tenta limpar na força bruta
                    // Se falhar aqui, o problema é o formato do banco
                }

                if (!is_array($horarios)) {
                    $relatorio[] = "[$data] ERRO JSON";
                    continue;
                }

                // 4. CÁLCULO MINUTO A MINUTO
                $trabalhado = 0;
                for ($i = 0; $i < 8; $i += 2) {
                    $ent = $horarios[$i] ?? null;
                    $sai = $horarios[$i+1] ?? null;
                    if ($ent && $sai && $ent != 'FALTA' && $sai != 'FALTA') {
                        list($h1, $m1) = explode(':', $ent);
                        list($h2, $m2) = explode(':', $sai);
                        $minE = ($h1 * 60) + $m1;
                        $minS = ($h2 * 60) + $m2;
                        if ($minS > $minE) $trabalhado += ($minS - $minE);
                    }
                }

                // 5. ATUALIZAÇÃO E RELATÓRIO
                // Força Meta 0 e Saldo = Trabalhado
                $upd = $pdo->prepare("UPDATE controle_ponto SET saldo_minutos = ?, meta_minutos = 0 WHERE id = ?");
                $upd->execute([$trabalhado, $dia['id']]);
                
                $diasAlterados++;
                $relatorio[] = "[$data] Trab: $trabalhado | Saldo Antigo: {$dia['saldo_minutos']} -> Novo: $trabalhado";
            }
        }

        // MONTA A MENSAGEM PARA VOCÊ LER
        $msgFinal = implode("\n", $relatorio);
        echo json_encode(['status' => 'sucesso', 'msg' => "DIAGNÓSTICO:\n" . $msgFinal, 'afetados' => $diasAlterados]);
        exit;
    }

    // --- LIMPEZA DE INTERVALO (EXCLUIR EVENTO EM MASSA) ---
    elseif ($acao === 'excluir_evento_intervalo') {
        
        // Garante leitura dos dados
        if (empty($dados)) {
            $dados = json_decode(file_get_contents('php://input'), true);
        }
        // Lê tanto de $dados quanto de $input para garantir
        $uid = $dados['usuario_id'] ?? $input['usuario_id'] ?? null;
        $inicio = $dados['data_inicio'] ?? $input['data_inicio'] ?? null;
        $fim = $dados['data_fim'] ?? $input['data_fim'] ?? null;

        if (!$uid || !$inicio) {
            echo json_encode(['status' => 'erro', 'msg' => "Dados incompletos."]);
            exit;
        }
        if (!$fim) $fim = $inicio; 

        try {
            $pdo->beginTransaction();

            // 1. CALCULA O SALDO QUE SERÁ APAGADO (Para estornar do total)
            $stmtSum = $pdo->prepare("SELECT SUM(saldo_minutos) FROM controle_ponto WHERE usuario_id = ? AND data_registro BETWEEN ? AND ?");
            $stmtSum->execute([$uid, $inicio, $fim]);
            $saldoParaRemover = intval($stmtSum->fetchColumn() ?: 0);

            // 2. DELETE OS DIAS
            $stmtDel = $pdo->prepare("DELETE FROM controle_ponto WHERE usuario_id = ? AND data_registro BETWEEN ? AND ?");
            $stmtDel->execute([$uid, $inicio, $fim]);
            $afetados = $stmtDel->rowCount();

            // 3. ATUALIZA O BANCO TOTAL (Estorno)
            // Se apagamos dias que somavam +100, temos que subtrair 100 do banco.
            // Se apagamos dias que somavam -100 (faltas), temos que somar 100 (subtrair negativo).
            if ($saldoParaRemover !== 0) {
                $updUser = $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = banco_atual_minutos - ? WHERE id = ?");
                $updUser->execute([$saldoParaRemover, $uid]);
            }

            $pdo->commit();
            echo json_encode(['status' => 'sucesso', 'msg' => "Limpeza concluída! $afetados dias apagados."]);

        } catch (Exception $e) {
            $pdo->rollBack();
            echo json_encode(['status' => 'erro', 'msg' => "Erro Banco: " . $e->getMessage()]);
        }
    }

    // --- AÇÃO DE SINCRONIZAÇÃO FORÇADA (NOVO) ---
    elseif ($acao === 'forcar_sincronia_total') {
        $uid = $dados['usuario_id'];
        $novoSaldo = intval($dados['saldo_calculado_admin']);
        
        // Grava o valor na marra. Sem perguntas.
        $stmt = $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = ? WHERE id = ?");
        $stmt->execute([$novoSaldo, $uid]);
        
        echo json_encode(['status' => 'sucesso', 'msg' => 'Saldo travado.']);
        exit;
    }

    // --- NOVO: VISÃO GERAL BASEADA NA TABELA REAL ---
    elseif ($acao === 'listar_dados_visao_geral') {
        
        // 1. Busca todos os usuários ativos
        $sqlUsers = "SELECT id, nome, funcao as cargo, telefone, aniversario, nivel_acesso 
                     FROM usuarios 
                     WHERE status = 'ativo' AND nivel_acesso != 'admin' 
                     ORDER BY nome ASC";
        $stmtUsers = $pdo->query($sqlUsers);
        $usuarios = $stmtUsers->fetchAll(PDO::FETCH_ASSOC);

        // 2. Busca O VALOR VERDADEIRO da tabela nova (saldo_real_admin)
        // Isso garante que leremos o valor 7282 (121:22) que você viu no banco
        $pdo->exec("CREATE TABLE IF NOT EXISTS saldo_real_admin (
            id INT AUTO_INCREMENT PRIMARY KEY,
            usuario_id INT NOT NULL,
            saldo_atual_minutos INT DEFAULT 0,
            ultima_atualizacao DATETIME DEFAULT CURRENT_TIMESTAMP,
            UNIQUE KEY unique_user (usuario_id)
        )");
        
        $sqlSaldos = "SELECT usuario_id, saldo_atual_minutos FROM saldo_real_admin";
        $stmtSaldos = $pdo->query($sqlSaldos);
        
        // Cria um mapa no PHP: [ID 39 => 7282]
        $mapaSaldos = [];
        while ($row = $stmtSaldos->fetch(PDO::FETCH_ASSOC)) {
            $mapaSaldos[$row['usuario_id']] = intval($row['saldo_atual_minutos']);
        }

        // 3. Busca saldos do histórico (Apenas para quem NÃO tem pagamento/sincronia)
        // Isso serve para quem não está na tabela 'saldo_real_admin'
        $sqlHist = "SELECT usuario_id, SUM(saldo_minutos) as total FROM controle_ponto GROUP BY usuario_id";
        $stmtHist = $pdo->query($sqlHist);
        $mapaHistorico = [];
        while ($rowH = $stmtHist->fetch(PDO::FETCH_ASSOC)) {
            $mapaHistorico[$rowH['usuario_id']] = intval($rowH['total']);
        }

        // 4. Busca presenças de hoje (para o ícone verde/vermelho)
        $hoje = date('Y-m-d');
        $stmtP = $pdo->prepare("SELECT usuario_id FROM controle_ponto WHERE data_registro = ?");
        $stmtP->execute([$hoje]);
        $presentes = $stmtP->fetchAll(PDO::FETCH_COLUMN);

        // 5. MISTURA FINAL (AQUI É ONDE O ERRO MORRE)
        foreach($usuarios as &$user) {
            $uid = $user['id'];

            // REGRA ABSOLUTA:
            // Se o ID existe na tabela 'saldo_real_admin' (ex: ID 39), USA AQUELE VALOR.
            // Ignora qualquer cálculo antigo.
            if (isset($mapaSaldos[$uid])) {
                $user['saldo_admin'] = $mapaSaldos[$uid]; // Vai pegar 121:22
            } 
            // Se não, tenta o histórico
            elseif (isset($mapaHistorico[$uid])) {
                $user['saldo_admin'] = $mapaHistorico[$uid];
            } 
            else {
                $user['saldo_admin'] = 0;
            }

            $user['presente_hoje'] = in_array($uid, $presentes) ? 1 : 0;
        }

        echo json_encode(['status' => 'sucesso', 'dados' => $usuarios]);
    }

    // --- NOVO: PAGAR E GRAVAR O SALDO ABSOLUTO NA TABELA REAL ---
    elseif ($acao === 'pagar_horas_real') {
        $uid = $input['usuario_id'];
        $minutosDebitar = intval($input['minutos_debitar']); 
        $obs = $input['obs'];
        $dataPag = $input['data'];
        $textoHoras = $input['horas_texto'];
        $saldoTela = intval($input['saldo_atual_absoluto']); 

        try {
            $pdo->beginTransaction();

            // Garante tabela
            $pdo->exec("CREATE TABLE IF NOT EXISTS saldo_real_admin (
                id INT AUTO_INCREMENT PRIMARY KEY,
                usuario_id INT NOT NULL,
                saldo_atual_minutos INT DEFAULT 0,
                ultima_atualizacao DATETIME DEFAULT CURRENT_TIMESTAMP,
                UNIQUE KEY unique_user (usuario_id)
            )");

            $stmtCheck = $pdo->prepare("SELECT saldo_atual_minutos FROM saldo_real_admin WHERE usuario_id = ?");
            $stmtCheck->execute([$uid]);
            $exists = $stmtCheck->fetch(PDO::FETCH_ASSOC);

            if ($exists) {
                $novoSaldo = intval($exists['saldo_atual_minutos']) - $minutosDebitar;
            } else {
                $novoSaldo = $saldoTela - $minutosDebitar;
            }

            $sqlUpsert = "INSERT INTO saldo_real_admin (usuario_id, saldo_atual_minutos, ultima_atualizacao) 
                          VALUES (?, ?, NOW()) 
                          ON DUPLICATE KEY UPDATE saldo_atual_minutos = ?, ultima_atualizacao = NOW()";
            $stmtUp = $pdo->prepare($sqlUpsert);
            $stmtUp->execute([$uid, $novoSaldo, $novoSaldo]);

            $obsFinal = "PG: $textoHoras | $obs";
            $sqlHist = "INSERT INTO controle_ponto (usuario_id, data_registro, horarios, saldo_minutos, meta_minutos, observacao)
                        VALUES (?, ?, ?, 0, 0, ?)";
            $jsonHorarios = json_encode(array_fill(0, 8, ""));
            $stmtHist = $pdo->prepare($sqlHist);
            $stmtHist->execute([$uid, $dataPag, $jsonHorarios, $obsFinal]);

            $pdo->commit();
            echo json_encode(['status' => 'sucesso', 'novo_saldo' => $novoSaldo]);

        } catch (Exception $e) {
            $pdo->rollBack();
            echo json_encode(['status' => 'erro', 'msg' => $e->getMessage()]);
        }
    }

    // --- NOVO: SALVAR FALTA/EDIÇÃO DO ADMIN (COM META 480 PARA DESCONTO) ---
    elseif ($acao === 'salvar_ponto_admin') {
        $uid = intval($input['usuario_id'] ?? 0);
        $data = $input['data'];
        $horariosArr = $input['horarios']; 
        $obs = $input['observacao'];
        $tipoDia = $input['tipo_especial'] ?? 'N'; // S, F ou N

        if ($uid <= 0) { echo json_encode(['status' => 'erro', 'msg' => "ID inválido."]); exit; }

        try {
            // 1. ANÁLISE DO TEXTO (FÉRIAS/ATESTADO)
            // Se tiver escrito Férias, Folga ou Atestado, a meta morre (Zero).
            $primeiroSlot = mb_strtoupper($horariosArr[0] ?? '', 'UTF-8');
            $ehImune = (strpos($primeiroSlot, 'FÉRIAS') !== false || strpos($primeiroSlot, 'FERIAS') !== false || 
                        strpos($primeiroSlot, 'ATESTADO') !== false || strpos($primeiroSlot, 'FOLGA') !== false || 
                        strpos($primeiroSlot, 'LICENÇA') !== false);

            // 2. CÁLCULO DO TRABALHO
            $trabalhado = 0;
            for ($i = 0; $i < 8; $i += 2) {
                $e = $horariosArr[$i] ?? ''; $s = $horariosArr[$i+1] ?? '';
                if ($e && $s && strpos($e, ':') && strpos($s, ':')) {
                    list($h1, $m1) = explode(':', $e); list($h2, $m2) = explode(':', $s);
                    $minE = ($h1 * 60) + $m1; $minS = ($h2 * 60) + $m2;
                    if ($minS > $minE) $trabalhado += ($minS - $minE);
                }
            }

            // 3. DEFINIÇÃO DA META (A LÓGICA CORRETA)
            $diaSemana = date('w', strtotime($data)); // 0=Dom, 6=Sab
            $meta = 480; // Padrão

            // Hierarquia de Poder:
            if ($ehImune) {
                $meta = 0; // Férias vence tudo
            } elseif ($tipoDia === 'S' || $tipoDia === 'F') {
                $meta = 0; // Regra manual vence dia útil
            } elseif ($diaSemana == 6) {
                $meta = 240; // Sábado é 4h (se não for férias)
            } elseif ($diaSemana == 0) {
                $meta = 0; // Domingo é 0h
            }

            // 4. CÁLCULO DO SALDO
            $saldoDia = 0;
            if ($tipoDia === 'F') { // Feriado Manual (Dobra)
                $saldoDia = $trabalhado * 2;
            } else {
                $saldoBruto = $trabalhado - $meta;
                // Tolerância 10 min
                if (abs($saldoBruto) <= 10) $saldoDia = 0;
                else $saldoDia = $saldoBruto;
            }

            // 5. GRAVA NO BANCO (AGORA COM OS VALORES CERTOS)
            $stmtCheck = $pdo->prepare("SELECT id FROM controle_ponto WHERE usuario_id = ? AND data_registro = ?");
            $stmtCheck->execute([$uid, $data]);
            $idExistente = $stmtCheck->fetchColumn();

            $horariosJson = json_encode($horariosArr);

            if ($idExistente) {
                $sql = "UPDATE controle_ponto SET horarios = ?, observacao = ?, saldo_minutos = ?, meta_minutos = ? WHERE id = ?";
                $pdo->prepare($sql)->execute([$horariosJson, $obs, $saldoDia, $meta, $idExistente]);
            } else {
                $sql = "INSERT INTO controle_ponto (usuario_id, data_registro, horarios, observacao, saldo_minutos, meta_minutos) VALUES (?, ?, ?, ?, ?, ?)";
                $pdo->prepare($sql)->execute([$uid, $data, $horariosJson, $obs, $saldoDia, $meta]);
            }

            // 6. ATUALIZA TOTAL
            atualizar_saldo_mestre($pdo, $uid);

            echo json_encode(['status' => 'sucesso', 'msg' => "Salvo. Meta: $meta, Saldo: $saldoDia"]);

        } catch (Exception $e) {
            echo json_encode(['status' => 'erro', 'msg' => $e->getMessage()]);
        }
        exit;
    }

    // --- MIGRAÇÃO: PREENCHER O NOVO CAMPO ---
    elseif ($acao === 'sistema_migrar_banco_fixo') {
        
        // Busca todos os usuários
        $sqlUsers = "SELECT id, nome FROM usuarios";
        $users = $pdo->query($sqlUsers)->fetchAll(PDO::FETCH_ASSOC);
        
        $log = [];
        $totalAfetados = 0;

        foreach ($users as $u) {
            $uid = $u['id'];

            // 1. Calcula a soma total do histórico (como era feito antes)
            $stmtSum = $pdo->prepare("SELECT SUM(saldo_minutos) FROM controle_ponto WHERE usuario_id = ?");
            $stmtSum->execute([$uid]);
            $saldoHistorico = intval($stmtSum->fetchColumn());

            // 2. Verifica se existia alguma sincronia forçada na tabela antiga (para garantir)
            try {
                // Verifica se a tabela 'saldo_real_admin' existe antes de tentar ler
                $checkTable = $pdo->query("SHOW TABLES LIKE 'saldo_real_admin'");
                if($checkTable->rowCount() > 0) {
                    $stmtBlindado = $pdo->prepare("SELECT saldo_atual_minutos FROM saldo_real_admin WHERE usuario_id = ?");
                    $stmtBlindado->execute([$uid]);
                    $blindado = $stmtBlindado->fetchColumn();
                    
                    // Se achou um saldo blindado, usa ele pois é mais confiável
                    if ($blindado !== false) {
                        $saldoHistorico = intval($blindado);
                    }
                }
            } catch (Exception $e) { /* Ignora erro se tabela não existir */ }

            // 3. GRAVA NO NOVO CAMPO DA TABELA USUARIOS
            $upd = $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = ? WHERE id = ?");
            $upd->execute([$saldoHistorico, $uid]);

            $log[] = "{$u['nome']}: Atualizado para " . $saldoHistorico;
            $totalAfetados++;
        }

        echo json_encode(['status' => 'sucesso', 'msg' => "Migração concluída! $totalAfetados usuários atualizados.", 'detalhes' => $log]);
    }
    // --- FUNÇÃO DE EMERGÊNCIA: RECALCULAR TUDO ---
    elseif ($acao === 'recalcular_geral_absoluto') {
        // 1. Zera todos os saldos atuais
        $pdo->exec("UPDATE usuarios SET banco_atual_minutos = 0");

        // 2. Recalcula a soma de TODOS os pontos da história para CADA usuário
        $sql = "SELECT usuario_id, SUM(saldo_minutos) as total_real 
                FROM controle_ponto 
                GROUP BY usuario_id";
        $stmt = $pdo->query($sql);
        $resultados = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $log = [];
        foreach ($resultados as $res) {
            $uid = $res['usuario_id'];
            $total = intval($res['total_real']);
            
            // Atualiza o usuário com a soma correta
            $upd = $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = ? WHERE id = ?");
            $upd->execute([$total, $uid]);
            
            $log[] = "ID $uid ajustado para: $total";
        }

        echo json_encode(['status' => 'sucesso', 'msg' => 'Base de dados recalculada e corrigida!', 'log' => $log]);
    }

    // --- RECALCULAR TUDO DO ZERO (CORREÇÃO DE BASE) ---
    elseif ($acao === 'recalcular_toda_base_do_zero') {
        
        try {
            $pdo->beginTransaction();

            $stmtUsers = $pdo->query("SELECT id, nome FROM usuarios");
            $usuarios = $stmtUsers->fetchAll(PDO::FETCH_ASSOC);
            
            foreach ($usuarios as $user) {
                $uid = $user['id'];

                // 1. DESCOBRE A DATA DE CORTE (DATA DO ÚLTIMO 'SALDO INICIAL')
                // Usamos LIKE bem genérico para pegar qualquer variação
                $sqlData = "SELECT MAX(data_registro) 
                            FROM controle_ponto 
                            WHERE usuario_id = ? 
                            AND (
                                observacao LIKE '%Saldo%' OR 
                                observacao LIKE '%Inicial%' OR 
                                observacao LIKE '%Anterior%' OR
                                horarios LIKE '%Saldo%'
                            )";
                
                $stmtData = $pdo->prepare($sqlData);
                $stmtData->execute([$uid]);
                $dataCorte = $stmtData->fetchColumn();

                // Se não achar data de corte, pega tudo (ano 2000)
                if (!$dataCorte) {
                    $dataCorte = '2000-01-01';
                }

                // 2. SOMA TUDO A PARTIR DESSA DATA (INCLUINDO ELA)
                // Isso garante que o valor de 31/12 (Saldo Inicial) entre na soma
                // E tudo o que veio antes (duplicidade) seja ignorado.
                $sqlSoma = "SELECT COALESCE(SUM(saldo_minutos), 0)
                            FROM controle_ponto
                            WHERE usuario_id = ?
                            AND data_registro >= ?";
                
                $stmtSoma = $pdo->prepare($sqlSoma);
                $stmtSoma->execute([$uid, $dataCorte]);
                $novoSaldo = $stmtSoma->fetchColumn();

                // 3. GRAVA NA MARRA
                $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = ? WHERE id = ?")
                    ->execute([$novoSaldo, $uid]);
            }

            $pdo->commit();
            echo json_encode(['status' => 'sucesso', 'msg' => "Saldos Recalculados a partir da última data de corte."]);

        } catch (Exception $e) {
            $pdo->rollBack();
            echo json_encode(['status' => 'erro', 'msg' => $e->getMessage()]);
        }
        exit;
    }

    // --- NOVA AÇÃO: LIMPAR DIA (DELETE REAL) ---
    elseif ($acao === 'limpar_dia_gestor') {
        $idReg = $input['id_registro'] ?? null;

        if (!$idReg) {
            echo json_encode(['status' => 'erro', 'msg' => 'ID do registro não informado.']);
            exit;
        }

        $pdo->beginTransaction();

        try {
            // 1. DESCUBRA QUEM É O DONO E QUAL O VALOR (Antes de apagar)
            // Selecionamos usuario_id E saldo_minutos do próprio registro
            $stmtGet = $pdo->prepare("SELECT usuario_id, saldo_minutos FROM controle_ponto WHERE id = ?");
            $stmtGet->execute([$idReg]);
            $alvo = $stmtGet->fetch(PDO::FETCH_ASSOC);

            // Se não achou, já foi apagado
            if (!$alvo) {
                $pdo->rollBack();
                echo json_encode(['status' => 'sucesso', 'msg' => 'Registro já estava limpo.']);
                exit;
            }

            $uidReal = $alvo['usuario_id']; // O ID real do dono
            $saldoParaEstornar = intval($alvo['saldo_minutos']);

            // 2. CORRIGE O BANCO TOTAL (ESTORNO)
            // Matemática: Banco Atual - (Saldo que será apagado)
            // Ex: Se tinha -480 (falta), Banco - (-480) = Banco + 480 (Devolve as horas)
            // Ex: Se tinha +120 (extra), Banco - 120 (Retira as horas)
            if ($saldoParaEstornar !== 0) {
                $updUser = $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = banco_atual_minutos - ? WHERE id = ?");
                $updUser->execute([$saldoParaEstornar, $uidReal]);
            }

            // 3. APAGA O REGISTRO
            $del = $pdo->prepare("DELETE FROM controle_ponto WHERE id = ?");
            $del->execute([$idReg]);

            $pdo->commit();
            echo json_encode(['status' => 'sucesso', 'msg' => 'Dia limpo e saldo atualizado!']);

        } catch (Exception $e) {
            $pdo->rollBack();
            echo json_encode(['status' => 'erro', 'msg' => 'Erro SQL: ' . $e->getMessage()]);
        }
    }
    // --- FORÇAR SALDO (Recebe o valor pronto do JS e grava) ---
    elseif ($acao === 'forcar_saldo_final_js') {
        $uid = $dados['usuario_id'];
        $saldo = intval($dados['saldo_minutos']);

        try {
            $stmt = $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = ? WHERE id = ?");
            $stmt->execute([$saldo, $uid]);
            echo json_encode(['status' => 'sucesso']);
        } catch (Exception $e) {
            echo json_encode(['status' => 'erro', 'msg' => $e->getMessage()]);
        }
        exit;
    }

    // --- MÃO DE DEUS: DEFINIR SALDO MANUALMENTE ---
    elseif ($acao === 'forcar_saldo_final_post') {
        
        // Pega direto do formulário, sem frescura de JSON
        $uid = isset($_POST['usuario_id']) ? intval($_POST['usuario_id']) : 0;
        $saldo = isset($_POST['saldo_minutos']) ? intval($_POST['saldo_minutos']) : 0;

        if ($uid > 0) {
            try {
                $stmt = $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = ? WHERE id = ?");
                $stmt->execute([$saldo, $uid]);
                echo json_encode(['status' => 'sucesso', 'msg' => "OK: ID $uid -> $saldo min"]);
            } catch (Exception $e) {
                echo json_encode(['status' => 'erro', 'msg' => $e->getMessage()]);
            }
        } else {
            echo json_encode(['status' => 'erro', 'msg' => "ID Zerado recebido pelo PHP."]);
        }
        exit;
    }
    // --- ATUALIZAR SALDO (USADO PELO RECALCULAR TUDO) ---
    elseif ($acao === 'atualizar_saldo_banco') {
        $uid = $input['usuario_id'];
        $novoSaldo = intval($input['novo_saldo']);

        try {
            $stmt = $pdo->prepare("UPDATE usuarios SET banco_atual_minutos = ? WHERE id = ?");
            $stmt->execute([$novoSaldo, $uid]);
            echo json_encode(['status' => 'sucesso']);
        } catch (Exception $e) {
            echo json_encode(['status' => 'erro', 'msg' => $e->getMessage()]);
        }
        exit;
    }

    // --- CONSULTAR FÉRIAS (AGRUPADAS POR PERÍODO) ---
    elseif ($acao === 'ler_ferias_usuario') {
        $uid = intval($input['usuario_id'] ?? 0);
        
        try {
            // 1. Busca TUDO do usuário (deixa o PHP filtrar, é mais seguro contra erros de acento)
            $stmt = $pdo->prepare("SELECT data_registro, horarios FROM controle_ponto WHERE usuario_id = ? ORDER BY data_registro ASC");
            $stmt->execute([$uid]);
            $todosRegistros = $stmt->fetchAll(PDO::FETCH_ASSOC);

            $diasFerias = [];

            // 2. Filtra linha por linha
            foreach ($todosRegistros as $row) {
                $h = json_decode($row['horarios'], true);
                // Se der erro no JSON, tenta usar o texto puro
                if (!is_array($h)) {
                    $textoPuro = mb_strtoupper($row['horarios'] ?? '', 'UTF-8');
                } else {
                    $textoPuro = mb_strtoupper($h[0] ?? '', 'UTF-8');
                }

                // Verifica variações da palavra
                if (strpos($textoPuro, 'FÉRIAS') !== false || 
                    strpos($textoPuro, 'FERIAS') !== false || 
                    strpos($textoPuro, 'RECESSO') !== false ||
                    strpos($textoPuro, 'FOLGA') !== false) {
                    
                    $diasFerias[] = $row['data_registro'];
                }
            }

            if (empty($diasFerias)) {
                echo json_encode(['status' => 'sucesso', 'periodos' => []]);
                exit;
            }

            // 3. Agrupamento Inteligente (Tolera fins de semana)
            $periodos = [];
            $inicioAtual = $diasFerias[0];
            $fimAtual = $diasFerias[0];

            for ($i = 1; $i < count($diasFerias); $i++) {
                $dataAnt = new DateTime($diasFerias[$i-1]);
                $dataAtu = new DateTime($diasFerias[$i]);
                
                // Calcula distância entre um dia e outro
                $diff = $dataAnt->diff($dataAtu)->days;

                // Se a distância for pequena (até 4 dias), considera o mesmo período
                // Isso evita que Sábado/Domingo quebrem as férias em duas partes
                if ($diff <= 4) {
                    $fimAtual = $diasFerias[$i];
                } else {
                    // Fechou um grupo, começa outro
                    $periodos[] = ['inicio' => $inicioAtual, 'fim' => $fimAtual];
                    $inicioAtual = $diasFerias[$i];
                    $fimAtual = $diasFerias[$i];
                }
            }
            // Adiciona o último
            $periodos[] = ['inicio' => $inicioAtual, 'fim' => $fimAtual];

            // Ordena (Mais recentes primeiro)
            usort($periodos, function($a, $b) {
                return strtotime($b['inicio']) - strtotime($a['inicio']);
            });

            echo json_encode(['status' => 'sucesso', 'periodos' => $periodos]);

        } catch (Exception $e) {
            echo json_encode(['status' => 'erro', 'msg' => $e->getMessage()]);
        }
        exit;
    }

} catch (Exception $e) {
    echo json_encode(['status' => 'erro', 'msg' => 'Erro Fatal: ' . $e->getMessage()]);
}
?>