<?php

namespace App\Http\Controllers;

use App\Models\Activity;
use App\Models\Client;
use App\Models\ClientCase;
use App\Models\Contract;
use Illuminate\Http\Request;
use Inertia\Inertia;

class NotificationController extends Controller
{
    public function unread(Request $request)
    {
        $user = $request->user();
        if (! $user) {
            abort(403);
        }

        $today = now()->toDateString();
        $perPage = max(1, min(100, (int) $request->integer('per_page', 15)));
        $search = trim((string) $request->input('search', ''));
        $clientUuid = trim((string) $request->input('client', ''));
        $clientId = null;
        $clientCaseIdsForFilter = collect();
        if ($clientUuid !== '') {
            $clientId = Client::query()->where('uuid', $clientUuid)->value('id');
            if ($clientId) {
                $clientCaseIdsForFilter = ClientCase::query()->where('client_id', $clientId)->pluck('id');
            }
        }

        $query = Activity::query()
            ->select(['id', 'due_date', 'amount', 'contract_id', 'client_case_id', 'created_at'])
            ->whereNotNull('due_date')
            ->whereDate('due_date', '<=', $today)
            // Exclude activities that have been marked as read by this user
            ->whereNotExists(function ($q) use ($user, $today) {
                $q->select(\DB::raw(1))
                    ->from('activity_notification_reads')
                    ->whereColumn('activity_notification_reads.activity_id', 'activities.id')
                    ->where('activity_notification_reads.user_id', $user->id)
                    ->whereDate('activity_notification_reads.due_date', '<=', $today)
                    ->whereNotNull('activity_notification_reads.read_at');
            })
            ->when($clientCaseIdsForFilter->isNotEmpty(), function ($q) use ($clientCaseIdsForFilter) {
                // Filter by clients: activities directly on any of the client's cases OR via contracts under those cases
                $q->where(function ($qq) use ($clientCaseIdsForFilter) {
                    $qq->whereIn('activities.client_case_id', $clientCaseIdsForFilter)
                        ->orWhereIn('activities.contract_id', Contract::query()
                            ->select('id')
                            ->whereIn('client_case_id', $clientCaseIdsForFilter)
                        );
                });
            })
            // allow simple search by contract reference or person name
            ->when($search !== '', function ($q) use ($search) {
                $s = mb_strtolower($search);
                $q->leftJoin('contracts', 'contracts.id', '=', 'activities.contract_id')
                    ->leftJoin('client_cases', 'client_cases.id', '=', 'activities.client_case_id')
                    ->leftJoin('person', 'person.id', '=', 'client_cases.person_id')
                    ->where(function ($qq) use ($s) {
                        $qq->whereRaw('LOWER(COALESCE(contracts.reference, \'\')) LIKE ?', ['%'.$s.'%'])
                            ->orWhereRaw('LOWER(COALESCE(person.full_name, \'\')) LIKE ?', ['%'.$s.'%']);
                    });
            })
            ->with([
                'contract' => function ($q) {
                    $q->select(['contracts.id', 'contracts.uuid', 'contracts.reference', 'contracts.client_case_id'])
                        ->with([
                            'clientCase' => function ($qq) {
                                $qq->select(['client_cases.id', 'client_cases.uuid', 'client_cases.client_id'])
                                    ->with([
                                        'client' => function ($qqq) {
                                            $qqq->select(['clients.id', 'clients.uuid', 'clients.person_id'])
                                                ->with([
                                                    'person' => function ($qqqq) {
                                                        $qqqq->select(['person.id', 'person.full_name']);
                                                    },
                                                ]);
                                        },
                                    ]);
                            },
                            'account' => function ($qq) {
                                $qq->select(['accounts.id', 'accounts.contract_id', 'accounts.balance_amount', 'accounts.initial_amount']);
                            },
                        ]);
                },
                'clientCase' => function ($q) {
                    $q->select(['client_cases.id', 'client_cases.uuid', 'client_cases.person_id', 'client_cases.client_id'])
                        ->with([
                            'person' => function ($qq) {
                                $qq->select(['person.id', 'person.full_name']);
                            },
                            'client' => function ($qq) {
                                $qq->select(['clients.id', 'clients.uuid', 'clients.person_id'])
                                    ->with([
                                        'person' => function ($qqq) {
                                            $qqq->select(['person.id', 'person.full_name']);
                                        },
                                    ]);
                            },
                        ]);
                },
            ])
            // force ordering by due_date DESC only
            ->orderByDesc('activities.due_date');

        // Use a custom page parameter name to match the frontend DataTableServer
        $activities = $query->paginate($perPage, ['*'], 'unread-page')->withQueryString();

        // Build a distinct clients list for the filter (client UUID + client.person.full_name)
        // Collect client_case_ids from both direct activities and via contracts
        $baseForClients = Activity::query()
            ->select(['contract_id', 'client_case_id'])
            ->whereNotNull('due_date')
            ->whereDate('due_date', '<=', $today)
            // Exclude activities that have been marked as read by this user
            ->whereNotExists(function ($q) use ($user, $today) {
                $q->select(\DB::raw(1))
                    ->from('activity_notification_reads')
                    ->whereColumn('activity_notification_reads.activity_id', 'activities.id')
                    ->where('activity_notification_reads.user_id', $user->id)
                    ->whereDate('activity_notification_reads.due_date', '<=', $today)
                    ->whereNotNull('activity_notification_reads.read_at');
            })
            ->when($clientCaseIdsForFilter->isNotEmpty(), function ($q) use ($clientCaseIdsForFilter) {
                $q->where(function ($qq) use ($clientCaseIdsForFilter) {
                    $qq->whereIn('activities.client_case_id', $clientCaseIdsForFilter)
                        ->orWhereIn('activities.contract_id', Contract::query()->select('id')->whereIn('client_case_id', $clientCaseIdsForFilter));
                });
            })
            ->get();

        $contractIds = $baseForClients->pluck('contract_id')->filter()->unique()->values();
        $directCaseIds = $baseForClients->pluck('client_case_id')->filter()->unique()->values();
        $mapContractToCase = $contractIds->isNotEmpty()
            ? Contract::query()->whereIn('id', $contractIds)->pluck('client_case_id', 'id')
            : collect();
        $caseIds = $directCaseIds
            ->merge($contractIds->map(fn ($cid) => $mapContractToCase->get($cid)))
            ->filter()
            ->unique()
            ->values();

        // Map caseIds -> clientIds, then load clients and present as value(label)
        $clientIds = $caseIds->isNotEmpty()
            ? ClientCase::query()->whereIn('id', $caseIds)->pluck('client_id')->filter()->unique()->values()
            : collect();

        $clients = $clientIds->isNotEmpty()
            ? Client::query()
                ->whereIn('id', $clientIds)
                ->with(['person:id,full_name'])
                ->get(['id', 'uuid', 'person_id'])
                ->map(fn ($c) => [
                    'value' => $c->uuid,
                    'label' => optional($c->person)->full_name ?: '(neznana stranka)',
                ])
                ->sortBy('label', SORT_NATURAL | SORT_FLAG_CASE)
                ->values()
            : collect();

        return Inertia::render('Notifications/Unread', [
            'activities' => $activities,
            'today' => $today,
            'clients' => $clients,
        ]);
    }
}
