<?php

declare(strict_types=1);

use GalpaoImperial\Api\AsaasClient;
use GalpaoImperial\Api\Database;
use GalpaoImperial\Api\HttpException;
use function GalpaoImperial\Api\corsPreflight;
use function GalpaoImperial\Api\ensureMethod;
use function GalpaoImperial\Api\generateOrderNumber;
use function GalpaoImperial\Api\generateTicketCode;
use function GalpaoImperial\Api\jsonBody;
use function GalpaoImperial\Api\jsonResponse;
use function GalpaoImperial\Api\mapAsaasPaymentStatus;
use function GalpaoImperial\Api\normalizeCpf;
use function GalpaoImperial\Api\normalizePhone;
use function GalpaoImperial\Api\required;
use function GalpaoImperial\Api\todayIso;

corsPreflight($method);
ensureMethod('POST', $method);

$payload = jsonBody();
required($payload, ['eventId', 'batchId', 'name', 'email', 'cpf', 'quantity']);

$pdo = Database::connection();

$eventStmt = $pdo->prepare(
    'SELECT e.*, b.id AS batch_id, b.name AS batch_name, b.price, b.quantity, b.sold, b.is_available, b.status AS batch_status
     FROM events e
     INNER JOIN event_batches b ON b.event_id = e.id
     WHERE e.id = :eventId AND b.id = :batchId
     LIMIT 1'
);
$eventStmt->execute([
    'eventId' => $payload['eventId'],
    'batchId' => $payload['batchId'],
]);
$selected = $eventStmt->fetch();

if (!$selected) {
    throw new HttpException(404, 'Evento ou lote não encontrado.');
}

$saleEnabledStatuses = ['active', 'featured', 'last_tickets'];
if (!in_array((string) $selected['status'], $saleEnabledStatuses, true)) {
    throw new HttpException(422, 'Este evento nao esta disponivel para compra.');
}

$quantity = max(1, min(10, (int) $payload['quantity']));
$ticketsPerUnit = max(1, min(20, (int) ($selected['tickets_per_unit'] ?? 1)));
$ticketQuantity = $quantity * $ticketsPerUnit;
$available = $selected['quantity'] === null ? 999999 : ((int) $selected['quantity'] - (int) $selected['sold']);

if (!(bool) $selected['is_available'] || $selected['batch_status'] !== 'active' || $available < $quantity) {
    throw new HttpException(422, 'Este lote não possui disponibilidade suficiente.');
}

$settingsTax = 2.0;
$asaasFeePerOrder = 0.99;
try {
    $settings = $pdo->query('SELECT service_tax, asaas_fee_per_order FROM site_settings ORDER BY id ASC LIMIT 1')->fetch() ?: [];
    $settingsTax = (float) ($settings['service_tax'] ?? 2);
    $asaasFeePerOrder = (float) ($settings['asaas_fee_per_order'] ?? 0.99);
} catch (Throwable) {
    $settingsTax = 2.0;
    $asaasFeePerOrder = 0.99;
}
$settingsTax = max(0.0, $settingsTax);
$asaasFeePerOrder = max(0.0, $asaasFeePerOrder);
$subtotalValue = round(((float) $selected['price']) * $quantity, 2);
$serviceFeeValue = round($settingsTax * $quantity, 2);
$asaasFeeValue = round($asaasFeePerOrder, 2);
$orderNumber = generateOrderNumber();
$totalValue = round($subtotalValue + $serviceFeeValue + $asaasFeeValue, 2);
$platformNetFeeValue = $serviceFeeValue;
$organizerNetValue = $subtotalValue;
$externalReference = 'ticket_' . uniqid();
$customerName = trim((string) $payload['name']);
$customerEmail = trim((string) $payload['email']);
$customerWhatsapp = normalizePhone((string) $payload['whatsapp']);
$customerCpf = normalizeCpf((string) $payload['cpf']);
$paymentMethod = (string) ($payload['paymentMethod'] ?? $payload['payment_method'] ?? 'pix');
$paymentMethod = $paymentMethod === 'credit_card' ? 'credit_card' : 'pix';
$billingType = $paymentMethod === 'credit_card' ? 'CREDIT_CARD' : 'PIX';

$promoterCode = trim((string) ($payload['promoterCode'] ?? $payload['promoter_code'] ?? ''));
$promoterId = null;
if ($promoterCode !== '') {
    try {
        $promoterStmt = $pdo->prepare('SELECT id, code FROM promoters WHERE code = :code AND is_active = 1 LIMIT 1');
        $promoterStmt->execute(['code' => $promoterCode]);
        $promoter = $promoterStmt->fetch();
        if ($promoter) {
            $promoterId = (int) $promoter['id'];
            $promoterCode = (string) $promoter['code'];
        } else {
            $promoterCode = '';
        }
    } catch (Throwable) {
        $promoterCode = '';
        $promoterId = null;
    }
}

