<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use App\Http\Controllers\Controller;
use App\DTOs\Customer\CustomerCreateDto;
use App\DTOs\Customer\CustomerUpdateDto;
use App\Repositories\Interfaces\ICustomerRepository;
use Exception;
use App\Models\Customer;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver;

class CustomerController extends Controller
{

    private $customerRepository;
    private $errorConnection = "";

    public function __construct(Request $request, ICustomerRepository $customerRepository)
    {
        if (isset($request['business_information'])) {
            $business_information = $request['business_information'];
            $ruc = $business_information['ruc_number'];

            $existe_conexion = $this->setDBClient($ruc);

            if ($existe_conexion['error']) {
                $this->errorConnection = $existe_conexion['message'];
                return $this->messageError("Se espera un número de RUC válido.", 201);
            } else {
                $this->customerRepository = $customerRepository;
            }
        } else {
            $this->errorConnection = 'Error en la conexión. Se espera número de RUC';
        }
    }

    public function index(Request $request)
    {
        if ($this->errorConnection != '') {
            return $this->messageError($this->errorConnection, 201);
        }

        $result = $this->customerRepository->paginate($request->all());

        if ($result) {
            return $this->successResponse($result, "Clientes encontrados correctamente", 201);
        } else {
            return $this->errorResponse("No hay Clientes", 201);
        }
    }

    public function show(int $id, Request $request)
    {
        $business_information = $request['business_information'];
        $business_ruc = $business_information['ruc_number'];
        if ($this->errorConnection != '') {
            return $this->messageError($this->errorConnection, 500);
        }

        $result = $this->customerRepository->find($id, $business_ruc);

        if ($result) {
            return $this->successResponse($result, "Cliente encontrado correctamente", 200);
        } else {
            return $this->errorResponse("Cliente no encontrado", 200);
        }
    }

