<?php
declare(strict_types=1);

session_start();
date_default_timezone_set('America/Sao_Paulo');

$mergeLib = __DIR__ . '/nuclea_merge_lib.php';
if (!is_file($mergeLib)) {
    http_response_code(500);
    echo 'Biblioteca nuclea_merge_lib.php nao encontrada.';
    exit;
}

require_once $mergeLib;

$phpseclibBase = __DIR__ . '/phpseclib';
$extraPaths = [
    $phpseclibBase,
    $phpseclibBase . '/Net',
    $phpseclibBase . '/Crypt',
    $phpseclibBase . '/Math',
    $phpseclibBase . '/File',
    $phpseclibBase . '/System',
];
set_include_path(get_include_path() . PATH_SEPARATOR . implode(PATH_SEPARATOR, $extraPaths));

require_once $phpseclibBase . '/bootstrap.php';
require_once $phpseclibBase . '/Net/SFTP.php';
require_once $phpseclibBase . '/Crypt/RSA.php';
require_once __DIR__ . '/spbseguranca.php';

function autoFirstExistingPath(array $candidates): string
{
    foreach ($candidates as $candidate) {
        if (is_string($candidate) && $candidate !== '' && is_file($candidate)) {
            return $candidate;
        }
    }
    return '';
}

function autoNormalizeRemotePath(string $path): string
{
    $path = trim($path);
    if ($path === '') {
        return '/';
    }
    if ($path[0] !== '/') {
        $path = '/' . $path;
    }

    $parts = [];
    foreach (explode('/', $path) as $part) {
        if ($part === '' || $part === '.') {
            continue;
        }
        if ($part === '..') {
            array_pop($parts);
            continue;
        }
        $parts[] = $part;
    }

    return '/' . implode('/', $parts);
}

function autoSafeName(string $value, string $fallback = 'arquivo'): string
{
    $value = basename($value);
    $value = preg_replace('/[^A-Za-z0-9_.-]+/', '_', $value);
    $value = trim((string)$value, '._-');
    return $value !== '' ? $value : $fallback;
}

function autoEnsureDir(string $dir): void
{
    if (!is_dir($dir) && !mkdir($dir, 0775, true)) {
        throw new RuntimeException('Nao foi possivel criar a pasta: ' . $dir);
    }
}

function autoIsSpbPayload(string $payload): bool
{
    if (strlen($payload) < SpbSeguranca::TAMANHO_CABECALHO) {
        return false;
    }
    $headerSize = unpack('n', substr($payload, 0, 2))[1] ?? 0;
    if ($headerSize !== SpbSeguranca::TAMANHO_CABECALHO) {
        return false;
    }
    $version = ord($payload[2]);
    return $version === SpbSeguranca::VERSAO_2 || $version === SpbSeguranca::VERSAO_3;
}

function autoSftpConnect(array $config)
{
    $host = (string)($config['host'] ?? '');
    $port = (int)($config['port'] ?? 22);
    $username = (string)($config['username'] ?? '');
    $privateKey = (string)($config['private_key'] ?? '');
    $passphrase = (string)($config['passphrase'] ?? '');

    if ($host === '' || $username === '' || $privateKey === '') {
        throw new RuntimeException('Host, usuario e chave privada sao obrigatorios.');
    }
    if (!is_file($privateKey)) {
        throw new RuntimeException('Chave privada nao encontrada: ' . $privateKey);
    }

    $rsa = new Crypt_RSA();
    if ($passphrase !== '') {
        $rsa->setPassword($passphrase);
    }
    $keyContents = file_get_contents($privateKey);
    if ($keyContents === false || !$rsa->loadKey($keyContents)) {
        throw new RuntimeException('Falha ao carregar chave privada SFTP.');
    }

    $sftp = new Net_SFTP($host, $port, 15);
    if (!$sftp->login($username, $rsa)) {
        throw new RuntimeException('Falha de autenticacao no SFTP.');
    }

    return $sftp;
}

