<?php

declare(strict_types=1);

namespace ImovelZapAi\Billing\Infrastructure\MercadoPago;

use ImovelZapAi\Billing\Application\Contracts\MercadoPagoClient;
use ImovelZapAi\Billing\Domain\Enums\BillingCycle;
use ImovelZapAi\Billing\Domain\Exceptions\BillingException;
use Illuminate\Support\Facades\Http;

final class HttpMercadoPagoClient implements MercadoPagoClient
{
    public function createPreapprovalPlan(
        string $reason,
        int $amountCents,
        BillingCycle $cycle,
        int $trialDays = 0,
    ): array {
        $body = [
            'reason' => $reason,
            'auto_recurring' => [
                'frequency' => 1,
                'frequency_type' => $cycle === BillingCycle::Yearly ? 'months' : 'months',
                'transaction_amount' => round($amountCents / 100, 2),
                'currency_id' => (string) config('billing.currency', 'BRL'),
            ],
            'back_url' => (string) config('billing.checkout_back_url'),
        ];

        if ($cycle === BillingCycle::Yearly) {
            $body['auto_recurring']['frequency'] = 12;
        }

        if ($trialDays > 0) {
            $body['auto_recurring']['free_trial'] = [
                'frequency' => max(1, (int) ceil($trialDays / 30)),
                'frequency_type' => 'months',
            ];
        }

        $response = $this->request()->post('/preapproval_plan', $body);
        if (! $response->successful()) {
            throw BillingException::checkoutFailed($response->body());
        }

        /** @var array{id?: string} $json */
        $json = $response->json() ?? [];

        return [
            'id' => (string) ($json['id'] ?? ''),
            'init_point' => null,
            'status' => 'active',
        ];
    }

    public function createPreapproval(
        string $preapprovalPlanId,
        string $payerEmail,
        string $externalReference,
        string $backUrl,
        ?int $transactionAmountCents = null,
    ): array {
        $body = [
            'preapproval_plan_id' => $preapprovalPlanId,
            'payer_email' => $payerEmail,
            'external_reference' => $externalReference,
            'back_url' => $backUrl,
            'status' => 'pending',
        ];

        if ($transactionAmountCents !== null) {
            $body['auto_recurring'] = [
                'transaction_amount' => round($transactionAmountCents / 100, 2),
                'currency_id' => (string) config('billing.currency', 'BRL'),
            ];
        }

        $response = $this->request()->post('/preapproval', $body);
        if (! $response->successful()) {
            throw BillingException::checkoutFailed($response->body());
        }

        /** @var array{id?: string, init_point?: string, status?: string} $json */
        $json = $response->json() ?? [];

        return [
            'id' => (string) ($json['id'] ?? ''),
            'init_point' => isset($json['init_point']) ? (string) $json['init_point'] : null,
            'status' => isset($json['status']) ? (string) $json['status'] : null,
            'external_reference' => $externalReference,
        ];
    }

    public function updatePreapproval(string $preapprovalId, array $payload): array
    {
        $response = $this->request()->put('/preapproval/'.$preapprovalId, $payload);
        if (! $response->successful()) {
            throw BillingException::checkoutFailed($response->body());
        }

        /** @var array{id?: string, status?: string} $json */
        $json = $response->json() ?? [];

        return [
            'id' => (string) ($json['id'] ?? $preapprovalId),
            'status' => isset($json['status']) ? (string) $json['status'] : null,
        ];
    }

    public function getPreapproval(string $preapprovalId): array
    {
        $response = $this->request()->get('/preapproval/'.$preapprovalId);
        if (! $response->successful()) {
            throw BillingException::checkoutFailed($response->body());
        }

        /** @var array{id?: string, status?: string, external_reference?: string} $json */
        $json = $response->json() ?? [];

        return [
            'id' => (string) ($json['id'] ?? $preapprovalId),
            'status' => isset($json['status']) ? (string) $json['status'] : null,
            'external_reference' => isset($json['external_reference']) ? (string) $json['external_reference'] : null,
        ];
    }

    public function cancelPreapproval(string $preapprovalId): void
    {
        $this->updatePreapproval($preapprovalId, ['status' => 'cancelled']);
    }

    private function request(): \Illuminate\Http\Client\PendingRequest
    {
        $token = (string) config('billing.mercadopago.access_token');
        if ($token === '') {
            throw BillingException::checkoutFailed('MERCADOPAGO_ACCESS_TOKEN ausente.');
        }

        return Http::baseUrl(rtrim((string) config('billing.mercadopago.base_url'), '/'))
            ->withToken($token)
            ->acceptJson()
            ->timeout((int) config('billing.mercadopago.timeout_seconds', 30));
    }
}