    public function store(Request $request)
    {
        try {
            if ($this->errorConnection != '') {
                return $this->messageError($this->errorConnection, 500);
            }

            $business_information = $request['business_information'];
            $business_ruc = $business_information['ruc_number'];

            $document_number = $request['document_number'];
            $ruc = $request['ruc'];

            // VALIDACION PARA NUMERO DE DOCUMENTO EXISTENTE
            if ($document_number != null) {

                $docnumExists = Customer::where('cf1', $document_number)
                    ->where('status', 1)
                    ->where('ruc', $business_ruc)
                    ->get();

                if (count($docnumExists) >= 1) {
                    return $this->errorResponse("El numero de documento que ingreso ya esta registrado ", 422);
                }
            }

            // VALIDACION PARA RUC EXISTENTE
            if ($ruc != null) {

                $rucExists = Customer::where('cf2', $ruc)
                    ->where('status', 1)
                    ->where('ruc', $business_ruc)
                    ->get();

                if (count($rucExists) >= 1) {
                    return $this->errorResponse("El numero de RUC que ingreso ya esta registrado", 422);
                }
            }


            $this->validate(
                $request,
                [
                    'name' => 'required|max:255',
                    'ruc' => [ //VALIDACION EN CASO DE QUE RUC SEA OBLIGATORIO O NO
                        function ($attribute, $value, $fail) use ($request) {
                            if ($request->input('person_type') == 2 && empty($value)) {
                                $fail('Debe ingresar un RUC.');
                            }
                        },
                        'required_if:person_type,2', // RUC es obligatorio si person_type es 2
                        'digits:11',
                        'nullable',
                        'numeric',

                    ],
                    'document_number' => [  //VALIDACION EN CASO DE QUE EL NUMERO DE DOCUMENTO SEA OBLIGATORIO O NO
                        function ($attribute, $value, $fail) use ($request) {
                            if ($request->input('person_type') == 2 && !empty($value)) {
                                $fail('No debe ingresar un número de documento si es una persona juridica.');
                            }
                        },
                        'nullable', // Número de documento es opcional
                        'required_if:person_type,1',
                        'min:5',
                        'max:15',
                    ],

                    'phone' => 'numeric|digits_between:1,15',
                    'email' => 'email',
                    'direccion' => ['required_if:person_type,2', 'max:255'],
                    'customers_type_id' => 'nullable|numeric|digits_between:1,11',
                    'created_by' => 'required|numeric|digits_between:1,11',
                    'person_type' => 'required|in:1,2',
                    'document_type_id' => [ // VALIDACION PARA EL TIPO DOCUMENTO // PERSONA NATURAL = 1, 4 o 7 // PERSONA JURIDICA = 6
                        'required',
                        'max:1',
                        Rule::in(
                            $request->input('person_type') == 1 ? [1, 4, 7] : ($request->input('person_type') == 2 ? [6] : [])
                        ),
                    ],


                    'is_retainer' => 'boolean',
                    'retainer_percentage' => [  // VALIDACION EN CASO DE QUE LA PERSONA SEA RETENEDORA O NO
                        'nullable',
                        'numeric',
                        function ($attribute, $value, $fail) use ($request) {
                            $isRetainer = $request->input('is_retainer');

                            if ($isRetainer && $value < 0.01) {
                                $fail('El porcentaje de retención debe ser al menos 0.01.');
                            } elseif (!$isRetainer && !is_null($value)) {
                                $fail('El cliente no es retenedor, no debe ingresar un porcentaje.');
                            }
                        },
                    ],

                ],
                [
                    'max' => [
                        'string' => 'El campo :attribute no debe exceder :max caracteres.',
                    ],
                    'required' => 'El campo :attribute es obligatorio.',
                    'numeric' => 'El campo :attribute debe ser un valor numérico.',
                    'digits_between' => 'El campo :attribute debe tener entre :min y :max dígitos.',
                    'email' => 'El campo :attribute debe ser una dirección de correo electrónico válida.',
                    'nullable' => 'El campo :attribute es opcional.',
                    'in' => 'El valor seleccionado para :attribute no es válido.',
                    'boolean' => 'El campo :attribute debe ser verdadero o falso.',
                    'required_if' => 'El campo :attribute es obligatorio cuando :other es :value.',
                    'between' => [
                        'numeric' => 'El campo :attribute debe tener entre :min y :max digitos.',
                    ],

                    'ruc.required' => 'Debe ingresar un RUC.',
                    'ruc.required_if' => 'El RUC es obligatorio si el tipo de persona es juridica.',
                    'ruc.max' => 'El RUC debe tener exactamente 11 digitos.',
                    'ruc.min' => 'El RUC debe tener exactamente 11 digitos.',

                    'document_number.required_if' => 'El numero de documento es requerido.',
                    'document_number.max' => 'El número de documento no debe exceder :max caracteres.',

                    'phone.numeric' => 'El número de teléfono debe ser numérico.',
                    'phone.digits_between' => 'El número de teléfono debe tener entre :min y :max dígitos.',

                    'email.email' => 'Debe ingresar una dirección de correo electrónico válida.',

                    'direccion.required_if' => 'La dirección es obligatoria cuando es una persona juridica.',
                    'direccion.max' => 'La dirección no debe exceder :max caracteres.',

                    'customers_type_id.numeric' => 'El ID del tipo de cliente debe ser numérico.',
                    'customers_type_id.digits_between' => 'El ID del tipo de cliente debe tener entre :min y :max dígitos.',
                    'customers_type_id.exists' => 'El tipo de Cliente no existe',

                    'created_by.required' => 'El campo creado por es obligatorio.',
                    'created_by.numeric' => 'El ID del creador debe ser numérico.',
                    'created_by.digits_between' => 'El ID del creador debe tener entre :min y :max dígitos.',

                    'person_type.required' => 'El campo tipo de persona es obligatorio.',
                    'person_type.max' => 'El campo tipo de persona no debe exceder :max caracteres.',
                    'person_type.in' => 'El valor seleccionado para el tipo de persona no es válido.',

                    'document_type_id.required' => 'El campo tipo de documento es obligatorio.',
                    'document_type_id.max' => 'El campo tipo de documento no debe exceder :max caracteres.',
                    'document_type_id.in' => 'El valor seleccionado para tipo de documento no es válido.',

                    'is_retainer.required_if' => 'El campo is_retainer.required_if es obligatorio cuando la opción es verdadera.',
                    'is_retainer.numeric' => 'El porcentaje de retención debe ser un valor numérico.',
                    'is_retainer.between' => 'El porcentaje de retención debe estar entre :min y :max digitos.',

                    'retainer_percentage.required_if' => 'El campo retainer_percentage es obligatorio cuando is_retainer es verdadera.',
                ]
            );

            $store = new CustomerCreateDto();
            $store->name = $request["name"];
            $store->cf1 = $request["document_number"];
            $store->cf2 = $request["ruc"];
            $store->phone = $request["phone"];
            $store->email = $request["email"];
            $store->direccion = $request["direccion"];
            $store->customers_type_id = $request["customers_type_id"];
            $store->created_by = $request['created_by'];
            $store->created_at = date('Y-m-d h:m:s');
            $store->person_type = $request["person_type"];
            $store->document_type_id = $request["document_type_id"];
            $store->is_retainer = $request["is_retainer"];
            $store->retainer_percentage = $request["retainer_percentage"];

            $store->ruc = $business_ruc;
            $store->status = 1;

            $result = $this->customerRepository->store($store);
            return $this->successResponse($result, "El cliente se agrego correctamente", 201);
        } catch (\Illuminate\Validation\ValidationException $e) {
            return $this->errorResponse($e->response->original, 422);
        }
    }