function autoDecryptSpbToUtf8Xml(string $payload, array $security): string
{
    $privateKeyPem = file_get_contents((string)$security['private_key']);
    $senderCertPem = file_get_contents((string)$security['sender_cert']);
    if ($privateKeyPem === false || $senderCertPem === false) {
        throw new RuntimeException('Nao foi possivel ler certificados/chave SPB.');
    }

    $privateKey = openssl_pkey_get_private($privateKeyPem, (string)$security['private_key_password']);
    if ($privateKey === false) {
        throw new RuntimeException('Falha ao abrir chave privada SPB.');
    }

    $xmlOriginal = SpbSeguranca::decifrarEVerificar($payload, $privateKey, $senderCertPem);
    $xmlUtf8 = function_exists('mb_convert_encoding')
        ? mb_convert_encoding($xmlOriginal, 'UTF-8', 'UTF-16BE')
        : $xmlOriginal;

    $dom = carregarXmlTexto($xmlUtf8);
    $dom->formatOutput = true;
    return (string)$dom->saveXML();
}

function autoListRemoteFiles($sftp, string $path, bool $recursive, int $limit): array
{
    $files = [];
    $queue = [autoNormalizeRemotePath($path)];
    $directoryType = defined('NET_SFTP_TYPE_DIRECTORY') ? NET_SFTP_TYPE_DIRECTORY : 2;

    while ($queue && count($files) < $limit) {
        $current = array_shift($queue);
        $rawList = $sftp->rawlist($current, false);
        if ($rawList === false) {
            continue;
        }

        foreach ($rawList as $entry => $attrs) {
            if ($entry === '.' || $entry === '..') {
                continue;
            }
            $entryPath = autoNormalizeRemotePath($current . '/' . $entry);
            $isDir = isset($attrs['type']) && (int)$attrs['type'] === $directoryType;
            if ($isDir) {
                if ($recursive) {
                    $queue[] = $entryPath;
                }
                continue;
            }
            $files[] = [
                'path' => $entryPath,
                'name' => $entry,
                'size' => isset($attrs['size']) ? (int)$attrs['size'] : 0,
                'mtime' => isset($attrs['mtime']) ? (int)$attrs['mtime'] : null,
            ];
            if (count($files) >= $limit) {
                break;
            }
        }
    }

    usort($files, static function (array $a, array $b): int {
        return strcmp($a['path'], $b['path']);
    });

    return $files;
}

function autoLoadSentXmls(array $dirs): array
{
    $items = [];
    $seen = [];
    foreach ($dirs as $dir) {
        if (!is_dir($dir)) {
            continue;
        }
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS)
        );
        foreach ($iterator as $file) {
            if (!$file->isFile()) {
                continue;
            }
            $path = $file->getPathname();
            $name = $file->getFilename();
            if (!preg_match('/\\.xml$/i', $name)) {
                continue;
            }
            try {
                $analysis = analisarXml(carregarXmlArquivo($path), $name);
                if ($analysis['tipo'] !== 'Aguardando') {
                    continue;
                }
                $base = normalizarNomArqBase($analysis['meta']['nom_arq'] ?? '');
                if ($base === '' || isset($seen[$base])) {
                    continue;
                }
                $seen[$base] = true;
                $items[] = ['arquivo' => $name, 'tipo' => 'Aguardando', 'resultado' => $analysis];
            } catch (Throwable $e) {
                continue;
            }
        }
    }
    return $items;
}

