<?php

namespace App\Services\Pagarme;

use App\Data\Pagarme\Customer\CustomerRequestData;
use App\Data\Pagarme\Customer\CustomerResponseData;
use App\Data\Pagarme\Customer\Parts\Request\AddressData;
use App\Data\Pagarme\Customer\Parts\Request\PhoneData;
use App\Data\Pagarme\Customer\Parts\Request\PhonesData;
use App\Models\Client;
use App\Services\Pagarme\Concerns\FormatsPagarmeData;
use App\Services\Pagarme\Concerns\MocksPagarmeRequests;
use App\Services\Pagarme\Concerns\SendsPagarmeRequests;

class PagarmeCustomerService
{
    use FormatsPagarmeData;
    use MocksPagarmeRequests;
    use SendsPagarmeRequests;

    public function createCustomerForClient(Client $client, array $data): ?string
    {
        if (! empty($client->gateway_customer_id)) {
            return $client->gateway_customer_id;
        }

        $client->loadMissing('user');

        $name  = $client->user?->name  ?? data_get($data, 'name', 'Cliente');
        $email = $client->user?->email ?? data_get($data, 'email');
        $code  = $client->ensureGatewayCode();

        $document     = $this->customerDocument($client->document ?? data_get($data, 'document'));
        $documentType = $this->customerDocumentType($document);

        $address = $this->buildAddressData($data);
        $phones  = $this->buildPhones($client->user?->phone ?? data_get($data, 'phone'));

        if ($this->shouldMockPagarmeRequest()) {
            $customerId = $this->mockPagarmeId('cus', $client->id);

            $client->forceFill([
                'gateway_customer_id'   => $customerId,
                'gateway_customer_code' => $code,
            ])->save();

            return $customerId;
        }

        $customerRequest = new CustomerRequestData(
            name:         $name,
            email:        (string) $email,
            document:     $document,
            type:         $documentType === 'CNPJ' ? 'company' : 'individual',
            documentType: $documentType,
            code:         $code,
            address:      $address,
            phones:       $phones,
        );

        $customerData = CustomerResponseData::fromArray($this->pagarmeRequest(
            method:         'POST',
            path:           '/customers',
            payload:        $customerRequest,
            idempotencyKey: $this->idempotencyKey($client),
            errorMessage:   'Erro ao criar cliente no Pagar.me.',
        ));

        $customerId = $customerData->requireId();

        $client->forceFill([
            'gateway_customer_id'   => $customerId,
            'gateway_customer_code' => $code,
        ])->save();

        return $customerId;
    }

    //

    private function buildAddressData(array $data): AddressData
    {
        $line1Parts = array_filter([
            (string) data_get($data, 'number', '0'),
            (string) data_get($data, 'address', ''),
            (string) data_get($data, 'district', ''),
        ], static fn ($value) => $value !== '');

        return new AddressData(
            line1:   implode(', ', $line1Parts),
            line2:   (string) data_get($data, 'complement', data_get($data, 'instructions', '')),
            zipCode: $this->digits(data_get($data, 'zip_code')),
            city:    (string) data_get($data, 'city', ''),
            state:   (string) data_get($data, 'state', ''),
            country: (string) data_get($data, 'country', 'BR'),
        );
    }

    private function buildPhones(?string $phone): PhonesData
    {
        $digits = $this->digits($phone);

        if ($digits === '') {
            return new PhonesData;
        }

        $areaCode = substr($digits, 0, 2);
        $number   = substr($digits, 2);

        if (strlen($digits) <= 2) {
            $areaCode = '';
            $number   = $digits;
        }

        return new PhonesData(
            mobilePhone: new PhoneData(
                countryCode: '55',
                areaCode:    $areaCode,
                number:      $number,
            ),
        );
    }

    // evita criacao duplicada de customer

    // formato: customer-{email}-{documento}

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

        $client->loadMissing('user');

        $key = $this->pagarmeIdempotencyKey('customer', [
            $client->user?->email ?: "client-{$client->id}",
            $this->customerDocument($client->document) ?: "document-client-{$client->id}",
        ]);

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

        return $key;
    }
}
