<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class ClientRequest extends FormRequest
{
    public function rules(): array
    {
        $clientId = $this->route('id');

        $rules = [
            'avatar' => 'sometimes|file|image|mimes:jpg,jpeg,png,webp|max:5120',

            'selfie_verified' => [
                'sometimes',
                'boolean',
                Rule::prohibitedIf(fn () => ! $this->user()?->canModerateClients()),
            ],

            'document' => [
                'sometimes',
                'string',
                'regex:/^[0-9]{11}$|^[0-9]{14}$/',
                function ($attribute, $value, $fail) {
                    if (! $this->isValidCpfCnpj($value)) {
                        $fail(__('validation.custom.document.invalid'));
                    }
                },
            ],

            'user_id' => [
                'sometimes',
                'exists:users,id',
                function ($attribute, $value, $fail) use ($clientId) {
                    $clientExists = \DB::table('clients')
                        ->where('user_id', $value)
                        ->whereNull('deleted_at')
                        ->when($clientId, function ($query) use ($clientId) {
                            $query->where('id', '!=', $clientId);
                        })
                        ->exists();

                    if ($clientExists) {
                        $fail(__('validation.custom.user_id.already_linked_to_client'));
                    }

                    $providerExists = \DB::table('providers')
                        ->where('user_id', $value)
                        ->whereNull('deleted_at')
                        ->exists();

                    if ($providerExists) {
                        $fail(__('validation.custom.user_id.already_linked_to_provider'));
                    }
                },
            ],
        ];

        if ($this->isMethod('post')) {
            $rules['document'] = [
                'required',
                'string',
                'regex:/^[0-9]{11}$|^[0-9]{14}$/',
                function ($attribute, $value, $fail) {
                    if (! $this->isValidCpfCnpj($value)) {
                        $fail(__('validation.custom.document.invalid'));
                    }
                },
            ];

            $rules['user_id'] = [
                'required',
                'exists:users,id',
                function ($attribute, $value, $fail) {
                    $clientExists = \DB::table('clients')
                        ->where('user_id', $value)
                        ->whereNull('deleted_at')
                        ->exists();

                    if ($clientExists) {
                        $fail(__('validation.custom.user_id.already_linked_to_client'));
                    }

                    $providerExists = \DB::table('providers')
                        ->where('user_id', $value)
                        ->whereNull('deleted_at')
                        ->exists();

                    if ($providerExists) {
                        $fail(__('validation.custom.user_id.already_linked_to_provider'));
                    }
                },
            ];
        }

        return $rules;
    }

    private function isValidCpfCnpj(string $value): bool
    {
        $value = preg_replace('/[^0-9]/', '', $value);

        if (strlen($value) === 11) {
            return $this->isValidCpf($value);
        } elseif (strlen($value) === 14) {
            return $this->isValidCnpj($value);
        }

        return false;
    }

    private function isValidCpf(string $cpf): bool
    {
        if (preg_match('/(\d)\1{10}/', $cpf)) {
            return false;
        }

        for ($t = 9; $t < 11; $t++) {
            for ($d = 0, $c = 0; $c < $t; $c++) {
                $d += $cpf[$c] * (($t + 1) - $c);
            }

            $d = ((10 * $d) % 11) % 10;

            if ($cpf[$c] != $d) {
                return false;
            }
        }

        return true;
    }

    private function isValidCnpj(string $cnpj): bool
    {
        if (preg_match('/(\d)\1{13}/', $cnpj)) {
            return false;
        }

        $length  = strlen($cnpj) - 2;
        $numbers = substr($cnpj, 0, $length);
        $digits  = substr($cnpj, $length);
        $sum     = 0;
        $pos     = $length - 7;

        for ($i = $length; $i >= 1; $i--) {
            $sum += $numbers[$length - $i] * $pos--;

            if ($pos < 2) {
                $pos = 9;
            }
        }

        $result = $sum % 11 < 2 ? 0 : 11 - $sum % 11;

        if ($result != $digits[0]) {
            return false;
        }

        $length  = $length + 1;
        $numbers = substr($cnpj, 0, $length);
        $sum     = 0;
        $pos     = $length - 7;

        for ($i = $length; $i >= 1; $i--) {
            $sum += $numbers[$length - $i] * $pos--;

            if ($pos < 2) {
                $pos = 9;
            }
        }

        $result = $sum % 11 < 2 ? 0 : 11 - $sum % 11;

        if ($result != $digits[1]) {
            return false;
        }

        return true;
    }
}
