<?php
ob_start();
session_start();
require_once 'db/conexao.php';

// Configuração de logs
$logFile = '/var/www/prn.laudocontrol.com.br/logs/php_errors.log';
$logDir = dirname($logFile);
$logs = [];
if (!is_dir($logDir)) {
    mkdir($logDir, 0755, true);
}
if (is_writable($logDir)) {
    ini_set('log_errors', 1);
    ini_set('error_log', $logFile);
}

// Função para registrar logs
function addLog(&$logs, $message) {
    $logMessage = $message . " às " . date('Y-m-d H:i:s');
    $logs[] = $logMessage;
    error_log($logMessage);
    file_put_contents('processar_fatura.log', $logMessage . PHP_EOL, FILE_APPEND);
}

// Verifica se o usuário está logado
if (!isset($_SESSION['usu_cod'])) {
    $logs = [];
    addLog($logs, "Usuário não logado.");
    header('Content-Type: application/json');
    ob_end_clean();
    echo json_encode(['status' => 'error', 'message' => 'Usuário não logado. Faça login.', 'logs' => $logs]);
    exit;
}

// Conexão com o banco de dados
$pdo = getConexao();
if ($pdo === null) {
    $logs = [];
    addLog($logs, "Falha na conexão com o banco de dados.");
    header('Content-Type: application/json');
    ob_end_clean();
    echo json_encode(['status' => 'error', 'message' => 'Falha na conexão com o banco.', 'logs' => $logs]);
    exit;
}

$logs = [];
addLog($logs, "Script ProcessarFatura.php iniciado");

/**
 * Normaliza valores monetários vindos do formulário, aceitando tanto
 * formatos pt-BR (1.234,56) quanto en-US (1234.56).
 */
function normalizeMoneyInput($value)
{
    if ($value === null) {
        return 0.0;
    }
    // Remove espaços, símbolo de moeda e caracteres não numéricos relevantes
    $clean = trim(str_replace(['R$', ' '], '', (string)$value));
    if ($clean === '') {
        return 0.0;
    }
    $hasComma = strpos($clean, ',') !== false;
    $hasDot = strpos($clean, '.') !== false;

    if ($hasComma && $hasDot) {
        // Cenário típico pt-BR: ponto como milhar e vírgula como decimal
        $clean = str_replace('.', '', $clean);
        $clean = str_replace(',', '.', $clean);
    } elseif ($hasComma) {
        // Apenas vírgula presente, tratar como decimal
        $clean = str_replace(',', '.', $clean);
    } elseif ($hasDot && substr_count($clean, '.') > 1) {
        // Múltiplos pontos: tratar todos como milhar, exceto o último
        $parts = explode('.', $clean);
        $decimal = array_pop($parts);
        $clean = implode('', $parts) . '.' . $decimal;
    }

    // Mantém apenas dígitos, sinal e ponto final
    $clean = preg_replace('/[^0-9\.\-]/', '', $clean);
    return (float)$clean;
}

// Log do método e dados recebidos
addLog($logs, "Método HTTP: {$_SERVER['REQUEST_METHOD']}");
addLog($logs, "Dados POST recebidos: " . json_encode($_POST));

// Inicializa variáveis
$tipo = strtolower(filter_var($_POST['tipo'] ?? '', FILTER_SANITIZE_STRING));
$med_cod = filter_var($_POST['med_cod'] ?? '', FILTER_SANITIZE_NUMBER_INT);
$dig_cod = filter_var($_POST['dig_cod'] ?? '', FILTER_SANITIZE_NUMBER_INT);
$fatPrest = ($tipo === 'medico' ? $med_cod : $dig_cod) ?? '';
$fatVal = normalizeMoneyInput($_POST['fat_val'] ?? '0.00');
$fat_val_dig = normalizeMoneyInput($_POST['fat_val_dig'] ?? '0.00');
$fatVcto = trim(filter_var($_POST['fat_vcto'] ?? '', FILTER_SANITIZE_STRING));
$examesSelecionados = $_POST['exames'] ?? [];
$usu_cod = $_SESSION['usu_cod'];
$unidades_summary = isset($_POST['unidades_summary']) ? json_decode($_POST['unidades_summary'], true) : [];
$contrato = trim(filter_var($_POST['contrato'] ?? '', FILTER_SANITIZE_STRING));
$isDigitador = isset($_POST['is_digitador']) && $_POST['is_digitador'] === '1';
$aplicar_desconto = isset($_POST['aplicar_desconto']) && $_POST['aplicar_desconto'] === '1';
$desconto_percent = $aplicar_desconto ? normalizeMoneyInput($_POST['desconto_percent'] ?? '0.00') : 0.00;
$observacoes = trim(filter_var($_POST['observacoes'] ?? '', FILTER_SANITIZE_STRING));
$itens_manuais = [];
if (!empty($_POST['itens_manuais'])) {
    $decoded = json_decode($_POST['itens_manuais'], true);
    if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
        $itens_manuais = $decoded;
    } else {
        addLog($logs, "Aviso: itens_manuais inválido no POST. json_last_error=" . json_last_error());
    }
}