function autoDownloadDecryptReturns($sftp, array $remoteFiles, array $security, string $baseDir): array
{
    $retornos = [];
    $logs = [];
    $encryptedDir = $baseDir . '/criptografados';
    $xmlDir = $baseDir . '/xml';
    autoEnsureDir($encryptedDir);
    autoEnsureDir($xmlDir);

    foreach ($remoteFiles as $remote) {
        $remotePath = $remote['path'];
        $safeName = autoSafeName($remote['name']);
        $payload = $sftp->get($remotePath);
        if ($payload === false || $payload === '') {
            $logs[] = ['arquivo' => $remotePath, 'status' => 'erro', 'mensagem' => 'Nao foi possivel baixar'];
            continue;
        }

        $encryptedPath = $encryptedDir . '/' . date('His') . '_' . substr(sha1($remotePath), 0, 8) . '_' . $safeName;
        file_put_contents($encryptedPath, $payload);

        if (!autoIsSpbPayload($payload)) {
            $logs[] = ['arquivo' => $remotePath, 'status' => 'ignorado', 'mensagem' => 'Nao parece SPB'];
            continue;
        }

        try {
            $xml = autoDecryptSpbToUtf8Xml($payload, $security);
            $xmlName = $safeName . '_decriptado.xml';
            $xmlPath = $xmlDir . '/' . $xmlName;
            file_put_contents($xmlPath, $xml);
            $analysis = analisarXml(carregarXmlTexto($xml), $xmlName);
            if ($analysis['tipo'] === 'Aguardando') {
                $logs[] = ['arquivo' => $remotePath, 'status' => 'ignorado', 'mensagem' => 'Arquivo aguardando baixado; enviado deve vir dos XMLs locais'];
                continue;
            }
            $retornos[] = ['arquivo' => $xmlName, 'tipo' => $analysis['tipo'], 'resultado' => $analysis];
            $logs[] = ['arquivo' => $remotePath, 'status' => 'ok', 'mensagem' => 'Descriptografado como ' . $analysis['tipo']];
        } catch (Throwable $e) {
            $logs[] = ['arquivo' => $remotePath, 'status' => 'erro', 'mensagem' => $e->getMessage()];
        }
    }

    return [$retornos, $logs];
}

$homeDir = (string)($_SERVER['HOME'] ?? getenv('HOME') ?: '');
$externalCertBase = $homeDir !== '' ? rtrim($homeDir, '/\\') . '/certificados/certificados_nuclea' : '';
$localCertBase = __DIR__ . '/certificados_nuclea';

$sftpConfig = [
    'host' => 'sftp-prd.nucleaservicos.com.br',
    'port' => 22,
    'username' => 'SLC42403952PRD',
    'private_key' => autoFirstExistingPath([
        $externalCertBase . '/id_rsa4',
        $localCertBase . '/id_rsa4',
        __DIR__ . '/id_rsa4',
    ]),
];
$spbSecurityConfig = [
    'sender_cert' => autoFirstExistingPath([
        $externalCertBase . '/SLC-T011.cer',
        $localCertBase . '/SLC-T011.cer',
    ]),
    'private_key' => autoFirstExistingPath([
        $externalCertBase . '/Certnew.key',
        $localCertBase . '/Certnew.key',
    ]),
    'private_key_password' => 'Du25041977@',
];

$erro = '';
$resultado = null;
$logs = [];
$enviados = [];
$retornos = [];
$remoteFiles = [];
$downloadDir = '';
$remotePath = '/';
$recursive = false;
$limit = 80;

