<?php

declare(strict_types=1);

namespace App\Http\Requests\Pwa;

use App\Models\CompanyFinancialSettings;
use App\Models\User;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class StoreCreditRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    /**
     * Devuelve las reglas de validación usando los límites reales de la empresa.
     * Los valores hardcodeados anteriores eran independientes de la configuración
     * de la empresa — ahora se leen directamente de CompanyFinancialSettings.
     */
    public function rules(): array
    {
        $companyId = $this->user()->company_id;
        $settings = $this->getCompanySettings();

        $allowedPeriodicities = $settings->allowed_periodicities ?? ['daily', 'weekly', 'biweekly', 'monthly'];

        return [
            'client_id' => [
                'required',
                'integer',
                Rule::exists('clients', 'id')->where('company_id', $companyId),
            ],
            'amount' => [
                'required', 'numeric',
                'min:'.(float) $settings->min_credit_amount,
                'max:'.(float) $settings->max_credit_amount,
            ],
            'interest_rate' => [
                'required', 'numeric',
                'min:'.(float) $settings->min_interest_rate,
                'max:'.(float) $settings->max_interest_rate,
            ],
            'installments_count' => [
                'required', 'integer',
                'min:'.(int) $settings->min_installments,
                'max:'.(int) $settings->max_installments,
            ],
            'periodicity' => ['required', 'string', Rule::in($allowedPeriodicities)],
            'start_date' => ['required', 'date', 'after_or_equal:today'],
            'first_due_date_override' => ['nullable', 'date', 'after_or_equal:start_date'],
            'due_day_1' => ['nullable', 'integer', 'min:1', 'max:31'],
            'due_day_2' => ['nullable', 'integer', 'min:1', 'max:31'],
            'collector_user_id' => [
                'nullable',
                'integer',
                Rule::exists('users', 'id')->where('company_id', $companyId),
                function ($attribute, $value, $fail) use ($companyId) {
                    if ($value === null) {
                        return;
                    }
                    $target = User::where('id', $value)
                        ->where('company_id', $companyId)
                        ->first();
                    if ($target && ! $target->hasRole('collector')) {
                        $fail('El usuario asignado debe tener el rol de cobrador.');
                    }
                },
            ],
            'notes' => ['nullable', 'string', 'max:500'],
            'is_simplified_amount' => ['nullable', 'boolean'],
            'simplified_amount_confirmed' => ['nullable', 'boolean'],
            'add_to_route' => ['nullable', 'boolean'],
            'idempotency_key' => ['nullable', 'uuid'],
        ];
    }

    public function messages(): array
    {
        $settings = $this->getCompanySettings();
        $minAmount = number_format((float) $settings->min_credit_amount, 0, ',', '.');
        $maxAmount = number_format((float) $settings->max_credit_amount, 0, ',', '.');
        $minRate = (float) $settings->min_interest_rate;
        $maxRate = (float) $settings->max_interest_rate;
        $minCuotas = (int) $settings->min_installments;
        $maxCuotas = (int) $settings->max_installments;

        return [
            'client_id.required' => 'El cliente es obligatorio.',
            'client_id.exists' => 'El cliente no existe o no pertenece a tu empresa.',
            'amount.required' => 'El monto es obligatorio.',
            'amount.min' => "El monto mínimo permitido es \${$minAmount}.",
            'amount.max' => "El monto máximo permitido es \${$maxAmount}.",
            'interest_rate.required' => 'La tasa de interés es obligatoria.',
            'interest_rate.min' => "La tasa mínima permitida es {$minRate}%.",
            'interest_rate.max' => "La tasa máxima permitida es {$maxRate}%.",
            'installments_count.required' => 'El número de cuotas es obligatorio.',
            'installments_count.min' => "El mínimo de cuotas permitido es {$minCuotas}.",
            'installments_count.max' => "El máximo de cuotas permitido es {$maxCuotas}.",
            'periodicity.required' => 'La periodicidad es obligatoria.',
            'periodicity.in' => 'La periodicidad seleccionada no está habilitada para esta empresa.',
            'start_date.required' => 'La fecha de inicio es obligatoria.',
            'start_date.after_or_equal' => 'La fecha de inicio no puede ser pasada.',
            'first_due_date_override.after_or_equal' => 'La fecha de primera cuota debe ser igual o posterior al inicio.',
            'collector_user_id.exists' => 'El cobrador no existe o no pertenece a tu empresa.',
            'idempotency_key.uuid' => 'La clave de idempotencia debe ser un UUID válido.',
        ];
    }

    /**
     * Carga (con caché en la instancia) los ajustes financieros de la empresa.
     */
    private function getCompanySettings(): CompanyFinancialSettings
    {
        return CompanyFinancialSettings::forCompany($this->user()->company_id);
    }

    /**
     * Prepare the data for validation.
     */
    protected function prepareForValidation(): void
    {
        $user = $this->user();

        // Si el usuario es Collector puro (sin rol supervisor ni admin),
        // forzar que el crédito se asigne a sí mismo, ignorando cualquier
        // collector_user_id enviado en el payload.
        $roles = $user->getRoleNames();
        if (
            $roles->contains('collector')
            && ! $roles->contains('supervisor')
            && ! $roles->contains('admin')
        ) {
            $this->merge(['collector_user_id' => $user->id]);
        }

        // Convertir periodicidad en español a inglés si es necesario
        $periodicityMap = [
            'diaria' => 'daily',
            'semanal' => 'weekly',
            'quincenal' => 'biweekly',
            'mensual' => 'monthly',
        ];

        if ($this->periodicity && isset($periodicityMap[strtolower($this->periodicity)])) {
            $this->merge([
                'periodicity' => $periodicityMap[strtolower($this->periodicity)],
            ]);
        }

        // Handle simplified input conversion
        if ($this->boolean('is_simplified_amount') && $this->amount) {
            $settings = CompanyFinancialSettings::forCompany($user->company_id);

            if ($settings->isSimplifiedInputEnabled('pwa_credit_create')) {
                $realAmount = $settings->convertSimplifiedToReal((float) $this->amount);
                $this->merge([
                    'amount' => $realAmount,
                    'original_simplified_amount' => $this->amount,
                ]);
            }
        }
    }
}
