<?php

namespace App\Components\Client;

use App\Models\Claim\Status;
use App\Models\Client\Client;
use App\Models\Institution\Institution;
use App\Models\LeadSource\LeadSource;
use App\Models\LeadSource\LeadSourceEndpoint;
use App\Models\Tag;
use App\Models\Tranche;
use App\Models\User\User;
use App\Services\ClientService;
use App\Services\HistoryService;
use Livewire\Attributes\Lazy;
use Livewire\Attributes\On;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

#[Lazy]
class Index extends Component {

    use WithPagination;

    public $search = '';
    public $sortColumn = 'name_last';
    public $sortDirection = 'asc';
    public $perPage = 10;

    #[Url(history: true)]
    public $status_id = null;
    #[Url(history: true)]
    public $lead_source_id = null;
    #[Url(history: true)]
    public $url = null;
    #[Url(history: true)]
    public $date_from = null;
    #[Url(history: true)]
    public $date_to = null;
    #[Url(history: true)]
    public $care_setting_id = null;
    #[Url(history: true)]
    public $tranche_id = null;
    protected ClientService $clientService;
    #[Url(history: true)]
    public $priority;
    #[Url(history: true)]
    public $tag_id;
    #[Url(history: true)]
    public $handler = null;

    public function placeholder() {
        return <<<'HTML'
        <div class="row">
            <div class="col-12 col-md-9">
                <div class="card">
                    <div class="card-body">
                        <div class="placeholder placeholder-wave w-100"></div>
                        <div class="placeholder placeholder-wave w-100"></div>
                        <div class="placeholder placeholder-wave w-75"></div>
                        <div class="placeholder placeholder-wave w-50"></div>
                    </div>
                </div>
            </div>
        </div>
        HTML;

    }

    public function boot(ClientService $clientService) {
        $this->clientService = $clientService;
    }

    #[On('status-updated')]
    public function onStatusUpdated(): void {
        // Livewire will re-render on event receipt; no state change needed.
    }