if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
    try {
        if (($_POST['acao'] ?? '') === 'exportar_xml') {
            enviarExportacaoXml(lerPayloadExportacao());
        }

        $remotePath = autoNormalizeRemotePath((string)($_POST['remote_path'] ?? '/'));
        $recursive = ($_POST['recursive'] ?? '') === 'S';
        $limit = max(1, min(500, (int)($_POST['limit'] ?? 80)));
        $passphrase = (string)($_POST['passphrase'] ?? '');
        if ($passphrase === '') {
            throw new RuntimeException('Informe a senha/passphrase SFTP.');
        }

        $sftpConfig['passphrase'] = $passphrase;
        $sftp = autoSftpConnect($sftpConfig);
        $remoteFiles = autoListRemoteFiles($sftp, $remotePath, $recursive, $limit);

        $downloadDir = __DIR__ . '/downloads/nuclea/' . date('Ymd_His');
        autoEnsureDir($downloadDir);
        [$retornos, $logs] = autoDownloadDecryptReturns($sftp, $remoteFiles, $spbSecurityConfig, $downloadDir);

        $sentDirs = [
            __DIR__ . '/uploads/nuclea',
            __DIR__ . '/../pagamentos/anexos/nuclea/aguardando',
            __DIR__ . '/../pagamentos/anexos/nuclea',
        ];
        $enviados = autoLoadSentXmls($sentDirs);

        if (count($enviados) === 0) {
            throw new RuntimeException('Nenhum XML enviado/aguardando foi encontrado nas pastas locais.');
        }
        if (count($retornos) === 0) {
            throw new RuntimeException('Nenhum retorno descriptografado foi encontrado no SFTP.');
        }

        $resultado = prepararMerge($enviados, $retornos);
    } catch (Throwable $e) {
        $erro = $e->getMessage();
    }
}
?>
<!doctype html>
<html lang="pt-br">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Merge Automatico SFTP Nuclea</title>
    <style>
        :root { --bg: #f3f6fb; --panel: #fff; --line: #d7e0ea; --text: #1f2933; --muted: #64748b; --blue: #0f4c81; --green: #0f766e; --red: #b42318; --amber: #92400e; }
        * { box-sizing: border-box; }
        body { margin: 0; background: var(--bg); color: var(--text); font-family: "Segoe UI", Tahoma, sans-serif; }
        .wrap { max-width: 1440px; margin: 24px auto; padding: 0 16px 32px; }
        h1 { margin: 0 0 6px; color: var(--blue); font-size: 24px; }
        h2 { margin: 0 0 10px; font-size: 18px; color: #243b53; }
        .muted { color: var(--muted); font-size: 13px; }
        .panel { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 16px; margin-top: 16px; }
        .form-grid { display: grid; grid-template-columns: 1fr 1fr 120px; gap: 12px; align-items: end; }
        label { display: block; font-size: 13px; font-weight: 700; margin-bottom: 6px; }
        input[type="text"], input[type="password"], input[type="number"] { width: 100%; min-height: 40px; border: 1px solid #c8d7ea; border-radius: 8px; padding: 0 10px; }
        button { min-height: 40px; border: 0; border-radius: 8px; padding: 0 16px; color: #fff; background: var(--blue); font-weight: 700; cursor: pointer; }
        .btn-export { background: var(--green); }
        .msg { border: 1px solid #fecdd3; color: var(--red); background: #fff1f2; padding: 12px; border-radius: 8px; margin-top: 16px; font-weight: 700; }
        .cards { display: grid; grid-template-columns: repeat(6, minmax(140px, 1fr)); gap: 10px; margin-top: 16px; }
        .card { background: #fbfdff; border: 1px solid var(--line); border-radius: 8px; padding: 12px; }
        .label { color: var(--muted); font-size: 12px; margin-bottom: 4px; }
        .value { font-weight: 800; font-size: 18px; }
        .value.total { color: var(--green); font-size: 22px; }
        table { width: 100%; border-collapse: collapse; font-size: 13px; }
        th, td { border-bottom: 1px solid #e2e8f0; padding: 8px; text-align: left; vertical-align: top; }
        th { background: #eef5ff; color: #243b53; position: sticky; top: 0; z-index: 1; }
        .num { text-align: right; white-space: nowrap; }
        .table-wrap { overflow: auto; max-height: 520px; border: 1px solid var(--line); border-radius: 8px; margin-top: 10px; }
        .status-erro { color: var(--red); font-weight: 800; }
        .status-ok { color: var(--green); font-weight: 800; }
        .status-pendente { color: var(--amber); font-weight: 800; }
        .badge { display: inline-block; border-radius: 999px; padding: 3px 8px; background: #eef2ff; font-size: 12px; font-weight: 800; white-space: nowrap; }
        @media (max-width: 900px) { .form-grid, .cards { grid-template-columns: 1fr; } }
    </style>
</head>
<body>
<div class="wrap">
    <h1>Merge Automatico SFTP Nuclea</h1>
    <div class="muted">Baixa arquivos do SFTP, descriptografa retornos recebidos, usa os XMLs enviados salvos localmente e executa o merge.</div>

    <div class="panel">
        <h2>Buscar No SFTP</h2>
        <form method="post">
            <input type="hidden" name="acao" value="sincronizar">
            <div class="form-grid">
                <div>
                    <label for="passphrase">Senha/passphrase SFTP</label>
                    <input id="passphrase" name="passphrase" type="password" required>
                </div>
                <div>
                    <label for="remote_path">Pasta remota</label>
                    <input id="remote_path" name="remote_path" type="text" value="<?php echo h($remotePath); ?>" required>
                </div>
                <div>
                    <label for="limit">Limite</label>
                    <input id="limit" name="limit" type="number" min="1" max="500" value="<?php echo h($limit); ?>">
                </div>
            </div>
            <p>
                <label>
                    <input type="checkbox" name="recursive" value="S" <?php echo $recursive ? 'checked' : ''; ?>>
                    Buscar subpastas
                </label>
            </p>
            <button type="submit">Baixar, descriptografar e fazer merge</button>
        </form>
    </div>

    <?php if ($erro !== ''): ?>
        <div class="msg"><?php echo h($erro); ?></div>
    <?php endif; ?>

    <?php if ($downloadDir !== ''): ?>
        <div class="panel">
            <h2>Sincronizacao</h2>
            <div class="muted">Arquivos salvos em: <?php echo h($downloadDir); ?></div>
            <div class="cards">
                <div class="card"><div class="label">Remotos encontrados</div><div class="value"><?php echo h(count($remoteFiles)); ?></div></div>
                <div class="card"><div class="label">XMLs enviados locais</div><div class="value"><?php echo h(count($enviados)); ?></div></div>
                <div class="card"><div class="label">Retornos descriptografados</div><div class="value"><?php echo h(count($retornos)); ?></div></div>
            </div>
            <div class="table-wrap">
                <table>
                    <thead><tr><th>Arquivo remoto</th><th>Status</th><th>Mensagem</th></tr></thead>
                    <tbody>
                    <?php foreach ($logs as $log): ?>
                        <tr>
                            <td><?php echo h($log['arquivo']); ?></td>
                            <td><span class="badge"><?php echo h($log['status']); ?></span></td>
                            <td><?php echo h($log['mensagem']); ?></td>
                        </tr>
                    <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
        </div>
    <?php endif; ?>

    <?php if ($resultado): ?>
        <?php
            $resumo = $resultado['resumo'];
            $payloadExportacao = payloadExportacao($resultado, implode(', ', array_column($enviados, 'arquivo')));
        ?>
        <div class="panel">
            <h2>Resumo Do Merge</h2>
            <form method="post">
                <input type="hidden" name="acao" value="exportar_xml">
                <input type="hidden" name="payload_exportacao" value="<?php echo h($payloadExportacao); ?>">
                <button type="submit" class="btn-export">Exportar XML</button>
            </form>
            <div class="cards">
                <div class="card"><div class="label">Total enviado</div><div class="value total">R$ <?php echo dinheiro($resumo['total_geral']); ?></div></div>
                <div class="card"><div class="label">NULiquid</div><div class="value"><?php echo h($resumo['qtd_nuliquid']); ?></div></div>
                <div class="card"><div class="label">Liquidados OK</div><div class="value status-ok"><?php echo h($resumo['qtd_liquid_ok']); ?></div></div>
                <div class="card"><div class="label">Com erro</div><div class="value <?php echo $resumo['qtd_liquid_erro'] > 0 ? 'status-erro' : ''; ?>"><?php echo h($resumo['qtd_liquid_erro']); ?></div></div>
                <div class="card"><div class="label">Pendentes</div><div class="value <?php echo ($resumo['qtd_sem_cod_ocorc'] + $resumo['qtd_liquid_sem_retorno']) > 0 ? 'status-pendente' : ''; ?>"><?php echo h($resumo['qtd_sem_cod_ocorc'] + $resumo['qtd_liquid_sem_retorno']); ?></div></div>
                <div class="card"><div class="label">Retornos ignorados</div><div class="value"><?php echo h($resumo['qtd_retorno_ignorado']); ?></div></div>
            </div>
        </div>

        <div class="panel">
            <h2>Status Por NULiquid</h2>
            <div class="table-wrap">
                <table>
                    <thead>
                    <tr>
                        <th>Status</th><th>NULiquid</th><th>CodOcorc</th><th>Controle credor</th><th>CNPJ/CPF</th><th>Nome</th><th>Arranjo</th><th>DtPgto</th><th class="num">Valor</th><th>Arquivos</th>
                    </tr>
                    </thead>
                    <tbody>
                    <?php foreach ($resultado['status_liquidacoes'] as $linha): ?>
                        <tr>
                            <td class="status-<?php echo h($linha['classe']); ?>"><?php echo h($linha['status']); ?></td>
                            <td><?php echo h($linha['nu_liquid'] === '' ? '-' : $linha['nu_liquid']); ?></td>
                            <td class="<?php echo $linha['cod_ocorc'] !== '' && $linha['cod_ocorc'] !== '00' ? 'status-erro' : ''; ?>"><?php echo h($linha['cod_ocorc'] === '' ? '-' : $linha['cod_ocorc']); ?></td>
                            <td><?php echo h($linha['controle'] === '' ? '-' : $linha['controle']); ?></td>
                            <td><?php echo h($linha['cnpj'] === '' ? '-' : $linha['cnpj']); ?></td>
                            <td><?php echo h($linha['nome'] === '' ? '-' : $linha['nome']); ?></td>
                            <td><?php echo h($linha['arranjo'] === '' ? '-' : $linha['arranjo']); ?></td>
                            <td><?php echo h($linha['dt_pgto'] === '' ? '-' : $linha['dt_pgto']); ?></td>
                            <td class="num">R$ <?php echo dinheiro($linha['valor']); ?></td>
                            <td><?php echo h($linha['arquivos'] === '' ? '-' : $linha['arquivos']); ?></td>
                        </tr>
                    <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
        </div>

        <div class="panel">
            <h2>Arquivos Usados</h2>
            <div class="table-wrap">
                <table>
                    <thead><tr><th>Arquivo</th><th>Tipo</th><th>NomArq</th><th class="num">Pontos</th><th class="num">NULiquid</th><th class="num">Total</th></tr></thead>
                    <tbody>
                    <?php foreach ($resultado['arquivos'] as $arquivo): ?>
                        <tr>
                            <td><?php echo h($arquivo['arquivo']); ?></td>
                            <td><span class="badge"><?php echo h($arquivo['tipo']); ?></span></td>
                            <td><?php echo h($arquivo['nom_arq']); ?></td>
                            <td class="num"><?php echo h($arquivo['qtd_pontos']); ?></td>
                            <td class="num"><?php echo h($arquivo['qtd_nuliquid']); ?></td>
                            <td class="num">R$ <?php echo dinheiro($arquivo['total_geral']); ?></td>
                        </tr>
                    <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
        </div>

        <?php if (!empty($resultado['ignorados'])): ?>
            <div class="panel">
                <h2>Ignorados</h2>
                <div class="table-wrap">
                    <table>
                        <thead><tr><th>Arquivo</th><th>Motivo</th></tr></thead>
                        <tbody>
                        <?php foreach ($resultado['ignorados'] as $ignorado): ?>
                            <tr><td><?php echo h($ignorado['arquivo']); ?></td><td><?php echo h($ignorado['motivo']); ?></td></tr>
                        <?php endforeach; ?>
                        </tbody>
                    </table>
                </div>
            </div>
        <?php endif; ?>
    <?php endif; ?>
</div>
</body>
</html>