addLog($logs, "Variáveis inicializadas - tipo: $tipo, fatPrest: $fatPrest, fatVal: $fatVal, fat_val_dig: $fat_val_dig, fatVcto: $fatVcto, usu_cod: $usu_cod, examesSelecionados: " . json_encode($examesSelecionados) . ", contrato: $contrato, is_digitador: " . ($isDigitador ? 'true' : 'false') . ", aplicar_desconto: " . ($aplicar_desconto ? 'true' : 'false') . ", desconto_percent: $desconto_percent, observacoes: $observacoes");

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    addLog($logs, "Confirmação de fatura recebida (método POST detectado)");

    // Validar dados
    addLog($logs, "Iniciando validação dos dados...");
    if (!in_array($tipo, ['medico', 'digitador'])) {
        addLog($logs, "Validação falhou: Tipo inválido - $tipo");
        header('Content-Type: application/json');
        ob_end_clean();
        echo json_encode(['status' => 'error', 'message' => 'Tipo de fatura inválido.', 'logs' => $logs]);
        exit;
    }
    addLog($logs, "Validação de tipo passou: $tipo");

    if (empty($fatPrest) || !is_numeric($fatPrest)) {
        addLog($logs, "Validação falhou: Código do profissional inválido - $fatPrest");
        header('Content-Type: application/json');
        ob_end_clean();
        echo json_encode(['status' => 'error', 'message' => 'Código do profissional inválido.', 'logs' => $logs]);
        exit;
    }
    addLog($logs, "Validação de fatPrest passou: $fatPrest");

    if (!is_numeric($fatVal) || $fatVal <= 0) {
        addLog($logs, "Validação falhou: Valor da fatura inválido - $fatVal");
        header('Content-Type: application/json');
        ob_end_clean();
        echo json_encode(['status' => 'error', 'message' => 'Valor da fatura inválido.', 'logs' => $logs]);
        exit;
    }
    addLog($logs, "Validação de fatVal passou: $fatVal");

    if ($tipo === 'medico' && $isDigitador && (!is_numeric($fat_val_dig) || $fat_val_dig < 0)) {
        addLog($logs, "Validação falhou: Valor do digitador inválido - $fat_val_dig");
        header('Content-Type: application/json');
        ob_end_clean();
        echo json_encode(['status' => 'error', 'message' => 'Valor do digitador inválido.', 'logs' => $logs]);
        exit;
    }
    addLog($logs, "Validação de fat_val_dig passou: $fat_val_dig");

    if ($aplicar_desconto) {
        if (!is_numeric($desconto_percent) || $desconto_percent < 0 || $desconto_percent > 100) {
            addLog($logs, "Validação falhou: Porcentagem de desconto inválida - $desconto_percent");
            header('Content-Type: application/json');
            ob_end_clean();
            echo json_encode(['status' => 'error', 'message' => 'Porcentagem de desconto inválida (deve ser entre 0 e 100).', 'logs' => $logs]);
            exit;
        }
        addLog($logs, "Validação de desconto_percent passou: $desconto_percent");
    }

    if (empty($fatVcto)) {
        addLog($logs, "Validação falhou: Data de vencimento vazia");
        header('Content-Type: application/json');
        ob_end_clean();
        echo json_encode(['status' => 'error', 'message' => 'Data de vencimento obrigatória.', 'logs' => $logs]);
        exit;
    }

    $fatVctoSQL = DateTime::createFromFormat('d/m/Y', $fatVcto);
    if ($fatVctoSQL === false || $fatVctoSQL->format('d/m/Y') !== $fatVcto) {
        addLog($logs, "Validação falhou: Data de vencimento inválida - $fatVcto");
        header('Content-Type: application/json');
        ob_end_clean();
        echo json_encode(['status' => 'error', 'message' => 'Data de vencimento inválida.', 'logs' => $logs]);
        exit;
    }
    $today = new DateTime();
    if ($fatVctoSQL < $today) {
        addLog($logs, "Validação falhou: Data de vencimento não é futura - $fatVcto");
        header('Content-Type: application/json');
        ob_end_clean();
        echo json_encode(['status' => 'error', 'message' => 'Data de vencimento deve ser futura.', 'logs' => $logs]);
        exit;
    }
    $fatVctoSQL = $fatVctoSQL->format('Y-m-d');
    addLog($logs, "Validação de fatVcto passou: $fatVctoSQL");

    if (empty($examesSelecionados)) {
        addLog($logs, "Validação falhou: Nenhum exame selecionado");
        header('Content-Type: application/json');
        ob_end_clean();
        echo json_encode(['status' => 'error', 'message' => 'Nenhum exame selecionado.', 'logs' => $logs]);
        exit;
    }
    addLog($logs, "Validação de examesSelecionados passou: " . count($examesSelecionados) . " exames");

    if (empty($contrato) || !in_array($contrato, ['PRN', 'MEDIMAGEM', 'MEDIMAGEM PALHOCA'])) {
        addLog($logs, "Validação falhou: Contrato inválido - $contrato");
        header('Content-Type: application/json');
        ob_end_clean();
        echo json_encode(['status' => 'error', 'message' => 'Contrato inválido.', 'logs' => $logs]);
        exit;
    }
    addLog($logs, "Validação de contrato passou: $contrato");

    // Validar unidades_summary
    if (!empty($unidades_summary)) {
        $total_percent = array_sum(array_column($unidades_summary, 'percent'));
        if ($total_percent < 99.5 || $total_percent > 100.5) {
            addLog($logs, "Validação falhou: Percentual total dos rateios inválido - $total_percent");
            header('Content-Type: application/json');
            ob_end_clean();
            echo json_encode(['status' => 'error', 'message' => 'Percentual total dos rateios inválido.', 'logs' => $logs]);
            exit;
        }

        $stmt_unidades = $pdo->prepare("SELECT uni_nome, uni_cod FROM unidades WHERE uni_nome IN (" . implode(',', array_fill(0, count($unidades_summary), '?')) . ")");
        $stmt_unidades->execute(array_keys($unidades_summary));
        $unidades_map = $stmt_unidades->fetchAll(PDO::FETCH_KEY_PAIR);
        addLog($logs, "Unidades mapeadas: " . json_encode($unidades_map));

        // Verificar se há unidade de rateio único que precisa ser buscada
        $unidade_rateio_unico_val = isset($_POST['unidade_rateio_unico_val']) ? (int)$_POST['unidade_rateio_unico_val'] : 0;
        if ($unidade_rateio_unico_val > 0) {
            $stmt_uni_unico = $pdo->prepare("SELECT uni_nome, uni_cod FROM unidades WHERE uni_cod = ?");
            $stmt_uni_unico->execute([$unidade_rateio_unico_val]);
            $uni_unico = $stmt_uni_unico->fetch(PDO::FETCH_ASSOC);
            if ($uni_unico && !isset($unidades_map[$uni_unico['uni_nome']])) {
                $unidades_map[$uni_unico['uni_nome']] = $uni_unico['uni_cod'];
                addLog($logs, "Unidade de rateio único adicionada ao map: " . $uni_unico['uni_nome']);
            }
        }

        foreach ($unidades_summary as $unidade => $data) {
            if (!isset($unidades_map[$unidade])) {
                addLog($logs, "Validação falhou: Unidade não encontrada - $unidade");
                header('Content-Type: application/json');
                ob_end_clean();
                echo json_encode(['status' => 'error', 'message' => "Unidade não encontrada: $unidade.", 'logs' => $logs]);
                exit;
            }
        }
    }

    try {
        addLog($logs, "Iniciando processamento da fatura...");
        $pdo->beginTransaction();

        // Usar observacoes como referência se não vazio, senão contrato
        $fat_ref = !empty($observacoes) ? $observacoes : $contrato;
        addLog($logs, "Referência gerada: $fat_ref");

        // Cálculo do desconto no valor líquido
        // O valor que chega em fatVal já está calculado no frontend com desconto aplicado onde necessário
        // Precisamos recalcular o valor bruto considerando itens manuais que NÃO devem ter desconto
        
        // Primeiro, calcular valor bruto total (exames + todos os itens manuais)
        $valor_bruto_exames = 0.0;
        if (!empty($examesSelecionados)) {
            $campoValExame = ($tipo === 'medico') ? 'ex_vl_med' : 'ex_vl_dig';
            $placeholders_exames = implode(',', array_fill(0, count($examesSelecionados), '?'));
            $stmt_val_exames = $pdo->prepare("SELECT SUM($campoValExame) FROM exames WHERE ex_pk IN ($placeholders_exames)");
            $stmt_val_exames->execute($examesSelecionados);
            $valor_bruto_exames = (float)($stmt_val_exames->fetchColumn() ?? 0);
        }
        
        // Calcular valor bruto dos itens manuais (todos, sem desconto)
        $valor_bruto_manual = 0.0;
        $valor_manual_com_desconto = 0.0;
        $valor_manual_sem_desconto = 0.0;
        if (!empty($itens_manuais)) {
            foreach ($itens_manuais as $item) {
                $valor_item = isset($item['valor_total']) ? (float)$item['valor_total'] : 0.0;
                $valor_bruto_manual += $valor_item;
                
                // Separar itens que devem ter desconto dos que não devem
                $item_aplicar_desconto = isset($item['aplicar_desconto']) ? (bool)$item['aplicar_desconto'] : false;
                if ($aplicar_desconto && $item_aplicar_desconto) {
                    $valor_manual_com_desconto += $valor_item;
                } else {
                    $valor_manual_sem_desconto += $valor_item;
                }
            }
        }
        
        // Valor bruto total (exames + todos os itens manuais)
        $gross = $valor_bruto_exames + $valor_bruto_manual;
        
        // Calcular valor líquido: valor bruto - desconto aplicado apenas nos valores que devem ter desconto
        $net = $fatVal; // O valor que veio do frontend já está correto
        if ($aplicar_desconto) {
            // Recalcular para garantir que está correto
            $base_desconto = $valor_bruto_exames + $valor_manual_com_desconto;
            $discount_amount = round($base_desconto * ($desconto_percent / 100), 2);
            $net = round($gross - $discount_amount, 2);
            
            // Se houver diferença, usar o valor do frontend que já foi calculado corretamente
            if (abs($net - $fatVal) > 0.01) {
                addLog($logs, "Diferença entre cálculo backend e frontend (usando valor do frontend): backend=$net, frontend=$fatVal");
                $net = $fatVal;
            }
        }
        
        addLog($logs, "Cálculo de desconto: valor_bruto_exames=$valor_bruto_exames, valor_bruto_manual=$valor_bruto_manual, gross=$gross, desconto_percent=$desconto_percent, net=$net, manual_com_desconto=$valor_manual_com_desconto, manual_sem_desconto=$valor_manual_sem_desconto");

        // Inserir fatura com novas colunas
        $stmtFatura = $pdo->prepare("
            INSERT INTO faturas_prest (fat_prest, fat_val, fat_val_int, fat_desc, fat_vcto, fat_tipo_prest, fat_usu, fat_ref, fat_status, fat_data, fat_val_dig)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'Gerada', CURRENT_TIMESTAMP, ?)
            RETURNING fat_id
        ");
        $params = [$fatPrest, $net, $gross, $desconto_percent, $fatVctoSQL, $tipo, $usu_cod, $fat_ref, $fat_val_dig];
        addLog($logs, "Query de inserção da fatura: " . json_encode($params));
        if (!$stmtFatura->execute($params)) {
            throw new Exception('Erro ao inserir fatura: ' . print_r($stmtFatura->errorInfo(), true));
        }
        $fatCod = $stmtFatura->fetchColumn();
        addLog($logs, "Fatura inserida com sucesso, código: $fatCod, fat_val=$net, fat_val_int=$gross, fat_desc=$desconto_percent, fat_val_dig=$fat_val_dig");

        // Atualizar exames
        $placeholders = implode(',', array_fill(0, count($examesSelecionados), '?'));
        $updateField = ($tipo === 'medico' ? 'ex_fat_med' : 'ex_fat_dig');
        $stmtUpdate = $pdo->prepare("UPDATE exames SET $updateField = ?, ex_fat_" . ($tipo === 'medico' ? 'dig' : 'med') . " = NULL WHERE ex_pk IN ($placeholders)");
        $paramsUpdate = array_merge([$fatCod], $examesSelecionados);
        addLog($logs, "Query de atualização de exames: " . json_encode($paramsUpdate));
        if (!$stmtUpdate->execute($paramsUpdate)) {
            throw new Exception('Erro ao atualizar exames: ' . print_r($stmtUpdate->errorInfo(), true));
        }
        addLog($logs, "Exames atualizados, linhas afetadas: " . $stmtUpdate->rowCount());

        // Inserir rateios respeitando a distribuição calculada no frontend (proporcional ou único)
        if (!empty($unidades_summary)) {
            // Usar os valores e percentuais já calculados pelo frontend
            // Apenas ajustar para garantir que valores somem exatamente o net e percentuais somem 100%
            $keys = array_keys($unidades_summary);
            $last_key = end($keys);
            
            // Ajustar valores para somar exatamente o net, mantendo proporções relativas
            $sum_val_atual = 0;
            foreach ($unidades_summary as $data) {
                $sum_val_atual += $data['valor'];
            }
            
            if ($sum_val_atual > 0 && $net > 0) {
                // Manter proporções relativas, mas ajustar para somar exatamente o net
                foreach ($unidades_summary as $unidade => &$data) {
                    $data['valor'] = round(($data['valor'] / $sum_val_atual) * $net, 2);
                }
                unset($data);
                
                // Garantir que a soma seja exatamente o net (ajustar última unidade se necessário)
                $sum_ajustado = 0;
                foreach ($unidades_summary as $data) {
                    $sum_ajustado += $data['valor'];
                }
                $diff = round($net - $sum_ajustado, 2);
                if (abs($diff) > 0.01) { // Tolerância de centavos
                    $unidades_summary[$last_key]['valor'] += $diff;
                }
            } else {
                // Se não há valores, distribuir igualmente
                $val_por_uni = round($net / count($unidades_summary), 2);
                foreach ($unidades_summary as $unidade => &$data) {
                    $data['valor'] = $val_por_uni;
                }
                unset($data);
                // Ajustar última unidade para soma exata
                $sum_igual = 0;
                foreach ($unidades_summary as $data) {
                    $sum_igual += $data['valor'];
                }
                $diff = round($net - $sum_igual, 2);
                if (abs($diff) > 0.01) {
                    $unidades_summary[$last_key]['valor'] += $diff;
                }
            }
            
            // Recalcular percentuais baseados nos valores finais ajustados
            // Garantir que valores não sejam negativos
            foreach ($unidades_summary as $unidade => &$data) {
                if ($data['valor'] < 0) {
                    $data['valor'] = 0;
                    addLog($logs, "Aviso: Valor negativo corrigido para zero na unidade: $unidade");
                }
            }
            unset($data);
            
            $sum_final = 0;
            foreach ($unidades_summary as $data) {
                $sum_final += $data['valor'];
            }
            
            // Calcular percentuais iniciais
            $percentuais_raw = [];
            foreach ($unidades_summary as $unidade => &$data) {
                if ($sum_final > 0) {
                    $percent_raw = ($data['valor'] / $sum_final) * 100;
                    $percentuais_raw[$unidade] = $percent_raw;
                    $data['percent'] = round($percent_raw, 2);
                } else {
                    $percentuais_raw[$unidade] = 0;
                    $data['percent'] = 0.00;
                }
            }
            unset($data);
            
            // Normalizar percentuais para garantir soma exata de 100% e valores entre 0-100%
            $sum_percent = 0;
            foreach ($unidades_summary as $data) {
                $sum_percent += $data['percent'];
            }
            
            // Calcular diferença com maior precisão
            $percent_diff = 100.00 - $sum_percent;
            
            // Se houver diferença, distribuir de forma inteligente
            if (abs($percent_diff) > 0.001) { // Tolerância menor para maior precisão
                // Ordenar por valor absoluto da diferença entre percentual raw e arredondado
                // Isso ajuda a distribuir a diferença de forma mais justa
                $unidades_ordenadas = [];
                foreach ($unidades_summary as $unidade => $data) {
                    $diff_raw = abs($percentuais_raw[$unidade] - $data['percent']);
                    $unidades_ordenadas[] = [
                        'unidade' => $unidade,
                        'diff' => $diff_raw,
                        'percent_atual' => $data['percent'],
                        'valor' => $data['valor']
                    ];
                }
                
                // Ordenar por maior diferença (priorizar quem mais perdeu no arredondamento)
                usort($unidades_ordenadas, function($a, $b) {
                    return $b['diff'] <=> $a['diff'];
                });
                
                // Distribuir a diferença começando pela unidade que mais perdeu no arredondamento
                $diff_restante = $percent_diff;
                $precisao = 0.01; // Precisão de 2 casas decimais
                
                foreach ($unidades_ordenadas as $item) {
                    if (abs($diff_restante) < $precisao) {
                        break;
                    }
                    
                    $unidade = $item['unidade'];
                    $percent_atual = $unidades_summary[$unidade]['percent'];
                    
                    // Calcular quanto podemos ajustar sem ultrapassar limites
                    if ($diff_restante > 0) {
                        // Adicionar diferença, mas não ultrapassar 100%
                        $ajuste = min($diff_restante, 100.00 - $percent_atual, $precisao);
                        if ($ajuste > 0) {
                            $unidades_summary[$unidade]['percent'] = round($percent_atual + $ajuste, 2);
                            $diff_restante = round($diff_restante - $ajuste, 2);
                        }
                    } else {
                        // Subtrair diferença, mas não ficar negativo
                        $ajuste = max($diff_restante, -$percent_atual, -$precisao);
                        if ($ajuste < 0) {
                            $unidades_summary[$unidade]['percent'] = round($percent_atual + $ajuste, 2);
                            $diff_restante = round($diff_restante - $ajuste, 2);
                        }
                    }
                }
                
                // Se ainda houver diferença, ajustar na última unidade (maior valor)
                if (abs($diff_restante) >= $precisao) {
                    // Encontrar unidade com maior valor para ajustar
                    $maior_valor = -1;
                    $unidade_maior = null;
                    foreach ($unidades_summary as $unidade => $data) {
                        if ($data['valor'] > $maior_valor) {
                            $maior_valor = $data['valor'];
                            $unidade_maior = $unidade;
                        }
                    }
                    
                    if ($unidade_maior !== null) {
                        $percent_atual = $unidades_summary[$unidade_maior]['percent'];
                        $novo_percent = round($percent_atual + $diff_restante, 2);
                        
                        // Garantir que fique entre 0 e 100%
                        $novo_percent = max(0.00, min(100.00, $novo_percent));
                        $unidades_summary[$unidade_maior]['percent'] = $novo_percent;
                        
                        // Recalcular diferença final
                        $diff_restante = round(100.00 - array_sum(array_column($unidades_summary, 'percent')), 2);
                        if (abs($diff_restante) >= $precisao) {
                            addLog($logs, "Aviso: Diferença residual após ajustes: $diff_restante%");
                        }
                    }
                }
            }
            
            // Validação final: garantir que todos os percentuais estão entre 0 e 100%
            $sum_final_percent = 0;
            foreach ($unidades_summary as $unidade => &$data) {
                // Garantir limites
                $data['percent'] = max(0.00, min(100.00, round($data['percent'], 2)));
                $sum_final_percent += $data['percent'];
            }
            unset($data);
            
            // Ajuste final para garantir soma exata de 100%
            $diff_final = round(100.00 - $sum_final_percent, 2);
            if (abs($diff_final) > 0.001 && !empty($unidades_summary)) {
                // Ajustar na unidade com maior valor
                $maior_valor = -1;
                $unidade_ajuste = null;
                foreach ($unidades_summary as $unidade => $data) {
                    if ($data['valor'] > $maior_valor) {
                        $maior_valor = $data['valor'];
                        $unidade_ajuste = $unidade;
                    }
                }
                
                if ($unidade_ajuste !== null) {
                    $percent_atual = $unidades_summary[$unidade_ajuste]['percent'];
                    $novo_percent = round($percent_atual + $diff_final, 2);
                    $novo_percent = max(0.00, min(100.00, $novo_percent));
                    $unidades_summary[$unidade_ajuste]['percent'] = $novo_percent;
                }
            }

            $valores_log = [];
            $percentuais_log = [];
            foreach ($unidades_summary as $data) {
                $valores_log[] = $data['valor'];
                $percentuais_log[] = $data['percent'];
            }
            addLog($logs, "Rateios processados: valores=" . json_encode($valores_log) . ", percentuais=" . json_encode($percentuais_log));

            // Validação final antes de inserir
            $soma_percent_final = 0;
            $soma_valor_final = 0;
            foreach ($unidades_summary as $unidade => $data) {
                // Validar limites
                if ($data['percent'] < 0 || $data['percent'] > 100) {
                    throw new Exception("Percentual inválido para unidade $unidade: {$data['percent']}% (deve estar entre 0 e 100)");
                }
                if ($data['valor'] < 0) {
                    throw new Exception("Valor inválido para unidade $unidade: R$ {$data['valor']} (não pode ser negativo)");
                }
                $soma_percent_final += $data['percent'];
                $soma_valor_final += $data['valor'];
            }
            
            // Validar soma de percentuais
            if (abs($soma_percent_final - 100.00) > 0.01) {
                throw new Exception("Soma de percentuais inválida: {$soma_percent_final}% (deve ser exatamente 100%)");
            }
            
            // Validar soma de valores (deve ser igual ao valor líquido)
            if (abs($soma_valor_final - $net) > 0.01) {
                addLog($logs, "Aviso: Soma de valores dos rateios ({$soma_valor_final}) difere do valor líquido ($net). Diferença: " . abs($soma_valor_final - $net));
            }
            
            // Inserir os rateios ajustados
            $stmt_rateio = $pdo->prepare("INSERT INTO fat_prest_rateio (rat_fat, rat_uni, rat_val, rat_perc) VALUES (:rat_fat, :rat_uni, :rat_val, :rat_perc)");
            foreach ($unidades_summary as $unidade => $data) {
                $uni_cod = $unidades_map[$unidade];
                
                // Garantir valores finais válidos antes de inserir
                $valor_final = max(0.00, round($data['valor'], 2));
                $percent_final = max(0.00, min(100.00, round($data['percent'], 2)));
                
                $paramsRateio = [
                    ':rat_fat' => $fatCod,
                    ':rat_uni' => $uni_cod,
                    ':rat_val' => $valor_final,
                    ':rat_perc' => $percent_final
                ];
                if (!$stmt_rateio->execute($paramsRateio)) {
                    throw new Exception('Erro ao inserir rateio: ' . print_r($stmt_rateio->errorInfo(), true));
                }
                addLog($logs, "Rateio inserido: fat_id=$fatCod, uni_cod=$uni_cod, valor={$valor_final}, percentual={$percent_final}%");
            }
            // Inserir itens manuais como exames
            if (!empty($itens_manuais)) {
                addLog($logs, 'Inserindo itens manuais: ' . json_encode($itens_manuais));
                
                // Determinar unidade padrão para rateio proporcional (usa primeira unidade do resumo)
                $uni_cod_padrao = null;
                if (!empty($unidades_map)) {
                    $firstKey = array_key_first($unidades_map);
                    $uni_cod_padrao = $unidades_map[$firstKey];
                }
                
                $campoFat = ($tipo === 'medico') ? 'ex_fat_med' : 'ex_fat_dig';
                $campoVal = ($tipo === 'medico') ? 'ex_vl_med' : 'ex_vl_dig';
                $campoPrest = ($tipo === 'medico') ? 'ex_med_cod' : 'ex_dig_cod';
                $stmt_ins_manual = $pdo->prepare("INSERT INTO exames (ex_uni, ex_modalidade, ex_estudo, ex_status, ex_data_ex, ex_qtde, $campoVal, ex_paciente, ex_item_manual, $campoFat, $campoPrest) VALUES (?, 'MANUAL', ?, 'Faturado', CURRENT_DATE, 1, ?, '', TRUE, ?, ?)");
                
                foreach ($itens_manuais as $item) {
                    $desc = isset($item['descricao']) ? trim($item['descricao']) : 'ITEM MANUAL';
                    // O valor_total do item manual é sempre o valor original (sem desconto aplicado)
                    // O desconto é aplicado apenas no cálculo do valor total da fatura, não no valor individual do item
                    $valor = isset($item['valor_total']) ? (float)$item['valor_total'] : 0.0;
                    if ($valor <= 0) { continue; }
                    
                    $item_aplicar_desconto = isset($item['aplicar_desconto']) ? (bool)$item['aplicar_desconto'] : false;
                    addLog($logs, "Item manual processado: desc=$desc, valor_original=$valor, aplicar_desconto=" . ($item_aplicar_desconto ? 'true' : 'false'));
                    
                    // Determinar qual unidade usar para este item manual
                    $uni_cod_item = null;
                    $rateio_proporcional = isset($item['rateio_proporcional']) ? (bool)$item['rateio_proporcional'] : true;
                    
                    if (!$rateio_proporcional && isset($item['unidade_cod']) && !empty($item['unidade_cod'])) {
                        // Rateio único: usar a unidade especificada no item
                        $uni_cod_item = (int)$item['unidade_cod'];
                        addLog($logs, "Item manual com rateio único: usando unidade_cod=$uni_cod_item");
                    } else {
                        // Rateio proporcional: usar primeira unidade do resumo ou padrão
                        $uni_cod_item = $uni_cod_padrao;
                        addLog($logs, "Item manual com rateio proporcional: usando unidade padrão=" . ($uni_cod_padrao ?? 'NULL'));
                    }
                    
                    $paramsIns = [ $uni_cod_item, $desc, $valor, $fatCod, $fatPrest ];
                    if (!$stmt_ins_manual->execute($paramsIns)) {
                        throw new Exception('Erro ao inserir item manual como exame: ' . print_r($stmt_ins_manual->errorInfo(), true));
                    }
                    addLog($logs, "Item manual inserido como exame: desc=$desc, valor=$valor, uni=" . ($uni_cod_item ?? 'NULL') . ", rateio_proporcional=" . ($rateio_proporcional ? 'true' : 'false'));
                }
            }
        }

        // Confirmar transação
        $pdo->commit();
        addLog($logs, "Transação concluída com sucesso, fatCod: $fatCod");

        // Armazenar dados na sessão
        $_SESSION['fatura_data'] = ['tipo' => $tipo, 'med_cod' => $med_cod, 'dig_cod' => $dig_cod];
        addLog($logs, "Dados salvos na sessão: " . json_encode($_SESSION['fatura_data']));

        header('Content-Type: application/json');
        ob_end_clean();
        echo json_encode([
            'status' => 'success',
            'message' => "Fatura concluída com sucesso! Código: $fatCod",
            'fatCod' => $fatCod,
            'logs' => $logs
        ]);
        exit;
    } catch (Exception $e) {
        $pdo->rollBack();
        addLog($logs, "Erro no processamento: " . $e->getMessage());
        header('Content-Type: application/json');
        ob_end_clean();
        echo json_encode(['status' => 'error', 'message' => 'Erro ao processar a fatura: ' . $e->getMessage(), 'logs' => $logs]);
        exit;
    }
} else {
    addLog($logs, "Ação não reconhecida ou método inválido. Método: {$_SERVER['REQUEST_METHOD']}, POST: " . json_encode($_POST));
    header('Content-Type: application/json');
    ob_end_clean();
    echo json_encode(['status' => 'error', 'message' => 'Ação não reconhecida. Verifique o método ou o campo confirmar_fatura.', 'logs' => $logs]);
    exit;
}
?>