<?php

namespace IpagWoocommerce;

class TransactionRequestTransformer implements TransformerInterface
{
    public function transform(array $request): array
    {
        $payload = $request['body'];

        $customer_handler = function () use ($payload) {
            $billing_address = [
                'street' => ArrUtils::get($payload, 'endereco'),
                'number' => ArrUtils::get($payload, 'numero_endereco'),
                'district' => ArrUtils::get($payload, 'bairro'),
                'complement' => ArrUtils::get($payload, 'complemento'),
                'city' => ArrUtils::get($payload, 'cidade'),
                'state' => ArrUtils::get($payload, 'estado'),
                'zipcode' => preg_replace('/\D/', '', ArrUtils::get($payload, 'cep')),
            ];

            $shipping_address = [
                'street' => ArrUtils::get($payload, 'endereco_entrega') ?: ArrUtils::get($billing_address, 'street'),
                'number' => ArrUtils::get($payload, 'numero_endereco_entrega') ?: ArrUtils::get($billing_address, 'number'),
                'district' => ArrUtils::get($payload, 'bairro_entrega') ?: ArrUtils::get($billing_address, 'district'),
                'city' => ArrUtils::get($payload, 'cidade_entrega') ?: ArrUtils::get($billing_address, 'city'),
                'state' => ArrUtils::get($payload, 'estado_entrega') ?: ArrUtils::get($billing_address, 'state'),
                'zipcode' => preg_replace('/\D/', '', ArrUtils::get($payload, 'cep_entrega')) ?: ArrUtils::get($billing_address, 'zipcode'),

                'complement' => gettype(ArrUtils::get($payload, 'complemento_entrega')) === 'string' ?
                    ArrUtils::get($payload, 'complemento_entrega') :
                    ArrUtils::get($billing_address, 'complement'),
            ];

            $customer = [
                'name' => ArrUtils::get($payload, 'nome'),
                'email' => ArrUtils::get($payload, 'email'),
                'phone' => preg_replace('/^55/', '', preg_replace('/\D/', '', ArrUtils::get($payload, 'fone'))),
                'billing_address' => $billing_address,
                'shipping_address' => $shipping_address,
            ];

            $customer_ip = ArrUtils::get($payload, 'ip');

            if ($customer_ip) {
                $customer['ip'] = $customer_ip;
            }

            $documento = preg_replace('/\D/', '', ArrUtils::get($payload, 'documento'));

            $cpf_cartao = preg_replace('/\D/', '', ArrUtils::get($payload, 'cpf_cartao'));

            $customer_document = $cpf_cartao ?: $documento ?: null;

            if ($customer_document) {
                $customer['cpf_cnpj'] = $customer_document;
            }

            return $customer;
        };

        $products_handler = function () use ($payload) {
            $raw = ArrUtils::get($payload, 'descricao_pedido', '[]');
            $items = is_array($raw) ? $raw : [];
            $products = [];

            if (is_string($raw)) {
                $items = json_decode($raw, true);

                if ($items === null) {
                    $items = json_decode(stripslashes($raw), true) ?: [];
                }
            }

            if (!empty($items) && array_keys($items) !== range(0, count($items) - 1)) {
                $items = array_values($items);
            }

            foreach ($items as $item) {
                $name = ArrUtils::get($item, 'descr', ArrUtils::get($item, 'name', ''));
                $quantity = intval(ArrUtils::get($item, 'quant', ArrUtils::get($item, 'quantity', 1)));
                $unit_price = round(floatval(ArrUtils::get($item, 'valor', ArrUtils::get($item, 'unit_price', 0))), 2);

                $products[] = [
                    'name' => $name,
                    'quantity' => $quantity,
                    'unit_price' => $unit_price,
                ];
            }

            return $products;
        };

        $payment_handler = function () use ($payload) {
            $method = mb_strtolower(ArrUtils::get($payload, 'metodo', ''));

            $type = $method == 'pix' ? 'pix' : (
                mb_stripos($method, 'boleto') !== false ? 'boleto' : 'card'
            );

            $installments = intval(ArrUtils::get($payload, 'parcelas', 1));

            $payment = [
                'type' => $type,
                'method' => $method,
                'installments' => $installments,
            ];

            if ($type === 'boleto') {
                $payment['boleto'] = [];

                $vencto = ArrUtils::get($payload, 'vencto');

                if ($vencto) {
                    $payment['boleto']['due_date'] = $vencto;
                    $payment['boleto']['instructions'] = ["Não receber após o vencimento ($vencto)."];
                }
            }

            if ($type === 'card') {
                $token = ArrUtils::get($payload, 'token_cartao');

                $cardData = [
                    'holder' => ArrUtils::get($payload, 'nome_cartao'),
                    'number' => ArrUtils::get($payload, 'num_cartao'),
                    'cvv' => ArrUtils::get($payload, 'cvv_cartao'),
                    'expiry_month' => ArrUtils::get($payload, 'mes_cartao'),
                    'expiry_year' => str_pad(ArrUtils::get($payload, 'ano_cartao'), 4, '20', STR_PAD_LEFT),
                    'tokenize' => ArrUtils::get($payload, 'gera_token_cartao') ? true : false,
                ];

                if ($token) {
                    $cardData = ['token' => $token];
                }

                $payment['card'] = $cardData;
            }

            return $payment;
        };

        $payment_subscription = function () use ($payload) {
            $raw_start = ArrUtils::get($payload, 'inicio');

            $start_date = $raw_start;

            if (!empty($raw_start)) {
                if (strpos($raw_start, '/') !== false) {
                    $dt = \DateTime::createFromFormat('d/m/Y', $raw_start);
                    if ($dt !== false) {
                        $start_date = $dt->format('Y-m-d');
                    }
                } else {
                    $dt = \DateTime::createFromFormat('Y-m-d', $raw_start);
                    if ($dt !== false) {
                        $start_date = $dt->format('Y-m-d');
                    }
                }
            }

            $trial_cycles = intval(ArrUtils::get($payload, 'trial_ciclos'));

            $amount = floatval(ArrUtils::get($payload, 'valor_rec', 0));

            if ($amount <= 0) {
                return null;
            }

            $subscription = [];
            $subscription['amount'] = $amount;

            if (!empty($start_date)) {
                $subscription['start_date'] = $start_date;
            }

            if ($trial_cycles > 0) {
                $subscription['trial'] = [
                    'cycles' => $trial_cycles,
                    'frequency' => intval(ArrUtils::get($payload, 'trial_frequencia', ArrUtils::get($payload, 'frequencia'))),
                ];
            }

            $cycles = intval(ArrUtils::get($payload, 'ciclos', 0));
            if ($cycles > 0) {
                $subscription['cycles'] = $cycles;
            }

            $subscription['frequency'] = intval(ArrUtils::get($payload, 'frequencia', 1));
            $subscription['interval'] = mb_strtolower(ArrUtils::get($payload, 'intervalo', 'month'));

            $installments = intval(ArrUtils::get($payload, 'parcelas_rec', ArrUtils::get($payload, 'parcelas', 1)));
            if ($installments > 0) {
                $subscription['installments'] = $installments;
            }

            $defer = ArrUtils::get($payload, 'trial') == '1' ? true : (ArrUtils::get($payload, 'defer_start', false) ? true : false);
            if ($defer) {
                $subscription['defer_start'] = true;
            }

            return $subscription;
        };

        $ip_address = ArrUtils::get($payload, 'ip');
        $visitor_id = ArrUtils::get($payload, 'visitor_id');
        $callback_url = ArrUtils::get($payload, 'url_retorno');
        $url_redirect = ArrUtils::get($payload, 'url_redirect');
        $amount = floatval(ArrUtils::get($payload, 'valor'));
        $order_id = strval(ArrUtils::get($payload, 'pedido'));
        $device_fingerprint = ArrUtils::get($payload, 'device_fingerprint');

        $eci = ArrUtils::get($payload, 'eci');
        $xid = ArrUtils::get($payload, 'xid');
        $cavv = ArrUtils::get($payload, 'cavv');
        $version = ArrUtils::get($payload, 'version');
        $returnCode = ArrUtils::get($payload, 'returnCode');
        $referenceId = ArrUtils::get($payload, 'referenceId');
        $returnMessage = ArrUtils::get($payload, 'returnMessage');

        $subscription_data = $payment_subscription();

        $parsed =
            array_merge(
                compact(
                    'amount',
                    'order_id',
                    'ip_address',
                    'visitor_id',
                    'callback_url',
                    'device_fingerprint',
                    'eci',
                    'xid',
                    'cavv',
                    'version',
                    'returnCode',
                    'referenceId',
                    'returnMessage'
                ),
                ['payment' => $payment_handler(), 'customer' => $customer_handler(), 'products' => $products_handler()]
            );

        if ($url_redirect) {
            $parsed['redirect_url'] = $url_redirect;
        }

        if ($subscription_data) {
            $parsed['subscription'] = $subscription_data;
        }

        $request['body'] = json_encode($parsed);

        return $request;
    }
}