$ticketHolders = is_array($payload['ticketHolders'] ?? null) ? $payload['ticketHolders'] : [];
$normalizeTicketHolder = static function (int $index) use ($ticketHolders, $customerName, $customerEmail): array {
    if ($index === 0) {
        return ['name' => $customerName, 'email' => $customerEmail];
    }

    $holder = is_array($ticketHolders[$index - 1] ?? null) ? $ticketHolders[$index - 1] : [];
    $name = trim((string) ($holder['name'] ?? ''));
    $email = trim((string) ($holder['email'] ?? ''));
    if ($name === '') {
        $name = $customerName;
    }
    if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $email = $customerEmail;
    }
    return ['name' => $name, 'email' => $email];
};

$asaas = new AsaasClient();
$customer = null;
$payment = null;
$pixQrCode = null;

if ($asaas->isEnabled()) {
    $customerPayload = [
        'name' => $customerName,
        'cpfCnpj' => $customerCpf,
        'email' => $customerEmail,
        'externalReference' => $externalReference,
        'notificationDisabled' => true,
    ];
    if ($customerWhatsapp !== '') {
        $customerPayload['mobilePhone'] = $customerWhatsapp;
    }

    $customer = $asaas->createOrUpdateCustomer($customerPayload);

    $payment = $asaas->createPayment([
        'customer' => $customer['id'],
        'billingType' => $billingType,
        'value' => $totalValue,
        'dueDate' => todayIso(),
        'description' => sprintf('%s - %s x%d', $selected['title'], $selected['batch_name'], $quantity),
        'externalReference' => $externalReference,
    ]);

    if ($paymentMethod === 'pix') {
        $pixQrCode = $asaas->getPixQrCode($payment['id']);
    }

    if (isset($payment['value'], $payment['netValue'])) {
        $asaasFeeValue = max(0.0, round((float) $payment['value'] - (float) $payment['netValue'], 2));
    }
}

$initialPaymentStatus = mapAsaasPaymentStatus($payment['status'] ?? null);

$pdo->beginTransaction();

