<?php

namespace App\Services;

use App\Models\Client\Client;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class ClientIntakeService
{
    public function create(array $data): Client
    {
        $data = $this->normaliseNameData($data);

        return DB::transaction(function () use ($data) {
            $client = Client::create([
                'solicitor_id' => $data['solicitor_id'] ?? null,
                'reference' => $data['reference'] ?? null,

                'title' => $this->standardiseName($data['title'] ?? null),
                'name_first' => $this->standardiseName($data['first_name'] ?? null),
                'name_middle' => $this->standardiseName($data['middle_name'] ?? null),
                'name_last' => $this->standardiseName($data['last_name'] ?? null),
                'name_preferred' => $this->standardiseName($data['preferred_name'] ?? null),

                'date_of_birth' => $data['dob'] ?? $data['date_of_birth'] ?? null,
                'email_address' => strtolower(trim($data['email'] ?? $data['email_address'] ?? '')),
                'phone_number' => str_replace(' ', '', $data['phone'] ?? $data['phone_number'] ?? ''),

                'tranche_id' => $data['tranche_id'] ?? null,
                'lead_source_id' => $data['lead_source_id'] ?? null,
                'lead_source_endpoint_id' => $data['lead_source_endpoint_id'] ?? null,
            ]);

            $client->claim()->create([
                'solicitor_id' => $data['solicitor_id'] ?? null,
                'status_id' => $data['status_id'] ?? 21,
            ]);

            if (! empty($data['what_type_of_care_were_you_in'])) {
                $client->notes()->create([
                    'solicitor_id' => $client->solicitor_id,
                    'user_id' => $data['user_id'] ?? null,
                    'client_id' => $client->id,
                    'note' => 'What type of care were you in? ' . $data['what_type_of_care_were_you_in'],
                ]);
            }

            if (! empty($data['anything_you_wish_to_tell_us'])) {
                $client->notes()->create([
                    'solicitor_id' => $client->solicitor_id,
                    'user_id' => $data['user_id'] ?? null,
                    'client_id' => $client->id,
                    'note' => 'Anything you wish to tell us? ' . $data['anything_you_wish_to_tell_us'],
                ]);
            }

            return $client->load('claim');
        });
    }

    private function normaliseNameData(array $data): array
    {
        $firstName = trim($data['first_name'] ?? '');
        $lastName = trim($data['last_name'] ?? '');
        $fullName = trim($data['full_name'] ?? $data['name'] ?? '');

        $hasFirstAndLast = $firstName !== '' && $lastName !== '';
        $hasFullName = $fullName !== '';

        if (! $hasFirstAndLast && ! $hasFullName) {
            throw ValidationException::withMessages([
                'name' => 'Either full name or both first name and last name are required.',
            ]);
        }

        if (! $hasFirstAndLast && $hasFullName) {
            $splitName = $this->splitFullName($fullName);

            $data['title'] = $data['title'] ?? $splitName['title'];
            $data['first_name'] = $data['first_name'] ?? $splitName['first_name'];
            $data['last_name'] = $data['last_name'] ?? $splitName['last_name'];
        }

        if (empty($data['first_name']) || empty($data['last_name'])) {
            throw ValidationException::withMessages([
                'name' => 'The name must include both a first name and last name.',
            ]);
        }

        return $data;
    }

    private function splitFullName(string $fullName): array
    {
        $titles = [
            'mr' => 'Mr',
            'mrs' => 'Mrs',
            'ms' => 'Ms',
            'miss' => 'Miss',
            'dr' => 'Dr',
            'prof' => 'Prof',
            'rev' => 'Rev',
            'sir' => 'Sir',
            'lady' => 'Lady',
            'lord' => 'Lord',
            'mx' => 'Mx',
        ];

        $result = [
            'title' => null,
            'first_name' => null,
            'last_name' => null,
        ];

        $clean = trim(preg_replace('/\s+/', ' ', $fullName));

        if ($clean === '') {
            return $result;
        }

        $tokens = explode(' ', $clean);

        $firstKey = strtolower(rtrim($tokens[0], '.'));

        if (isset($titles[$firstKey])) {
            $result['title'] = $titles[$firstKey];
            array_shift($tokens);
        }

        if (empty($tokens)) {
            return $result;
        }

        $result['first_name'] = array_shift($tokens);
        $result['last_name'] = ! empty($tokens) ? implode(' ', $tokens) : null;

        return $result;
    }

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

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

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