<?php

namespace App\Services\Pagarme;

use App\Data\Pagarme\Request\BankAccountUpdateRequestData;
use App\Data\Pagarme\Request\RecipientRequestData\RecipientAutomaticAnticipationSettingsData;
use App\Data\Pagarme\Request\RecipientRequestData\RecipientBankAccountData;
use App\Data\Pagarme\Request\RecipientRequestData\RecipientRegisterInformationData\RecipientAddressData;
use App\Data\Pagarme\Request\RecipientRequestData\RecipientRegisterInformationData\RecipientPhoneNumbersData\RecipientPhoneData;
use App\Data\Pagarme\Request\RecipientRequestData\RecipientRegisterInformationData\RecipientPhoneNumbersData\RecipientPhoneNumbersData;
use App\Data\Pagarme\Request\RecipientRequestData\RecipientRegisterInformationData\RecipientRegisterInformationData;
use App\Data\Pagarme\Request\RecipientRequestData\RecipientRequestData;
use App\Data\Pagarme\Request\RecipientRequestData\RecipientTransferSettingsData;
use App\Data\Pagarme\Response\RecipientResponseData\RecipientResponseData;
use App\Models\Provider;
use App\Services\Pagarme\Concerns\FormatsPagarmeData;
use App\Services\Pagarme\Concerns\SendsPagarmeRequests;

class PagarmeRecipientService
{
    use FormatsPagarmeData;
    use SendsPagarmeRequests;

    public function createRecipientForProvider(Provider $provider, array $data): string
    {
        if (! empty($provider->recipient_id)) {
            return $provider->recipient_id;
        }

        $metadata = $data['recipient_metadata'] ?? [];
        $paymentMode = $data['recipient_payment_mode'];
        $recipientCode = $provider->ensureGatewayCode();

        $addressParts = $this->extractAddressParts($data);

        $registerInformation = new RecipientRegisterInformationData(
            name: $data['recipient_name'],
            email: $data['recipient_email'],
            document: $this->digits($data['recipient_document'] ?? null),
            type: $data['recipient_type'] ?? 'individual',
            birthdate: $this->formatBirthdate($data['birth_date'] ?? null),
            monthlyIncome: isset($data['monthly_income']) ? (int) $data['monthly_income'] : 1000,
            professionalOccupation: $data['professional_occupation'] ?? 'autonomo',

            phoneNumbers: new RecipientPhoneNumbersData(
                $this->buildRecipientPhone($data['phone'] ?? null),
            ),

            address: new RecipientAddressData(
                street: $addressParts['street'],
                complementary: $addressParts['complementary'],
                streetNumber: $addressParts['street_number'],
                neighborhood: $addressParts['neighborhood'],
                city: $data['city'] ?? null,
                state: $data['state'] ?? null,
                zipCode: $this->digits($data['zip_code'] ?? null),
                referencePoint: $addressParts['reference_point'],
            ),
        );

        $defaultBankAccount = $this->buildRecipientBankAccount(
            $data['recipient_default_bank_account'],
        );

        $payload = new RecipientRequestData(
            code: $recipientCode,

            registerInformation: $registerInformation,
            defaultBankAccount: $defaultBankAccount,

            transferSettings: new RecipientTransferSettingsData(
                transferEnabled: false,
                transferInterval: 'Daily',
                transferDay: 0,
            ),

            automaticAnticipationSettings: new RecipientAutomaticAnticipationSettingsData(
                enabled: false,
            ),
        );

        $bankAccountData = $payload->defaultBankAccount->toArray();

        $raw = $this->pagarmeRequest(
            method: 'POST',
            path: '/recipients',
            payload: $payload,
            idempotencyKey: $this->idempotencyKey($provider->id),
            errorMessage: 'Erro ao criar recebedor no Pagar.me.',
        );

        $recipientData = RecipientResponseData::fromArray($raw);

        $recipientId = $recipientData->requireId();

        $provider->forceFill([
            'recipient_id'                   => $recipientId,
            'recipient_name'                 => $data['recipient_name'],
            'recipient_email'                => $data['recipient_email'],
            'recipient_description'          => $data['recipient_description'],
            'recipient_document'             => $data['recipient_document'],
            'recipient_type'                 => $payload->registerInformation->type,
            'recipient_code'                 => $recipientCode,
            'recipient_payment_mode'         => $paymentMode,
            'recipient_default_bank_account' => $bankAccountData,

            'recipient_transfer_settings' => [
                'transfer_enabled'  => false,
                'transfer_interval' => 'daily',
                'transfer_day'      => 0,
            ],

            'recipient_automatic_anticipation_settings' => [
                'enabled' => false,
            ],

            'recipient_metadata' => $metadata,
        ])->save();

        return $recipientId;
    }

    public function updateDefaultBankAccount(Provider $provider, array $bankAccountData): Provider
    {
        $payload = new BankAccountUpdateRequestData(
            holderName: $this->normalizeHolderName($bankAccountData['holder_name']),
            holderType: $bankAccountData['holder_type'],
            holderDocument: $this->digits($bankAccountData['holder_document']),
            bank: $bankAccountData['bank'],
            branchNumber: $bankAccountData['branch_number'],
            branchCheckDigit: $bankAccountData['branch_check_digit'] ?? null,
            accountNumber: $bankAccountData['account_number'],
            accountCheckDigit: $bankAccountData['account_check_digit'],
            type: $bankAccountData['type'],
        );

        $raw = $this->pagarmeRequest(
            method: 'PATCH',
            path: "/recipients/{$provider->recipient_id}/default-bank-account",
            payload: $payload,
            idempotencyKey: $this->idempotencyKey($provider->id, 'default-bank-account-'.sha1(json_encode($payload->toArray()))),
            errorMessage: 'Erro ao atualizar conta bancaria do recebedor no Pagar.me.',
        );

        $recipientData = RecipientResponseData::fromArray($raw);

        $provider->forceFill([
            'recipient_default_bank_account' => $recipientData->defaultBankAccount?->toArray() ?: $payload->toArray()['bank_account'],
        ])->save();

        return $provider->fresh();
    }

    //

    private function buildRecipientBankAccount(array $data): RecipientBankAccountData
    {
        return new RecipientBankAccountData(
            holderName: $this->normalizeHolderName($data['holder_name']),
            holderType: $data['holder_type'],
            holderDocument: $this->digits($data['holder_document']),
            bank: $data['bank'],
            branchNumber: $data['branch_number'],
            branchCheckDigit: $data['branch_check_digit'] ?? null,
            accountNumber: $data['account_number'],
            accountCheckDigit: $data['account_check_digit'],
            type: $data['type'],
        );
    }

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

        if (strlen($digits) < 10) {
            return new RecipientPhoneData(
                ddd: '11',
                number: '999999999',
                type: 'mobile',
            );
        }

        if (str_starts_with($digits, '55')) {
            $digits = substr($digits, 2);
        }

        return new RecipientPhoneData(
            ddd: substr($digits, 0, 2),
            number: substr($digits, 2),
            type: 'mobile',
        );
    }

    // evita criacao duplica de recipient

    private function idempotencyKey(int $providerId, string $suffix = 'recipient'): string
    {
        return "provider-{$providerId}-{$suffix}";
    }
}