try {
    $insertOrder = $pdo->prepare(
        'INSERT INTO orders (
            order_number, order_type, event_id, customer_name, customer_email, customer_whatsapp,
            customer_cpf, total_value, subtotal_value, platform_fee_value, asaas_fee_value, organizer_net_value,
            payment_method, payment_status, ticket_status, quantity,
            asaas_customer_id, asaas_payment_id, asaas_invoice_url, external_reference, raw_response_json
        ) VALUES (
            :orderNumber, :orderType, :eventId, :customerName, :customerEmail, :customerWhatsapp,
            :customerCpf, :totalValue, :subtotalValue, :platformFeeValue, :asaasFeeValue, :organizerNetValue,
            :paymentMethod, :paymentStatus, :ticketStatus, :quantity,
            :asaasCustomerId, :asaasPaymentId, :asaasInvoiceUrl, :externalReference, :rawResponseJson
        )'
    );

    $insertOrder->execute([
        'orderNumber' => $orderNumber,
        'orderType' => 'ticket',
        'eventId' => $selected['id'],
        'customerName' => $customerName,
        'customerEmail' => $customerEmail,
        'customerWhatsapp' => $customerWhatsapp,
        'customerCpf' => $customerCpf,
        'totalValue' => $totalValue,
        'subtotalValue' => $subtotalValue,
        'platformFeeValue' => $serviceFeeValue,
        'asaasFeeValue' => $asaasFeeValue,
        'organizerNetValue' => $organizerNetValue,
        'paymentMethod' => $paymentMethod,
        'paymentStatus' => $initialPaymentStatus,
        'ticketStatus' => 'unused',
        'quantity' => $quantity,
        'asaasCustomerId' => $customer['id'] ?? null,
        'asaasPaymentId' => $payment['id'] ?? null,
        'asaasInvoiceUrl' => $payment['invoiceUrl'] ?? null,
        'externalReference' => $externalReference,
        'rawResponseJson' => json_encode([
            'customer' => $customer,
            'payment' => $payment,
            'pixQrCode' => $pixQrCode,
            'pricing' => [
                'subtotalValue' => $subtotalValue,
                'serviceFeePerTicket' => $settingsTax,
                'serviceFeeValue' => $serviceFeeValue,
                'asaasFeePerOrder' => $asaasFeeValue,
                'organizerNetValue' => $organizerNetValue,
                'platformNetFeeValue' => $platformNetFeeValue,
                'totalValue' => $totalValue,
                'ticketsPerUnit' => $ticketsPerUnit,
                'ticketQuantity' => $ticketQuantity,
            ],
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
    ]);

    $orderId = (int) $pdo->lastInsertId();

    if ($promoterId !== null && $promoterCode !== '') {
        try {
            $updatePromoter = $pdo->prepare(
                'UPDATE orders
                 SET promoter_id = :promoterId,
                     promoter_code = :promoterCode,
                     promoter_assigned_at = NOW()
                 WHERE id = :orderId'
            );
            $updatePromoter->execute([
                'promoterId' => $promoterId,
                'promoterCode' => $promoterCode,
                'orderId' => $orderId,
            ]);
        } catch (Throwable) {
            // Mantém o pedido funcionando mesmo se a atribuição do promotor falhar.
        }
    }


    $insertItem = $pdo->prepare(
        'INSERT INTO order_items (order_id, batch_id, item_name, unit_price, quantity, total_price, metadata_json)
         VALUES (:orderId, :batchId, :itemName, :unitPrice, :quantity, :totalPrice, :metadataJson)'
    );

    $insertItem->execute([
        'orderId' => $orderId,
        'batchId' => $selected['batch_id'],
        'itemName' => $selected['batch_name'],
        'unitPrice' => (float) $selected['price'],
        'quantity' => $quantity,
        'totalPrice' => $subtotalValue,
        'metadataJson' => json_encode([
            'eventTitle' => $selected['title'],
            'subtotalValue' => $subtotalValue,
            'serviceFeePerTicket' => $settingsTax,
            'serviceFeeValue' => $serviceFeeValue,
            'asaasFeePerOrder' => $asaasFeeValue,
            'organizerNetValue' => $organizerNetValue,
            'platformNetFeeValue' => $platformNetFeeValue,
            'totalValue' => $totalValue,
            'ticketsPerUnit' => $ticketsPerUnit,
            'ticketQuantity' => $ticketQuantity,
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
    ]);

    $orderItemId = (int) $pdo->lastInsertId();

    try {
        if (!$pdo->query("SHOW COLUMNS FROM tickets LIKE 'holder_name'")->fetch()) {
            $pdo->exec('ALTER TABLE tickets ADD COLUMN holder_name VARCHAR(180) NULL AFTER ticket_code');
        }
        if (!$pdo->query("SHOW COLUMNS FROM tickets LIKE 'holder_email'")->fetch()) {
            $pdo->exec('ALTER TABLE tickets ADD COLUMN holder_email VARCHAR(180) NULL AFTER holder_name');
        }
        if (!$pdo->query("SHOW COLUMNS FROM tickets LIKE 'ticket_email_sent_at'")->fetch()) {
            $pdo->exec('ALTER TABLE tickets ADD COLUMN ticket_email_sent_at DATETIME NULL');
        }
        if (!$pdo->query("SHOW COLUMNS FROM tickets LIKE 'ticket_email_error'")->fetch()) {
            $pdo->exec('ALTER TABLE tickets ADD COLUMN ticket_email_error TEXT NULL');
        }
    } catch (Throwable) {
        // Se não puder alterar a tabela, continua com os campos antigos.
    }

    $hasHolderColumns = (bool) $pdo->query("SHOW COLUMNS FROM tickets LIKE 'holder_email'")->fetch();
    if ($hasHolderColumns) {
        $insertTicket = $pdo->prepare(
            'INSERT INTO tickets (order_id, order_item_id, event_id, batch_id, ticket_code, holder_name, holder_email, status)
             VALUES (:orderId, :orderItemId, :eventId, :batchId, :ticketCode, :holderName, :holderEmail, :status)'
        );
    } else {
        $insertTicket = $pdo->prepare(
            'INSERT INTO tickets (order_id, order_item_id, event_id, batch_id, ticket_code, status)
             VALUES (:orderId, :orderItemId, :eventId, :batchId, :ticketCode, :status)'
        );
    }

    for ($index = 0; $index < $ticketQuantity; $index++) {
        $holder = $normalizeTicketHolder($index);
        $params = [
            'orderId' => $orderId,
            'orderItemId' => $orderItemId,
            'eventId' => $selected['id'],
            'batchId' => $selected['batch_id'],
            'ticketCode' => generateTicketCode(),
            'status' => 'unused',
        ];
        if ($hasHolderColumns) {
            $params['holderName'] = $holder['name'];
            $params['holderEmail'] = $holder['email'];
        }
        $insertTicket->execute($params);
    }

    $pdo->commit();
} catch (Throwable $throwable) {
    $pdo->rollBack();
    throw $throwable;
}

if (($payment['id'] ?? null) && $initialPaymentStatus === 'paid') {
    try {
        (new \GalpaoImperial\Api\SiteRepository($pdo))->markOrderPaid((string) $payment['id']);
    } catch (Throwable) {
        // Não travar criação do pedido por falha no e-mail/status pós-pagamento.
    }
}

jsonResponse([
    'success' => true,
    'message' => $asaas->isEnabled()
        ? 'Pedido criado e cobrança Pix gerada com sucesso.'
        : 'Pedido criado em modo local. Configure o Asaas para gerar cobrança real.',
    'data' => [
        'orderNumber' => $orderNumber,
        'totalValue' => $totalValue,
        'eventTitle' => $selected['title'],
        'pix' => [
            'encodedImage' => $pixQrCode['encodedImage'] ?? null,
            'payload' => $pixQrCode['payload'] ?? null,
            'expirationDate' => $pixQrCode['expirationDate'] ?? null,
        ],
        'payment' => [
            'id' => $payment['id'] ?? null,
            'status' => mapAsaasPaymentStatus($payment['status'] ?? null),
            'invoiceUrl' => $payment['invoiceUrl'] ?? null,
            'method' => $paymentMethod,
        ],
    ],
], 201);