    public function update(int $id, Request $request)
    {
        try {
            $business_information = $request['business_information'];
            $business_ruc = $business_information['ruc_number'];

            if ($this->errorConnection != '') {
                return $this->messageError($this->errorConnection, 500);
            }
            $result = $this->customerRepository->find($id, $business_ruc);

            if ($result) {
                //VALIDACION PARA 8 CEROS DE NUMERO DE DOCUMENTO
                if ($result->cf1 == '00000000') {
                    return $this->errorResponse("Datos de cliente protegidos.No se puede actualizar", 422);
                }



                //VALIDACION PARA NUMERO DE DOCUMENTO EXISTENTE
                if (isset($request['document_number']) && !empty($request['document_number'])) {
                    $docnumExists = Customer::where('cf1', $request['document_number'])
                        ->where('id', "<>", $id)
                        ->where('status', 1)
                        ->where('ruc', $business_ruc)
                        ->get();
                    if (count($docnumExists) >= 1) {
                        return $this->errorResponse("El numero de documento que ingreso ya esta registrado ", 422);
                    }
                }
                //VALIDACION PARA RUC EXISTENTE
                if (isset($request['ruc']) && !empty($request['ruc'])) { /*si existe / vacio*/
                    $rucExists = Customer::where('cf2', $request['ruc'])
                        ->where('id', "<>", $id)
                        ->where('status', 1)
                        ->where('ruc', $business_ruc)
                        ->get();
                    if (count($rucExists) >= 1) {
                        return $this->errorResponse("El numero de RUC que ingreso ya esta registrado", 422);
                    }
                }
                $this->validate($request, [
                    'name' => 'required|max:255',
                    'ruc' => [
                        function ($attribute, $value, $fail) use ($request) {
                            if ($request->input('person_type') == 2 && empty($value)) {
                                $fail('Debe ingresar un RUC.');
                            }
                        },
                        'required_if:person_type,2', // RUC es obligatorio si person_type es 2
                        'digits:11',
                        /*'nullable',*/
                    ],
                    'document_number' => [
                        function ($attribute, $value, $fail) use ($request) {
                            if ($request->input('person_type') == 2 && !empty($value)) {
                                $fail('No debe ingresar un número de documento si es persona juridica.');
                            }
                        },
                        'nullable', // Número de documento es opcional
                        'min:5',
                        'max:15',
                        'required_if:person_type,1',
                        'alpha_num',
                    ],
                    'phone' => 'numeric|digits_between:1,15',
                    'email' => 'email',
                    'direccion' => ['required_if:person_type,2|max:255'],
                    'customers_type_id' => 'nullable|numeric|digits_between:1,11',
                    'person_type' => 'required|numeric|max:2|in:1,2',
                    'document_type_id' => [
                        'required',
                        'max:1',
                        Rule::in(
                            $request->input('person_type') == 1 ? [1, 4, 7] : ($request->input('person_type') == 2 ? [6] : [])
                        ),
                    ],
                    'is_retainer' => 'boolean',
                    'retainer_percentage' => [  // VALIDACION EN CASO DE QUE LA PERSONA SEA RETENEDORA O NO
                        'nullable',
                        'numeric',
                        function ($attribute, $value, $fail) use ($request) {
                            $isRetainer = $request->input('is_retainer');

                            if ($isRetainer && $value < 0.01) {
                                $fail('El porcentaje de retención debe ser al menos 0.01.');
                            } elseif (!$isRetainer && !is_null($value)) {
                                $fail('El cliente no es retenedor, no debe ingresar un porcentaje.');
                            }
                        },
                    ],

                ], [
                    'max' => [
                        'string' => 'El campo :attribute no debe exceder :max caracteres.',
                    ],
                    'required' => 'El campo :attribute es obligatorio.',
                    'numeric' => 'El campo :attribute debe ser un valor numérico.',
                    'digits_between' => 'El campo :attribute debe tener entre :min y :max dígitos.',
                    'email' => 'El campo :attribute debe ser una dirección de correo electrónico válida.',
                    'nullable' => 'El campo :attribute es opcional.',
                    'in' => 'El valor seleccionado para :attribute no es válido.',
                    'boolean' => 'El campo :attribute debe ser verdadero o falso.',
                    'required_if' => 'El campo :attribute es obligatorio cuando :other es :value.',
                    'between' => [
                        'numeric' => 'El campo :attribute debe estar entre :min y :max.',
                    ],


                    'ruc.required_if' => 'El RUC es obligatorio si el tipo de persona es 2.',
                    'ruc.digits' => 'El RUC debe tener 11 digitos y solo numeros enteros',
                    'document_number.required_if' => 'El "Numero de documento" es obligatorio cuando el tipo de persona es natural.',
                    'document_number.min' => 'El número de documento debe ser mayor a :min caracteres.',
                    'document_number.max' => 'El número de documento no debe exceder :max caracteres.',
                    'document_number.alpha_num' => 'El número de documento debe tener solo letras y/o numeros',
                    'phone.numeric' => 'El número de teléfono solo acepta numeros.',
                    'phone.digits_between' => 'El número de teléfono debe tener minimo :min y maxino :max dígitos.',
                    'email.email' => 'Debe ingresar una dirección de correo electrónico válida.',
                    'direccion.max' => 'La dirección no debe exceder :max caracteres.',
                    'direccion.required_if' => 'La dirección es obligatoria cuando es una persona juridica.',
                    'customers_type_id.numeric' => 'El ID del tipo de cliente debe ser numérico.',
                    'customers_type_id.digits_between' => 'El ID del tipo de cliente debe tener entre :min y :max dígitos.',
                    'customers_type_id.exists' => 'El tipo de Cliente no existe',
                    'customers_type_id.required' => 'El Codigo de tipo de cliente es obligatorio',
                    'person_type.required' => 'El campo "tipo de persona" es obligatorio.',
                    'person_type.max' => 'El campo "tipo de persona" no debe tener mas de :max caracteres.',
                    'person_type.in' => 'El valor seleccionado para "tipo de persona" no es válido.',
                    'document_type_id.required' => 'El campo "tipo de documento" es obligatorio.',
                    'document_type_id.max' => 'El campo "tipo de documento" no debe exceder :max caracteres.',
                    'document_type_id.in' => 'El valor seleccionado para "tipo de documento" no es válido.',
                    'is_retainer.required_if' => 'El campo "Retenedor" es obligatorio cuando la opción es 1 o verdadera.',
                    'is_retainer.numeric' => 'El porcentaje de retención debe ser un valor numérico.',
                    'is_retainer.between' => 'El porcentaje de retención debe estar entre :min y :max .',
                ]);

                //DATA DEL REQUEST
                //$data['id'] = $id;
                //ENVIAMOS AL DTO
                //return $result;
                $entry = new CustomerUpdateDto();
                $entry->id = $id;
                $entry->name = $request['name'];
                $entry->cf1 = $request['document_number'];
                $entry->cf2 = $request['ruc'];
                $entry->phone = $request['phone'];
                $entry->email = $request['email'];
                $entry->direccion = $request['direccion'];
                $entry->customers_type_id = $request['customers_type_id'];
                $entry->created_by = $result->created_by;
                $entry->created_at = $result->created_at;
                $entry->updated_by = $request['updated_by'];
                $entry->updated_at = date('Y-m-d h:m:s');
                $entry->person_type = $request['person_type'];
                $entry->document_type_id = $request['document_type_id'];
                $entry->is_retainer = $request['is_retainer'];
                $entry->retainer_percentage = $request['retainer_percentage'];

                $entry->ruc = $business_ruc;
                $entry->status = 1;


                //ACTUALIZAMOS INFORMACION
                $this->customerRepository->update($entry);
                //Nuevamente se consulta la data del ID
                $result = $this->customerRepository->find($id, $business_ruc);

                return $this->successResponse($result, "El Cliente fue actualizado correctamente", 200);
            } else {
                return $this->errorResponse("Cliente ingresado no existe", 404);
            }
        } catch (\Illuminate\Validation\ValidationException $e) {
            return $this->errorResponse($e->response->original, 422);
        }
    }

    public function destroy(int $id, Request $request)
    {

        if ($this->errorConnection != '') {
            return $this->messageError($this->errorConnection, 500);
        }
        $business_information = $request['business_information'];
        $business_ruc = $business_information['ruc_number'];

        $result = $this->customerRepository->find($id, $business_ruc);

        if ($result) {
            $this->customerRepository->destroy($id);

            return $this->successResponse($id, "Cliente eliminado correctamente", 200);
        } else {
            return $this->errorResponse("Cliente ingresado no existe", 404);
        }
    }
}
