<?php

require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../config/config.php';
require_once __DIR__ . '/../middleware/auth.php';
require_once __DIR__ . '/../helpers/response.php';
require_once __DIR__ . '/../helpers/token.php';

// ============================================
// AUTENTICAÇÃO
// ============================================

$company = authenticateCompany();
$companyId = $company['id'];

// ============================================
// PARSE DO PAYLOAD
// ============================================

$payload = json_decode(file_get_contents('php://input'), true);

if (!$payload) {
    jsonResponse(['error' => 'Invalid JSON'], 400);
}

// ============================================
// VALIDAÇÃO DE CAMPOS OBRIGATÓRIOS
// ============================================

$requiredFields = [
    'customer' => ['name', 'email', 'document'],
    'receivable' => ['document_number', 'issue_date', 'due_date', 'amount']
];

foreach ($requiredFields as $section => $fields) {
    if (!isset($payload[$section])) {
        jsonResponse(['error' => "Missing section: {$section}"], 400);
    }
    
    foreach ($fields as $field) {
        if (!isset($payload[$section][$field]) || trim($payload[$section][$field]) === '') {
            jsonResponse(['error' => "Missing required field: {$section}.{$field}"], 400);
        }
    }
}

// ============================================
// VALIDAÇÃO DE FORMATO - EMAIL
// ============================================

if (!filter_var($payload['customer']['email'], FILTER_VALIDATE_EMAIL)) {
    jsonResponse(['error' => 'Invalid email format'], 400);
}

// ============================================
// VALIDAÇÃO E NORMALIZAÇÃO - CPF/CNPJ
// ============================================

$document = preg_replace('/\D/', '', $payload['customer']['document']);

if (strlen($document) !== 11 && strlen($document) !== 14) {
    jsonResponse(['error' => 'Invalid document format (must be 11 or 14 digits)'], 400);
}

// Validação básica de CPF/CNPJ (opcional mas recomendado)
if (strlen($document) === 11) {
    // Validação de CPF
    if (preg_match('/^(\d)\1{10}$/', $document)) {
        jsonResponse(['error' => 'Invalid CPF (repeated digits)'], 400);
    }
} elseif (strlen($document) === 14) {
    // Validação de CNPJ
    if (preg_match('/^(\d)\1{13}$/', $document)) {
        jsonResponse(['error' => 'Invalid CNPJ (repeated digits)'], 400);
    }
}

// ============================================
// VALIDAÇÃO DE DATAS
// ============================================

$issueDate = trim($payload['receivable']['issue_date']);
$dueDate = trim($payload['receivable']['due_date']);

if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $issueDate) || !strtotime($issueDate)) {
    jsonResponse(['error' => 'Invalid issue_date format (use YYYY-MM-DD)'], 400);
}

if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $dueDate) || !strtotime($dueDate)) {
    jsonResponse(['error' => 'Invalid due_date format (use YYYY-MM-DD)'], 400);
}

// Valida: vencimento não pode ser antes da emissão
if (strtotime($dueDate) < strtotime($issueDate)) {
    jsonResponse(['error' => 'due_date cannot be before issue_date'], 400);
}

// ============================================
// VALIDAÇÃO DE VALOR
// ============================================

$amount = floatval($payload['receivable']['amount']);

if ($amount <= 0) {
    jsonResponse(['error' => 'Amount must be greater than 0'], 400);
}

// ============================================
// VALIDAÇÃO DE CAMPOS OPCIONAIS
// ============================================

// invoice_number deve ser inteiro se fornecido
if (isset($payload['receivable']['invoice_number']) && 
    $payload['receivable']['invoice_number'] !== null &&
    $payload['receivable']['invoice_number'] !== '') {
    
    if (!is_numeric($payload['receivable']['invoice_number']) || 
        intval($payload['receivable']['invoice_number']) <= 0) {
        jsonResponse(['error' => 'invoice_number must be a positive integer'], 400);
    }
}

// ============================================
// INÍCIO DA TRANSAÇÃO
// ============================================

$db = Database::getConnection();
$db->begin_transaction();

