<?php

require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../config/config.php';

// ============================================
// FUNÇÃO: Pegar IP real
// ============================================

function getRealIpAddress() {
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        return trim($ips[0]);
    }
    
    if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
        return $_SERVER['HTTP_X_REAL_IP'];
    }
    
    return $_SERVER['REMOTE_ADDR'] ?? 'unknown';
}

// ============================================
// VALIDAÇÃO DOS PARÂMETROS
// ============================================

if (!isset($_GET['token']) || trim($_GET['token']) === '') {
    http_response_code(400);
    die('Missing token parameter');
}

if (!isset($_GET['type']) || trim($_GET['type']) === '') {
    http_response_code(400);
    die('Missing type parameter');
}

$token = trim($_GET['token']);
$type = trim($_GET['type']);

// ============================================
// VALIDAÇÃO DO ID DO RECEIVABLE
// ============================================

if (!isset($_GET['id']) || trim($_GET['id']) === '') {
    http_response_code(400);
    die('Missing receivable id parameter');
}

$receivableId = (int)$_GET['id'];

if ($receivableId <= 0) {
    http_response_code(400);
    die('Invalid receivable id');
}

// Validação de formato do token
if (strlen($token) < 32 || strlen($token) > 128) {
    http_response_code(400);
    die('Invalid token format');
}

// Tipos permitidos
$allowedTypes = ['boleto', 'invoice_pdf', 'invoice_xml'];

if (!in_array($type, $allowedTypes)) {
    http_response_code(400);
    die('Invalid type. Allowed: ' . implode(', ', $allowedTypes));
}

// ============================================
// VALIDA TOKEN E BUSCA DADOS
// ============================================

$db = Database::getConnection();

$stmt = $db->prepare(
    'SELECT 
        t.id as access_token_id,
        r.id as receivable_id,
        r.document_number,
        r.invoice_key,
        r.customer_id,
        c.company_id
     FROM access_tokens t
     INNER JOIN email_send_receivables esr ON esr.email_send_id = t.email_send_id
     INNER JOIN receivables r ON r.id = esr.receivable_id
     INNER JOIN billing_customers c ON c.id = r.customer_id
     WHERE t.token = ? 
     AND r.id = ?
     AND t.expires_at >= NOW()
     LIMIT 1'
);

$stmt->bind_param('si', $token, $receivableId);
$stmt->execute();
$result = $stmt->get_result();

if ($result->num_rows === 0) {
    http_response_code(404);
    die('Invalid or expired token');
}

$data = $result->fetch_assoc();

// ============================================
// MONTA CAMINHO DO ARQUIVO
// ============================================

// Estrutura: /storage/company_{id}/receivables/{document_number}/
$baseDir = UPLOAD_PATH . '/company_' . $data['company_id'] . '/receivables/' . $data['document_number'];

$filePath = null;
$fileName = null;
$mimeType = null;
$actionLog = null;

switch ($type) {
    case 'boleto':
        $filePath = $baseDir . '/boleto.pdf';
        $fileName = 'Boleto_' . $data['document_number'] . '.pdf';
        $mimeType = 'application/pdf';
        $actionLog = 'downloaded_boleto';
        break;
        
    case 'invoice_pdf':
        if (!$data['invoice_key']) {
            http_response_code(404);
            die('Invoice key not available');
        }
        $filePath = $baseDir . '/nfe_' . $data['invoice_key'] . '.pdf';
        $fileName = 'NotaFiscal_' . $data['invoice_key'] . '.pdf';
        $mimeType = 'application/pdf';
        $actionLog = 'downloaded_invoice_pdf';
        break;
        
    case 'invoice_xml':
        if (!$data['invoice_key']) {
            http_response_code(404);
            die('Invoice key not available');
        }
        $filePath = $baseDir . '/nfe_' . $data['invoice_key'] . '.xml';
        $fileName = 'NotaFiscal_' . $data['invoice_key'] . '.xml';
        $mimeType = 'application/xml';
        $actionLog = 'downloaded_invoice_xml';
        break;
}

// ============================================
// PROTEÇÃO: Path Traversal
// ============================================

$realPath = realpath($filePath);

// Verifica se o arquivo existe
if (!$realPath || !file_exists($realPath)) {
    http_response_code(404);
    die('File not found');
}

// Verifica se o arquivo está dentro do diretório permitido
$allowedBasePath = realpath(UPLOAD_PATH);
if (strpos($realPath, $allowedBasePath) !== 0) {
    http_response_code(403);
    error_log('Path traversal attempt detected: ' . $filePath);
    die('Access denied');
}

// ============================================
// REGISTRA O DOWNLOAD
// ============================================

$stmt = $db->prepare(
    'INSERT INTO access_logs 
     (access_token_id, ip_address, user_agent, action, accessed_at)
     VALUES (?, ?, ?, ?, NOW())'
);

$ipAddress = getRealIpAddress();
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';

$stmt->bind_param('isss',
    $data['access_token_id'],
    $ipAddress,
    $userAgent,
    $actionLog
);
$stmt->execute();

// ============================================
// SERVE O ARQUIVO
// ============================================

// Limpa qualquer output anterior
if (ob_get_level()) {
    ob_end_clean();
}

// Headers de segurança
header('Content-Type: ' . $mimeType);
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Length: ' . filesize($realPath));
header('Cache-Control: no-cache, must-revalidate');
header('Expires: 0');
header('Pragma: public');

// Previne XSS
header('X-Content-Type-Options: nosniff');

// Streaming seguro (não carrega arquivo inteiro na memória)
$handle = fopen($realPath, 'rb');
if ($handle) {
    while (!feof($handle)) {
        echo fread($handle, 8192); // Lê em chunks de 8KB
        flush();
    }
    fclose($handle);
} else {
    http_response_code(500);
    die('Failed to read file');
}

exit;