<?php

namespace App\Components\Claim;

use App\Enum\Dsar\DsarStatus;
use App\Models\Client\Client;
use App\Models\Dsar\Dsar;
use App\Models\Institution\Institution;
use App\Services\{DsarService, WipService, HistoryService};
use Illuminate\Support\Str;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Pagination\LengthAwarePaginator;
use Livewire\Component;
use Livewire\WithPagination;
use App\Trait\SupportsWip;

class Dsars extends Component {
    use AuthorizesRequests, WithPagination, SupportsWip;

    public Client $client;
    public bool $showAdd = false;
    public $search = '';
    public array $selectedIds  = [];
    public array $postIds      = [];

    public function showAddDsar() {
        $this->showAdd = true;
        $this->startWipTimer();
    }

    public function createDsars( 
            DsarService $dsar,
            HistoryService $history,
            WipService $wipService) 
        {
        $this->authorize('dsars.create');

        $tranche = $this->client->claim->dsarTranches()->create([
            'status' => 'draft'
        ]);

        $pivotDates = $this->client->claim->institutions
            ->keyBy('id')
            ->map(fn($i) => $i->pivot->dates);

        $institutionsAdded = [];
        $createdDsars = [];

        foreach ($this->selectedIds as $id) {
            $institution = Institution::find($id);

            if (!$institution) {
                throw new \Exception('Institution not found');
            }

            $slug      = (string) Str::uuid();
            $reference = 'DSAR-' . now()->format('Ymd') . '-' . strtoupper(substr($slug, 0, 6));
            $extra     = ['dsar_reference' => $reference];

            $createdDsar = $tranche->dsars()->create([
                'solicitor_id'   => $this->client->solicitor_id,
                'claim_id'       => $this->client->claim->id,
                'user_id'        => auth()->id(),
                'institution_id' => $id,
                'status'         => 'draft',
                'slug'           => $slug,
                'reference'      => $reference,
                'expected_at'    => now()->addDays(30),
                'content'        => $dsar->buildContent($institution->dsarType, $this->client, $institution, $extra),
                'email_content'  => $dsar->buildEmailContent($institution->dsarType, $this->client, $institution, $extra),
            ]);

            $createdDsars[] = $createdDsar;
            $institutionsAdded[] = $institution->display_name;
        }

        $trancheContext = [
            'claim_id' => $this->client->claim->id,
            'tranche_id' => $tranche->id,
            'institutions' => $institutionsAdded,
        ];

        // Log to the client timeline
        $history->add(
            $this->client,
            'DSAR tranche created with ' . count($institutionsAdded) . ' institution(s): ' . implode(', ', $institutionsAdded),
            $trancheContext
        );

        // Log to each individual DSAR
        foreach ($createdDsars as $createdDsar) {
            $history->add($createdDsar, 'DSAR created for "' . ($createdDsar->institution?->display_name ?? 'Unknown') . '"', [
                'claim_id' => $this->client->claim->id,
                'tranche_id' => $tranche->id,
                'institution' => $createdDsar->institution?->display_name,
            ]);
        }

        $this->hideAddDsar();

        $this->stopWipTimer();

        $wipService->create([
            'client_id' => $this->client->id,
            'claim_id' => $this->client->claim->id,
            ...$this->getWipPayload('dsar'),
            'description' => $this->wipDescription ?: 'Created ' . count($createdDsars) . ' DSAR(s)',
        ], $tranche);

        return redirect()->route('dsars.tranches.view', $tranche);
    }

    public function hideAddDsar() {
        $this->showAdd = false;
        $this->reset(['search', 'selectedIds']);
    }

    public function selectAllPostable() {
        $this->postIds = $this->client->claim->dsars()
            ->where('status', 'needs posting')
            ->pluck('id')
            ->map(fn($id) => (string) $id)
            ->all();
    }