try {
    
    // ============================================
// VERIFICAÇÃO: JÁ EXISTE? REENVIA!
// ============================================

$stmt = $db->prepare(
    'SELECT id, customer_id FROM receivables 
     WHERE company_id = ? AND document_number = ? 
     LIMIT 1'
);
$stmt->bind_param('is', $companyId, $payload['receivable']['document_number']);
$stmt->execute();
$result = $stmt->get_result();

if ($result->num_rows > 0) {
    // Receivable JÁ EXISTE! Reenvia email ao invés de rejeitar
    $existingReceivable = $result->fetch_assoc();
    $receivableId = $existingReceivable['id'];
    $customerId = $existingReceivable['customer_id'];
    
    // Busca token existente
    $stmt = $db->prepare(
        'SELECT token, expires_at 
         FROM access_tokens 
         WHERE email_send_id IN (
             SELECT email_send_id 
             FROM email_send_receivables 
             WHERE receivable_id = ?
         )
         ORDER BY created_at DESC 
         LIMIT 1'
    );
    $stmt->bind_param('i', $receivableId);
    $stmt->execute();
    $tokenResult = $stmt->get_result();
    
    if ($tokenResult->num_rows > 0) {
        $tokenData = $tokenResult->fetch_assoc();
        $token = $tokenData['token'];
        $expiresAt = $tokenData['expires_at'];
    } else {
        // Não tem token? Cria um novo
        $token = generateToken();
        $expirationDays = $company['token_expiration_days'] ?? DEFAULT_TOKEN_EXPIRATION_DAYS;
        $expiresAt = date('Y-m-d H:i:s', strtotime("+{$expirationDays} days"));
        
        $stmt = $db->prepare(
            'INSERT INTO access_tokens (email_send_id, token, expires_at, created_at)
             VALUES (NULL, ?, ?, NOW())'
        );
        $stmt->bind_param('ss', $token, $expiresAt);
        $stmt->execute();
    }
    
    $db->commit();
    
    error_log("Receivable {$receivableId} already exists. Returning existing data for resend.");
    
    // Retorna dados existentes (batch vai usar pra reenviar)
    jsonResponse([
        'success' => true,
        'receivable_id' => $receivableId,
        'customer_id' => $customerId,
        'email_send_id' => null, // Será criado no batch
        'access_token_id' => null,
        'access_url' => BASE_URL . '/receivable/' . $token,
        'token' => $token,
        'expires_at' => $expiresAt,
        'expiration_days' => $company['token_expiration_days'] ?? DEFAULT_TOKEN_EXPIRATION_DAYS,
        'is_resend' => true // Flag pra batch saber que é reenvio
    ], 201);
}
    
    // ============================================
    // PASSO 1: CUSTOMER - BUSCA OU INSERE
    // ============================================
    
    // Primeiro tenta buscar se já existe
    $stmt = $db->prepare(
        'SELECT id FROM billing_customers 
         WHERE company_id = ? AND document = ? 
         LIMIT 1'
    );
    $stmt->bind_param('is', $companyId, $document);
    $stmt->execute();
    $result = $stmt->get_result();
    
    if ($result->num_rows > 0) {
        // Cliente existe, pega o ID e atualiza dados
        $customerId = $result->fetch_assoc()['id'];
        
        $stmt = $db->prepare(
            'UPDATE billing_customers 
             SET name = ?, email = ?, updated_at = NOW()
             WHERE id = ?'
        );
        $stmt->bind_param('ssi', 
            $payload['customer']['name'],
            $payload['customer']['email'],
            $customerId
        );
        $stmt->execute();
        
    } else {
        // Cliente não existe, insere novo
        $stmt = $db->prepare(
            'INSERT INTO billing_customers 
             (company_id, name, email, document, created_at)
             VALUES (?, ?, ?, ?, NOW())'
        );
        $stmt->bind_param('isss',
            $companyId,
            $payload['customer']['name'],
            $payload['customer']['email'],
            $document
        );
        $stmt->execute();
        $customerId = $stmt->insert_id;
    }

    // ============================================
    // PASSO 2: RECEIVABLE
    // ============================================
    
    // Prepara campos opcionais
    $orderId = $payload['receivable']['order_id'] ?? null;
    $orderNumber = $payload['receivable']['order_number'] ?? null;
    $quoteNumber = $payload['receivable']['quote_number'] ?? null;
    $customerPONumber = $payload['receivable']['customer_po_number'] ?? null;
    $invoiceSeries = $payload['receivable']['invoice_series'] ?? null;
    $invoiceNumber = isset($payload['receivable']['invoice_number']) && 
                     $payload['receivable']['invoice_number'] !== '' 
                     ? intval($payload['receivable']['invoice_number']) 
                     : null;
    $invoiceKey = $payload['receivable']['invoice_key'] ?? null;
    $barcode = $payload['receivable']['barcode'] ?? null;
    
    $stmt = $db->prepare(
        'INSERT INTO receivables
        (company_id, customer_id, order_id, document_number, order_number,
         quote_number, customer_po_number, invoice_series, invoice_number,
         invoice_key, barcode, issue_date, due_date, amount, created_at)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())'
    );

    $stmt->bind_param(
        'iiissssisssssd',
        $companyId,
        $customerId,
        $orderId,
        $payload['receivable']['document_number'],
        $orderNumber,
        $quoteNumber,
        $customerPONumber,
        $invoiceSeries,
        $invoiceNumber,
        $invoiceKey,
        $barcode,
        $issueDate,
        $dueDate,
        $amount
    );
    $stmt->execute();
    $receivableId = $stmt->insert_id;

    // ============================================
	// PASSO 3: EMAIL SEND (CONDICIONAL!)
	// ============================================

	$skipEmail = $payload['skip_email'] ?? false;

	if (!$skipEmail) {
		
		// Gera subject padrão se não fornecido
		$subject = $payload['email']['subject'] ?? null;
		
		if (!$subject) {
			if ($invoiceNumber) {
				$subject = 'Documentos Fiscais Disponíveis - NF ' . $invoiceNumber;
			} else {
				$subject = 'Documentos Fiscais Disponíveis - Doc ' . $payload['receivable']['document_number'];
			}
		}
		
		$stmt = $db->prepare(
			'INSERT INTO email_sends (customer_id, subject, sent_at, status, created_at)
			 VALUES (?, ?, NOW(), "sent", NOW())'
		);
		$stmt->bind_param('is', $customerId, $subject);
		$stmt->execute();
		$emailSendId = $stmt->insert_id;
		
		// Relaciona email_send com receivable
		$stmt = $db->prepare(
			'INSERT INTO email_send_receivables (email_send_id, receivable_id)
			 VALUES (?, ?)'
		);
		$stmt->bind_param('ii', $emailSendId, $receivableId);
		$stmt->execute();
		
	} else {
		// Batch mode: pula email (será enviado agrupado depois)
		$emailSendId = null;
		error_log("Skipping individual email (batch mode) for receivable_id: {$receivableId}");
	}

    // ============================================
	// PASSO 4: ACCESS TOKEN
	// ============================================

	$token = generateToken();

	// Usa token_expiration_days da empresa, ou padrão do sistema
	$expirationDays = $company['token_expiration_days'] ?? DEFAULT_TOKEN_EXPIRATION_DAYS;
	$expiresAt = date('Y-m-d H:i:s', strtotime("+{$expirationDays} days"));

	// Access token sempre é criado (mesmo sem email individual)
	$emailSendIdForToken = $emailSendId ?? null;

	$stmt = $db->prepare(
		'INSERT INTO access_tokens (email_send_id, token, expires_at, created_at)
		 VALUES (?, ?, ?, NOW())'
	);
	$stmt->bind_param('iss', $emailSendIdForToken, $token, $expiresAt);
	$stmt->execute();
	$accessTokenId = $stmt->insert_id;

    // ============================================
    // PASSO 5: SENDGRID - DISPARO REAL
    // ============================================
    
	if (!$skipEmail) {
		require_once __DIR__ . '/../helpers/sendgrid.php';
		
		// Prepara dados para o email
		$receivableData = [
			'id' => $receivableId,
			'document_number' => $payload['receivable']['document_number'],
			'invoice_number' => $invoiceNumber,
			'due_date' => $dueDate,
			'amount' => $amount
		];
		
		$customerData = [
			'name' => $payload['customer']['name'],
			'email' => $payload['customer']['email']
		];
		
		$accessUrl = BASE_URL . '/receivable/' . $token;
		
		// Envia email
		$emailResult = sendReceivableEmail($receivableData, $customerData, $token, $accessUrl);
		
		if ($emailResult) {
			// Pega o message_id (pode ser null se não veio no header)
			$messageId = $emailResult['message_id'] ?? null;
			
			if ($messageId && $emailSendId) { 
				// Sucesso COM message_id
				$stmt = $db->prepare(
					'UPDATE email_sends 
					 SET sendgrid_message_id = ?, status = "sent"
					 WHERE id = ?'
				);
				$stmt->bind_param('si', $messageId, $emailSendId);
				$stmt->execute();
				
				error_log('Email sent successfully. Message ID: ' . $messageId);
			} else {
				// Sucesso MAS sem message_id no header
				error_log('Email sent successfully but no message_id in header');
			}
			
		} else {
			// Falhou no envio
			error_log('Failed to send email for receivable_id: ' . $receivableId);
		
			if ($emailSendId) {
				$stmt = $db->prepare(
					'UPDATE email_sends 
					 SET status = "failed"
					 WHERE id = ?'
				);
				$stmt->bind_param('i', $emailSendId);
				$stmt->execute();
			}
		}
	}

    // ============================================
    // COMMIT
    // ============================================
    
    $db->commit();

    // ============================================
    // RESPOSTA DE SUCESSO
    // ============================================
    
    jsonResponse([
        'success' => true,
        'receivable_id' => $receivableId,
        'customer_id' => $customerId,
        'email_send_id' => $emailSendId,
        'access_token_id' => $accessTokenId,
        'access_url' => BASE_URL . '/receivable/' . $token,
        'token' => $token,
        'expires_at' => $expiresAt,
        'expiration_days' => $expirationDays
    ], 201);

} catch (mysqli_sql_exception $e) {
    $db->rollback();
    
    // Log detalhado do erro MySQL
    error_log('=== MySQL Error in send.php ===');
    error_log('Message: ' . $e->getMessage());
    error_log('Code: ' . $e->getCode());
    error_log('Company ID: ' . $companyId);
    error_log('Document Number: ' . ($payload['receivable']['document_number'] ?? 'N/A'));
    error_log('Payload: ' . json_encode($payload, JSON_PRETTY_PRINT));
    error_log('================================');
    
    // Tratamento de erros específicos
    if ($e->getCode() === 1062) { // Duplicate entry
        // Tenta identificar qual constraint foi violada
        if (strpos($e->getMessage(), 'uq_company_document_number') !== false) {
            jsonResponse([
                'error' => 'Receivable with this document_number already exists'
            ], 409);
        } elseif (strpos($e->getMessage(), 'uq_company_document') !== false) {
            jsonResponse([
                'error' => 'Customer with this document already exists for this company'
            ], 409);
        } else {
            jsonResponse([
                'error' => 'Duplicate entry detected'
            ], 409);
        }
    }
    
    jsonResponse(['error' => 'Database error'], 500);
    
} catch (Exception $e) {
    $db->rollback();
    
    // Log detalhado do erro geral
    error_log('=== General Error in send.php ===');
    error_log('Message: ' . $e->getMessage());
    error_log('File: ' . $e->getFile());
    error_log('Line: ' . $e->getLine());
    error_log('Trace: ' . $e->getTraceAsString());
    error_log('Payload: ' . json_encode($payload, JSON_PRETTY_PRINT));
    error_log('skip_email: ' . ($payload['skip_email'] ?? 'not set'));
    error_log('===================================');
    
    // RETORNA ERRO MAIS DETALHADO
    jsonResponse([
        'error' => 'Internal server error',
        'message' => $e->getMessage(),
        'file' => basename($e->getFile()),
        'line' => $e->getLine()
    ], 500);
}