<?php

namespace App\Services\Pagarme;

use App\Data\Pagarme\Card\CardRequestData;
use App\Data\Pagarme\Card\CardResponseData;
use App\Data\Pagarme\Card\Parts\Request\BillingAddressData;
use App\Models\Address;
use App\Models\ClientPaymentMethod;
use App\Services\Pagarme\Concerns\FormatsPagarmeData;
use App\Services\Pagarme\Concerns\MocksPagarmeRequests;
use App\Services\Pagarme\Concerns\SendsPagarmeRequests;

class PagarmeCardService
{
    use FormatsPagarmeData;
    use MocksPagarmeRequests;
    use SendsPagarmeRequests;

    public function __construct(
        private readonly PagarmeCustomerService $pagarmeCustomerService,
    ) {}

    public function createCardForPaymentMethod(ClientPaymentMethod $paymentMethod): ?string
    {
        if (! empty($paymentMethod->gateway_card_id)) {
            return $paymentMethod->gateway_card_id;
        }

        $paymentMethod->loadMissing('client.user');

        $customerId = $this->pagarmeCustomerService->createCustomerForClient(
            $paymentMethod->client,
            []
        );

        if ($this->shouldMockPagarmeRequest()) {
            $cardId = $this->mockPagarmeId('card', $paymentMethod->id);

            $paymentMethod->forceFill([
                'gateway_card_id'  => $cardId,
                'brand'            => $paymentMethod->brand            ?: 'visa',
                'last_four_digits' => $paymentMethod->last_four_digits ?: '1111',
            ])->save();

            return $cardId;
        }

        $cardData = CardResponseData::fromArray($this->pagarmeRequest(
            method: 'POST',
            path:   "/customers/{$customerId}/cards",

            payload: new CardRequestData(
                token: $paymentMethod->token,
                label: $paymentMethod->card_name,

                billingAddress: BillingAddressData::fromAddress(
                    Address::query()
                        ->with(['city.state', 'state'])
                        ->where('source', 'client')
                        ->where('source_id', $paymentMethod->client_id)
                        ->orderByDesc('is_primary')
                        ->latest('id')
                        ->first()
                ),
            ),

            idempotencyKey: $this->idempotencyKey($paymentMethod),
            errorMessage:   'Erro ao salvar cartao no Pagar.me.',
        ));

        $cardId = $cardData->requireId();

        $paymentMethod->forceFill([
            'gateway_card_id'  => $cardId,
            'brand'            => $paymentMethod->brand ?: $cardData->brand,
            'last_four_digits' => $paymentMethod->last_four_digits ?: $cardData->lastFourDigits,
        ])->save();

        return $cardId;
    }

    // evita criacao duplicada de cartao

    // formato: card-{email}-{ultimos-4-digitos}-{bandeira}

    private function idempotencyKey(ClientPaymentMethod $paymentMethod): string
    {
        if (! empty($paymentMethod->idempotency_key)) {
            return $paymentMethod->idempotency_key;
        }

        $paymentMethod->loadMissing('client.user');

        $email = $paymentMethod->client?->user?->email
            ?: "client-{$paymentMethod->client_id}";

        $lastFourDigits = $paymentMethod->last_four_digits
            ?: substr($this->digits($paymentMethod->card_number), -4)
            ?: "card-{$paymentMethod->id}";

        $key = $this->pagarmeIdempotencyKey('card', [
            $email,
            $lastFourDigits,
            $paymentMethod->brand ?: 'unknown-brand',
        ]);

        $paymentMethod->forceFill(['idempotency_key' => $key])->save();

        return $key;
    }
}
