<?php

namespace App\Components\Client;

use App\Models\Client\Client;
use App\Models\LeadSource\LeadSource;
use App\Models\Tranche;
use App\Rules\PhoneNumber;
use App\Services\HistoryService;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Log;
use Livewire\Component;
use App\Rules\LandlineNumber;
use Illuminate\Validation\Rule;

class Edit extends Component {
    use AuthorizesRequests;

    public Client $client;

    public $title;
    public $first_name;
    public $preferred_name;
    public $middle_name;
    public $last_name;
    public $dob;
    public $email;
    public $phone;

    public $tranche_id;
    public $lead_source_id;
    public $landline;

    protected $messages = [
        'first_name.regex' => 'First name contains invalid characters.',
        'middle_name.regex' => 'Middle name contains invalid characters.',
        'last_name.regex' => 'Last name contains invalid characters.',
        'preferred_name.regex' => 'Preferred name contains invalid characters.',
        'phone.regex' => 'Phone number must be a valid UK mobile number (try the prefix of +44).',
        'landline.regex' => 'Landline number must be a valid UK landline number, for example 01511234567.',
    ];

    public function mount(Client $client): void {
        $this->authorize('edit', $client);

        $this->client = $client;

        $this->title = $client->title;
        $this->first_name = $client->name_first;
        $this->middle_name = $client->name_middle;
        $this->last_name = $client->name_last;
        $this->preferred_name = $client->name_preferred;
        $this->dob = $client->date_of_birth?->format('Y-m-d');
        $this->email = (string)$client->email_address;
        $this->phone = (string)$client->phone_number;
        $this->landline = $client->landline_number
            ? (string) $client->landline_number
            : null;
        $this->tranche_id = $client->tranche_id;
        $this->lead_source_id = $client->lead_source_id;

    }

    public function render() {
        return view('components.client.edit', [
            'tranches' => Tranche::selectRaw("id, CONCAT(funder_name, ' - ', tranche_name) as name")->pluck('name', 'id')->toArray(),
            'lead_sources' => LeadSource::pluck('display_name', 'id')->toArray(),
        ]);
    }

    public function save(HistoryService $history): void {
        $this->authorize('edit', $this->client);

        $validated = $this->validate();

        try {
            $before = $this->client->only(['title', 'name_first', 'name_middle', 'name_last', 'name_preferred', 'date_of_birth']);

            $this->client->update([
                'title' => $this->standardiseName($this->title),
                'name_first' => $this->standardiseName($this->first_name),
                'name_middle' => $this->standardiseName($this->middle_name),
                'name_last' => $this->standardiseName($this->last_name),
                'name_preferred' => $this->standardiseName($this->preferred_name),
                'date_of_birth' => $this->dob,
                'email_address' => strtolower(trim($this->email ?: '')),
                'phone_number' => $this->normaliseNumber($this->phone),
                'tranche_id' => $this->tranche_id ?: null,
                'lead_source_id' => $this->lead_source_id ?: null,
                'landline_number' => $this->normaliseNumber($this->landline),
            ]);

            $history->add($this->client, 'Client details updated.', [
                'changed' => array_diff_assoc(
                    $this->client->fresh()->only(array_keys($before)),
                    $before
                ),
            ]);

            $this->redirectRoute('clients.show', $this->client);

        } catch (\Exception $exception) {
            Log::error(
                "Failed to update client {$this->client->id}: " . $exception->getMessage()
            );

            $this->addError('client', 'An unexpected error occurred. Please try again.');
        }
    }

    protected function normaliseNumber(?string $value): ?string
    {
        if (! $value) {
            return null;
        }

        return preg_replace('/[\s\-\(\)]/', '', trim($value));
    }


    protected function standardiseName(?string $value): ?string {
        if (!$value) {
            return null;
        }

        $value = trim($value);

        $value = preg_replace('/\s+/', ' ', $value);

        $value = mb_convert_case($value, MB_CASE_TITLE, 'UTF-8');

        return $value;
    }

    protected function rules(): array {
        return [
            'title' => ['string', 'max:50', 'regex:/^[a-zA-Z\'\-\s]+$/'],
            'first_name' => ['required', 'string', 'min:2', 'max:50', 'regex:/^[a-zA-Z\'\-\s]+$/'],
            'middle_name' => ['nullable', 'string', 'min:2', 'max:50', 'regex:/^[a-zA-Z\'\-\s]+$/'],
            'last_name' => ['required', 'string', 'min:2', 'max:50', 'regex:/^[a-zA-Z\'\-\s]+$/'],
            'preferred_name' => ['nullable', 'string', 'min:2', 'max:50', 'regex:/^[a-zA-Z\'\-\s]+$/'],
            'dob' => ['required', 'date', 'before:-18 years', 'after:-120 years'],
            'email' => [
                'nullable',
                'email:rfc,dns',
                'unique:clients,email_address,' . $this->client->id . ',id',
            ],
            'phone' => ['required', new PhoneNumber()],
            'tranche_id' => ['nullable', 'integer', 'exists:tranches,id'],
            'lead_source_id' => ['nullable', 'exists:lead_sources,id'],
            'landline' => ['nullable', new LandlineNumber(), Rule::unique('clients', 'landline_number')->ignore($this->client->id)],
        ];
    }
}