    public function render() {
        $clients = Client::whereHas('claim');

        if ($this->search !== '') {
            $search = trim($this->search);

            $clients->where(function ($query) use ($search) {
                $phoneSearch = $search;
                if (str_starts_with($phoneSearch, '07')) {
                    $phoneSearch = '+44' . substr($phoneSearch, 1);
                }

                $like = '%' . $search . '%';
                $likeSqueezed = '%' . preg_replace('/\s+/', '', $search) . '%';

                $query
                    ->orWhere('email_address', 'like', $like)
                    ->orWhere('phone_number', 'like', '%' . $phoneSearch . '%')
                    ->orWhere('landline', 'like', '%' . $phoneSearch . '%')
                    ->orWhere('reference', 'like', $like)
                    ->orWhere('name_first', 'like', $like)
                    ->orWhere('name_middle', 'like', $like)
                    ->orWhere('name_last', 'like', $like)
                    ->orWhere('name_preferred', 'like', $like)
                    ->orWhereRaw("CONCAT_WS(' ', title, name_first, name_last) LIKE ?", [$like])
                    ->orWhereRaw("CONCAT_WS(' ', title, name_first, name_middle, name_last) LIKE ?", [$like])
                    ->orWhereRaw("REPLACE(CONCAT_WS('', title, name_first, name_middle, name_last), ' ', '') LIKE ?", [$likeSqueezed]);

                $tokens = preg_split('/\s+/', $search, -1, PREG_SPLIT_NO_EMPTY);
                if (count($tokens) > 1) {
                    $query->orWhere(function ($q) use ($tokens) {
                        foreach ($tokens as $token) {
                            $q->where(function ($inner) use ($token) {
                                $inner->where('name_first', 'like', '%' . $token . '%')
                                    ->orWhere('name_middle', 'like', '%' . $token . '%')
                                    ->orWhere('name_last', 'like', '%' . $token . '%')
                                    ->orWhere('name_preferred', 'like', '%' . $token . '%');
                            });
                        }
                    });
                }

                $query->orWhereHas('pensionCases', function ($q) use ($like) {
                    $q->where('national_insurance', 'like', $like)
                        ->orWhere('case_number', 'like', $like);
                })->orWhereHas('willsCases', function ($q) use ($like) {
                    $q->where('national_insurance', 'like', $like)
                        ->orWhere('case_number', 'like', $like);
                });

                if (is_numeric($this->search)) {
                    $query->orWhere('id', $search - 100000);
                }
            });
        }

        if ($this->status_id) {
            $clients->whereHas('claim', function ($claims) {
                $claims->where('status_id', $this->status_id);
            });
        }

        if (is_numeric($this->tranche_id)) {
            $tranche = $this->tranche_id ?: null;
            $clients->where('tranche_id', $tranche);
        }

        if ($this->lead_source_id !== null) {
            if ($this->lead_source_id) {
                $clients->where('lead_source_id', $this->lead_source_id);
            } else {
                $clients->whereNull('lead_source_id');
            }
        }

        if ($this->handler) {
            $handler = $this->handler;
            $clients->whereHas('handlers', function ($query) use ($handler) {
                $query->where('user_id', $handler);
            });
        }

        if ($this->url !== null) {
            if ($this->url) {
                $clients->where('lead_source_endpoint_id', $this->url);
            } else {
                $clients->whereNull('lead_source_endpoint_id');
            }
        }

        if ($this->tag_id) {
            $clients->whereHas('claim.tags', function ($tags) {
                $tags->where('tags.id', $this->tag_id);
            });
        }

        if ($this->priority) {
            $clients->where(function ($priorityQuery) {
                if ($this->priority == 1) {
                    $priorityQuery->whereHas('claim.terminalIllness')
                        ->orWhereDate('clients.date_of_birth', '<', now()->subYears(68));
                } elseif ($this->priority == 2) {
                    $priorityQuery->whereHas('claim', function ($claim) {
                        $claim->whereDoesntHave('terminalIllness');
                    })->whereDate('clients.date_of_birth', '>', now()->subYears(68));
                }
            });
        }

        if ($this->date_from) {
            $clients->whereDate('created_at', '>=', $this->date_from);
        }

        if ($this->date_to) {
            $clients->whereDate('created_at', '<=', $this->date_to);
        }

        if ($this->care_setting_id) {
            $clients->whereHas('claim', function ($claim) {
                $claim->whereHas('careSettings', function ($careSettings) {
                    $careSettings->where('institution_id', $this->care_setting_id);
                });
            });
        }

        $clients = $clients->paginate($this->perPage);

        $endpoints = LeadSourceEndpoint::query()
            ->get(['id', 'url', 'display_name'])
            ->mapWithKeys(fn($endpoint) => [
                $endpoint->id => "{$endpoint->url} - {$endpoint->display_name}"
            ])
            ->toArray();

        $tranches = Tranche::query()->get([
            'funder_name', 'tranche_name', 'id'
        ])->mapWithKeys(fn($tranche) => [
            $tranche->id => "{$tranche->funder_name} - {$tranche->tranche_name}"
        ])->toArray();

        $endpoints = [0 => 'None Assigned'] + $endpoints;
        $tranches = [0 => 'None Assigned'] + $tranches;

        return view('components.client.client-list', [
            'clients' => $clients,
            'leadSources' => LeadSource::pluck('display_name', 'id')->toArray(),
            'urls' => $endpoints,
            'statuses' => Status::where('type', 'ha')->pluck('display_name', 'id')->toArray(),
            'careSettings' => Institution::orderBy('display_name')->pluck('display_name', 'id')->toArray(),
            'tags' => Tag::pluck('name', 'id')->toArray(),
            'tranches' => $tranches,
            'handlers' => User::all()->mapWithKeys(function ($user) {
                return [$user->id => $user->name_first . ' ' . $user->name_last];
            })->toArray(),
        ]);
    }

    public function clearFilters() {
        $this->reset('lead_source_id', 'url', 'date_from', 'date_to', 'status_id', 'care_setting_id');
    }

    public function checkDeleteClient($clientId) {
        $this->dispatch('swal:confirm',
            itemId: $clientId,
            title: 'Are you absolutely sure?',
            text: 'You will not be able to recover this client.'
        );
    }

    public function deleteClient(HistoryService $history, $clientId) {
        $client = Client::findOrFail($clientId);
        if ($this->clientService->delete($client, $history)) {
            $this->dispatch("alert", title: $client->name_first . " " . $client->name_last . " Deleted");
        }
    }
}
