<?php

namespace App\Http\Requests\Agents;

use App\Domain\Agents\Models\Agent;
use App\Domain\Organization\Models\Branch;
use App\Domain\Organization\Models\Team;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class StoreAgentRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'name' => ['required', 'string', 'max:255'],
            'local_name' => ['nullable', 'string', 'max:255'],
            'phone' => ['required', 'string', 'max:32'],
            'whatsapp' => ['nullable', 'string', 'max:32'],
            'email' => ['nullable', 'email', 'max:255'],
            'national_id' => ['nullable', 'string', 'max:50'],
            'date_of_birth' => ['nullable', 'date', 'before:today'],

            'branch_id' => ['nullable', 'uuid', Rule::exists('branches', 'uuid')->whereNull('deleted_at')],
            'team_id' => ['nullable', 'uuid', Rule::exists('teams', 'uuid')->whereNull('deleted_at')],
            'supervisor_id' => ['nullable', 'uuid', Rule::exists('agents', 'uuid')->whereNull('deleted_at')],

            'address' => ['nullable', 'string', 'max:1000'],
            'district' => ['nullable', 'string', 'max:100'],
            'upazila' => ['nullable', 'string', 'max:100'],
            'territory' => ['nullable', 'string', 'max:255'],

            'agent_type' => ['nullable', Rule::in(['external', 'internal', 'referral'])],
            'joining_date' => ['nullable', 'date'],
            'contract_start_date' => ['nullable', 'date'],
            'contract_end_date' => ['nullable', 'date', 'after_or_equal:contract_start_date'],

            'bank_name' => ['nullable', 'string', 'max:255'],
            'bank_branch' => ['nullable', 'string', 'max:255'],
            'bank_account_name' => ['nullable', 'string', 'max:255'],
            'bank_account_number' => ['nullable', 'string', 'max:64'],
            'mobile_wallet_provider' => ['nullable', 'string', 'max:40'],
            'mobile_wallet_number' => ['nullable', 'string', 'max:32'],

            'monthly_target' => ['nullable', 'integer', 'min:0', 'max:100000'],
            'notes' => ['nullable', 'string', 'max:5000'],
        ];
    }

    /**
     * A phone number identifies an agent in the field; duplicates within one
     * company usually mean the same person being registered twice.
     */
    public function withValidator($validator): void
    {
        $validator->after(function ($validator) {
            $companyId = $this->user()?->company_id;
            $phone = $this->input('phone');

            if ($companyId === null || blank($phone)) {
                return;
            }

            $duplicate = Agent::where('company_id', $companyId)
                ->where('phone', $phone)
                ->when($this->route('agent'), fn ($query) => $query->whereKeyNot($this->route('agent')->getKey()))
                ->exists();

            if ($duplicate) {
                $validator->errors()->add('phone', 'An agent with this phone number already exists.');
            }
        });
    }

    /** @return array<string, mixed> */
    public function modelAttributes(): array
    {
        $data = $this->validated();

        $data['branch_id'] = $this->resolveKey(Branch::class, $data['branch_id'] ?? null);
        $data['team_id'] = $this->resolveKey(Team::class, $data['team_id'] ?? null);
        $data['supervisor_id'] = $this->resolveKey(Agent::class, $data['supervisor_id'] ?? null);

        return $data;
    }

    private function resolveKey(string $model, ?string $uuid): ?int
    {
        return $uuid === null ? null : $model::where('uuid', $uuid)->value('id');
    }
}