    public function markAsPosted(HistoryService $history) {
        $this->authorize('dsars.mark-posted');

        if (empty($this->postIds)) {
            return;
        }

        Dsar::whereIn('id', $this->postIds)
            ->where('status', 'needs posting')
            ->each(function (Dsar $dsar) use ($history) {
                $dsar->update([
                    'status'    => 'sent',
                    'posted_at' => now(),
                ]);
                $context = [
                    'dsar_id'     => $dsar->id,
                    'claim_id'    => $dsar->claim_id,
                    'institution' => $dsar->institution?->display_name,
                    'posted_at'   => now()->toDateTimeString(),
                ];
                $history->add($dsar, 'DSAR to "' . ($dsar->institution?->display_name ?? 'Unknown') . '" marked as posted', $context);
                $history->add($this->client, 'DSAR to "' . ($dsar->institution?->display_name ?? 'Unknown') . '" marked as posted', $context);
            });

        $this->reset('postIds');
        $this->dispatch('toast', message: 'DSARs marked as posted.', type: 'success');
    }

    /**
     * Delete a single DSAR from the claim's list. Resolved through the claim's own
     * dsars() relation so a forged id cannot reach another client's DSAR.
     */
    public function deleteDsar(int $dsarId, HistoryService $history): void {
        $dsar = $this->client->claim->dsars()->findOrFail($dsarId);

        $this->authorize('delete', $dsar);

        $institution = $dsar->institution?->display_name ?? 'Unknown';
        $context     = [
            'dsar_id'     => $dsar->id,
            'claim_id'    => $dsar->claim_id,
            'institution' => $institution,
        ];

        $dsar->delete();

        $history->add($this->client, 'DSAR to "' . $institution . '" deleted', $context);

        $this->dispatch('toast', message: 'DSAR deleted.', type: 'success');
    }

    public function render() {
        $dsarsQuery = $this->client->claim->dsars();

        $allInstitutions = $this->client->claim->careSettings
            ->pluck('institution')
            ->filter()
            ->flatMap(function ($institution)
            {
                return collect([$institution])->concat($institution->relatedInstitutions);
            })
            ->concat($this->client->claim->institutions)
            ->unique('id');

        // Global institutions (is_prioritised) not already in the claim list
        $claimInstitutionIds = $allInstitutions->pluck('id')->all();
        $globalInstitutions = Institution::where('is_prioritised', true)
            ->when($claimInstitutionIds, fn($q) => $q->whereNotIn('id', $claimInstitutionIds))
            ->orderBy('display_name')
            ->get();

        if (!empty($this->search)) {
            $term = strtolower($this->search);
            $allInstitutions = $allInstitutions->filter(
                fn($item) => str_contains(strtolower($item->display_name), $term)
            );
            $globalInstitutions = $globalInstitutions->filter(
                fn($item) => str_contains(strtolower($item->display_name), $term)
            );
        }

        $allInstitutions = $allInstitutions->values();

        $perPage = 10;
        $currentPage = LengthAwarePaginator::resolveCurrentPage('availPage');
        $currentItems = $allInstitutions->slice(($currentPage - 1) * $perPage, $perPage)->all();

        $paginatedInstitutions = new LengthAwarePaginator(
            $currentItems,
            $allInstitutions->count(),
            $perPage,
            $currentPage,
            [
                'path' => \request()->url(),
                'query' => request()->query(),
                'pageName' => 'availPage'
            ]
        );

        $draftTranches = $this->client->claim->dsarTranches()
            ->where('status', 'draft')
            ->with('dsars')
            ->get();

        $allDsars      = $this->client->claim->dsars();
        $totalCount    = $allDsars->count();
        $sentCount     = $this->client->claim->dsars()->whereNotIn('status', ['draft', 'approved'])->count();
        $receivedCount = $this->client->claim->dsars()->whereIn('status', DsarStatus::terminal())->count();

        return view('components.claim.dsars', [
            'dsars'                 => $dsarsQuery->paginate(10, ['*'], 'dsarsPage'),
            'availableInstitutions' => $paginatedInstitutions,
            'globalInstitutions'    => $globalInstitutions,
            'draftTranches'         => $draftTranches,
            'totalCount'            => $totalCount,
            'sentCount'             => $sentCount,
            'receivedCount'         => $receivedCount,
        ]);
    }
}