<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Contribution;
use App\Models\Discussion;
use App\Models\HealthInstitution;
use App\Models\KnowledgeBaseQuestion;
use App\Models\LoanApplication;
use App\Models\LoanProduct;
use App\Models\Member;
use App\Models\Mentorship\Assignment;
use App\Models\Mentorship\Programme;
use App\Models\Mentorship\Session as MentorshipSession;
use App\Models\RCampaign;
use App\Models\RForumThread;
use App\Models\RHealthStory;
use App\Models\RPartner;
use App\Models\RPublication;
use App\Models\TrainingCertificate;
use App\Models\TrainingPackage;
use App\Models\TrainingRegistration;
use App\Models\TrainingSession;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

/**
 * HeaderSearchController
 *
 * Handles role-scoped AJAX live search for the app header.
 * Each role sees only the models within its permitted Search_Scope.
 *
 * Requirements: 4.1, 4.2, 4.3, 4.10, 10.1, 10.5
 */
class HeaderSearchController extends Controller
{
    /**
     * Maximum results returned per model type.
     */
    private const LIMIT = 5;

    /**
     * GET /api/header/search?q={query}
     *
     * Validates the query, resolves the authenticated user's role,
     * dispatches to the appropriate scope method, and returns grouped results.
     *
     * Requirements: 4.1, 4.2, 4.3, 10.5
     */
    public function search(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'q' => ['required', 'string', 'min:2', 'max:100'],
        ]);

        $q    = $validated['q'];
        $user = $request->user();
        $role = $user->roles->first()?->name ?? '';

        $results = match (true) {
            in_array($role, ['Super Manager', 'Manager']) => $this->searchSuperManager($q),
            $role === 'Members'                           => $this->searchMembers($q, $user),
            $role === 'Trainers'                          => $this->searchTrainers($q, $user),
            $role === 'Trainees'                          => $this->searchTrainees($q, $user),
            $role === 'Mentor'                            => $this->searchMentor($q, $user),
            $role === 'Mentee'                            => $this->searchMentee($q, $user),
            $role === 'Partners'                          => $this->searchPartners($q),
            $role === 'Contributor'                       => $this->searchContributor($q),
            $role === 'Health Marketor'                   => $this->searchHealthMarketor($q, $user),
            default                                       => [],
        };

        $total = array_sum(array_map('count', $results));

        return response()->json([
            'results' => $results,
            'total'   => $total,
        ]);
    }

    // =========================================================================
    // ROLE SCOPE METHODS
    // =========================================================================

    /**
     * Super Manager / Manager scope.
     * Searches: Users, Members, Training Packages, Mentorship Programmes,
     *           Loan Applications, Publications.
     */
    private function searchSuperManager(string $q): array
    {
        $results = [];

        $users = User::where('name', 'like', "%{$q}%")
            ->orWhere('email', 'like', "%{$q}%")
            ->limit(self::LIMIT)
            ->get();

        if ($users->isNotEmpty()) {
            $results['Users'] = $users->map(fn ($u) => [
                'id'       => $u->id,
                'title'    => $u->name,
                'subtitle' => $u->email,
                'url'      => route('users.edit', $u->id),
                'type'     => 'Users',
            ])->values()->all();
        }

        $members = Member::whereHas('user', fn ($q2) => $q2->where('name', 'like', "%{$q}%"))
            ->orWhere('membership_code', 'like', "%{$q}%")
            ->limit(self::LIMIT)
            ->get();

        if ($members->isNotEmpty()) {
            $results['Members'] = $members->map(fn ($m) => [
                'id'       => $m->id,
                'title'    => $m->full_name,
                'subtitle' => $m->membership_code,
                'url'      => route('membership.members.show', $m->id),
                'type'     => 'Members',
            ])->values()->all();
        }

        $packages = TrainingPackage::where('name', 'like', "%{$q}%")
            ->limit(self::LIMIT)
            ->get();

        if ($packages->isNotEmpty()) {
            $results['Training Packages'] = $packages->map(fn ($p) => [
                'id'       => $p->id,
                'title'    => $p->name,
                'subtitle' => ucfirst($p->status),
                'url'      => route('training.packages.show', $p->id),
                'type'     => 'Training Packages',
            ])->values()->all();
        }

        $programmes = Programme::where('title', 'like', "%{$q}%")
            ->limit(self::LIMIT)
            ->get();

        if ($programmes->isNotEmpty()) {
            $results['Mentorship Programmes'] = $programmes->map(fn ($p) => [
                'id'       => $p->id,
                'title'    => $p->title,
                'subtitle' => $p->is_active ? 'Active' : 'Inactive',
                'url'      => route('mentorship.programmes.show', $p->id),
                'type'     => 'Mentorship Programmes',
            ])->values()->all();
        }

        $loans = LoanApplication::where('reference_number', 'like', "%{$q}%")
            ->orWhere('purpose', 'like', "%{$q}%")
            ->limit(self::LIMIT)
            ->get();

        if ($loans->isNotEmpty()) {
            $results['Loan Applications'] = $loans->map(fn ($l) => [
                'id'       => $l->id,
                'title'    => $l->reference_number,
                'subtitle' => ucfirst($l->status),
                'url'      => route('membership.loans.show', $l->id),
                'type'     => 'Loan Applications',
            ])->values()->all();
        }

        $publications = RPublication::where('title', 'like', "%{$q}%")
            ->orWhere('abstract', 'like', "%{$q}%")
            ->limit(self::LIMIT)
            ->get();

        if ($publications->isNotEmpty()) {
            $results['Publications'] = $publications->map(fn ($p) => [
                'id'       => $p->id,
                'title'    => $p->title,
                'subtitle' => ucfirst($p->status),
                'url'      => route('research.show', $p->id),
                'type'     => 'Publications',
            ])->values()->all();
        }

        return $results;
    }

    /**
     * Members scope.
     * Searches: Training Packages, Knowledge Base Questions, Contributions, Loan Products.
     */
    private function searchMembers(string $q, User $user): array
    {
        $results = [];

        $packages = TrainingPackage::where('name', 'like', "%{$q}%")
            ->where('is_public', true)
            ->limit(self::LIMIT)
            ->get();

        if ($packages->isNotEmpty()) {
            $results['Training Packages'] = $packages->map(fn ($p) => [
                'id'       => $p->id,
                'title'    => $p->name,
                'subtitle' => $p->is_free ? 'Free' : $p->getFormattedFee(),
                'url'      => route('public.training.show', $p->id),
                'type'     => 'Training Packages',
            ])->values()->all();
        }

        $questions = KnowledgeBaseQuestion::where('title', 'like', "%{$q}%")
            ->where('is_published', true)
            ->limit(self::LIMIT)
            ->get();

        if ($questions->isNotEmpty()) {
            $results['Knowledge Base'] = $questions->map(fn ($kb) => [
                'id'       => $kb->id,
                'title'    => $kb->title,
                'subtitle' => ucfirst($kb->difficulty),
                'url'      => route('public.knowledge-base.show', $kb->slug),
                'type'     => 'Knowledge Base',
            ])->values()->all();
        }

        $member = $user->member ?? null;
        if ($member) {
            $contributions = Contribution::where('member_id', $member->id)
                ->where('description', 'like', "%{$q}%")
                ->limit(self::LIMIT)
                ->get();

            if ($contributions->isNotEmpty()) {
                $results['Contributions'] = $contributions->map(fn ($c) => [
                    'id'       => $c->id,
                    'title'    => $c->description ?? 'Contribution #' . $c->id,
                    'subtitle' => ucfirst($c->status),
                    'url'      => route('membership.contributions.show', $c->id),
                    'type'     => 'Contributions',
                ])->values()->all();
            }
        }

        $loanProducts = LoanProduct::where('name', 'like', "%{$q}%")
            ->where('is_active', true)
            ->limit(self::LIMIT)
            ->get();

        if ($loanProducts->isNotEmpty()) {
            $results['Loan Products'] = $loanProducts->map(fn ($lp) => [
                'id'       => $lp->id,
                'title'    => $lp->name,
                'subtitle' => 'Up to ' . number_format($lp->max_amount ?? 0),
                'url'      => route('membership.loan-products.show', $lp->id),
                'type'     => 'Loan Products',
            ])->values()->all();
        }

        return $results;
    }

    /**
     * Trainers scope.
     * Searches: Training Sessions, Registrations, Certificates.
     */
    private function searchTrainers(string $q, User $user): array
    {
        $results = [];

        $sessions = TrainingSession::where('session_name', 'like', "%{$q}%")
            ->whereHas('trainers', fn ($tq) => $tq->where('users.id', $user->id))
            ->limit(self::LIMIT)
            ->get();

        if ($sessions->isNotEmpty()) {
            $results['Training Sessions'] = $sessions->map(fn ($s) => [
                'id'       => $s->id,
                'title'    => $s->session_name,
                'subtitle' => $s->session_date?->format('M j, Y') ?? '',
                'url'      => route('training.sessions.show', $s->id),
                'type'     => 'Training Sessions',
            ])->values()->all();
        }

        $registrations = TrainingRegistration::whereHas(
            'trainingPackage',
            fn ($pq) => $pq->where('name', 'like', "%{$q}%")
        )
            ->whereHas('trainingPackage.sessions.trainers', fn ($tq) => $tq->where('users.id', $user->id))
            ->limit(self::LIMIT)
            ->get();

        if ($registrations->isNotEmpty()) {
            $results['Registrations'] = $registrations->map(fn ($r) => [
                'id'       => $r->id,
                'title'    => $r->trainingPackage?->name ?? 'Registration #' . $r->id,
                'subtitle' => ucfirst($r->status),
                'url'      => route('training.registrations.show', $r->id),
                'type'     => 'Registrations',
            ])->values()->all();
        }

        $certificates = TrainingCertificate::whereHas(
            'trainingPackage',
            fn ($pq) => $pq->where('name', 'like', "%{$q}%")
        )
            ->where('is_revoked', false)
            ->limit(self::LIMIT)
            ->get();

        if ($certificates->isNotEmpty()) {
            $results['Certificates'] = $certificates->map(fn ($c) => [
                'id'       => $c->id,
                'title'    => $c->trainingPackage?->name ?? $c->certificate_number,
                'subtitle' => $c->certificate_number,
                'url'      => route('training.certificates.show', $c->id),
                'type'     => 'Certificates',
            ])->values()->all();
        }

        return $results;
    }

    /**
     * Trainees scope.
     * Searches: Training Packages, My Registrations, Certificates.
     */
    private function searchTrainees(string $q, User $user): array
    {
        $results = [];

        $packages = TrainingPackage::where('name', 'like', "%{$q}%")
            ->where('is_public', true)
            ->limit(self::LIMIT)
            ->get();

        if ($packages->isNotEmpty()) {
            $results['Training Packages'] = $packages->map(fn ($p) => [
                'id'       => $p->id,
                'title'    => $p->name,
                'subtitle' => $p->is_free ? 'Free' : $p->getFormattedFee(),
                'url'      => route('public.training.show', $p->id),
                'type'     => 'Training Packages',
            ])->values()->all();
        }

        $registrations = TrainingRegistration::where('user_id', $user->id)
            ->whereHas('trainingPackage', fn ($pq) => $pq->where('name', 'like', "%{$q}%"))
            ->limit(self::LIMIT)
            ->get();

        if ($registrations->isNotEmpty()) {
            $results['My Registrations'] = $registrations->map(fn ($r) => [
                'id'       => $r->id,
                'title'    => $r->trainingPackage?->name ?? 'Registration #' . $r->id,
                'subtitle' => ucfirst($r->status),
                'url'      => route('training.registrations.show', $r->id),
                'type'     => 'My Registrations',
            ])->values()->all();
        }

        $certificates = TrainingCertificate::where('user_id', $user->id)
            ->whereHas('trainingPackage', fn ($pq) => $pq->where('name', 'like', "%{$q}%"))
            ->where('is_revoked', false)
            ->limit(self::LIMIT)
            ->get();

        if ($certificates->isNotEmpty()) {
            $results['Certificates'] = $certificates->map(fn ($c) => [
                'id'       => $c->id,
                'title'    => $c->trainingPackage?->name ?? $c->certificate_number,
                'subtitle' => $c->certificate_number,
                'url'      => route('training.certificates.show', $c->id),
                'type'     => 'Certificates',
            ])->values()->all();
        }

        return $results;
    }

    /**
     * Mentor scope.
     * Searches: Mentorship Assignments, Sessions.
     */
    private function searchMentor(string $q, User $user): array
    {
        $results = [];

        $assignments = Assignment::where('mentor_id', $user->id)
            ->whereHas('programme', fn ($pq) => $pq->where('title', 'like', "%{$q}%"))
            ->orWhere(fn ($aq) => $aq
                ->where('mentor_id', $user->id)
                ->whereHas('mentee', fn ($mq) => $mq->where('name', 'like', "%{$q}%"))
            )
            ->limit(self::LIMIT)
            ->get();

        if ($assignments->isNotEmpty()) {
            $results['Assignments'] = $assignments->map(fn ($a) => [
                'id'       => $a->id,
                'title'    => $a->programme?->title ?? 'Assignment #' . $a->id,
                'subtitle' => $a->mentee?->name ?? '',
                'url'      => route('mentorship.assignments.show', $a->id),
                'type'     => 'Assignments',
            ])->values()->all();
        }

        $sessions = MentorshipSession::whereHas(
            'assignment',
            fn ($aq) => $aq->where('mentor_id', $user->id)
        )
            ->where('title', 'like', "%{$q}%")
            ->limit(self::LIMIT)
            ->get();

        if ($sessions->isNotEmpty()) {
            $results['Sessions'] = $sessions->map(fn ($s) => [
                'id'       => $s->id,
                'title'    => $s->title ?? 'Session #' . $s->id,
                'subtitle' => $s->status ?? '',
                'url'      => route('mentorship.sessions.show', $s->id),
                'type'     => 'Sessions',
            ])->values()->all();
        }

        return $results;
    }

    /**
     * Mentee scope.
     * Searches: Mentorship Programmes, My Sessions, Certificates.
     */
    private function searchMentee(string $q, User $user): array
    {
        $results = [];

        $programmes = Programme::where('title', 'like', "%{$q}%")
            ->where('is_active', true)
            ->limit(self::LIMIT)
            ->get();

        if ($programmes->isNotEmpty()) {
            $results['Mentorship Programmes'] = $programmes->map(fn ($p) => [
                'id'       => $p->id,
                'title'    => $p->title,
                'subtitle' => $p->is_free ? 'Free' : ($p->formatted_fee ?? ''),
                'url'      => route('mentorship.public.programme', $p->id),
                'type'     => 'Mentorship Programmes',
            ])->values()->all();
        }

        $sessions = MentorshipSession::whereHas(
            'assignment',
            fn ($aq) => $aq->where('mentee_id', $user->id)
        )
            ->where('title', 'like', "%{$q}%")
            ->limit(self::LIMIT)
            ->get();

        if ($sessions->isNotEmpty()) {
            $results['My Sessions'] = $sessions->map(fn ($s) => [
                'id'       => $s->id,
                'title'    => $s->title ?? 'Session #' . $s->id,
                'subtitle' => $s->status ?? '',
                'url'      => route('mentorship.sessions.show', $s->id),
                'type'     => 'My Sessions',
            ])->values()->all();
        }

        return $results;
    }

    /**
     * Partners scope.
     * Searches: Partner Directory, Forum Threads, Publications.
     */
    private function searchPartners(string $q): array
    {
        $results = [];

        $partners = RPartner::where('name', 'like', "%{$q}%")
            ->orWhere('description', 'like', "%{$q}%")
            ->limit(self::LIMIT)
            ->get();

        if ($partners->isNotEmpty()) {
            $results['Partners'] = $partners->map(fn ($p) => [
                'id'       => $p->id,
                'title'    => $p->name,
                'subtitle' => $p->country ?? '',
                'url'      => route('partners.show', $p->id),
                'type'     => 'Partners',
            ])->values()->all();
        }

        $threads = RForumThread::where('title', 'like', "%{$q}%")
            ->where('is_approved', true)
            ->limit(self::LIMIT)
            ->get();

        if ($threads->isNotEmpty()) {
            $results['Forum Threads'] = $threads->map(fn ($t) => [
                'id'       => $t->id,
                'title'    => $t->title,
                'subtitle' => $t->category_label ?? ucfirst($t->category),
                'url'      => route('partners.forum.show', $t->id),
                'type'     => 'Forum Threads',
            ])->values()->all();
        }

        $publications = RPublication::where('title', 'like', "%{$q}%")
            ->whereIn('status', [RPublication::STATUS_APPROVED, RPublication::STATUS_FEATURED])
            ->limit(self::LIMIT)
            ->get();

        if ($publications->isNotEmpty()) {
            $results['Publications'] = $publications->map(fn ($p) => [
                'id'       => $p->id,
                'title'    => $p->title,
                'subtitle' => $p->category_label ?? ucfirst($p->category),
                'url'      => route('research.public.show', $p->id),
                'type'     => 'Publications',
            ])->values()->all();
        }

        return $results;
    }

    /**
     * Contributor scope.
     * Searches: Discussions, Knowledge Base Questions.
     */
    private function searchContributor(string $q): array
    {
        $results = [];

        $discussions = Discussion::where('title', 'like', "%{$q}%")
            ->where('is_active', true)
            ->limit(self::LIMIT)
            ->get();

        if ($discussions->isNotEmpty()) {
            $results['Discussions'] = $discussions->map(fn ($d) => [
                'id'       => $d->id,
                'title'    => $d->title,
                'subtitle' => ucfirst($d->status),
                'url'      => route('public.discussions.show', $d->slug),
                'type'     => 'Discussions',
            ])->values()->all();
        }

        $questions = KnowledgeBaseQuestion::where('title', 'like', "%{$q}%")
            ->where('is_published', true)
            ->limit(self::LIMIT)
            ->get();

        if ($questions->isNotEmpty()) {
            $results['Knowledge Base'] = $questions->map(fn ($kb) => [
                'id'       => $kb->id,
                'title'    => $kb->title,
                'subtitle' => ucfirst($kb->difficulty),
                'url'      => route('public.knowledge-base.show', $kb->slug),
                'type'     => 'Knowledge Base',
            ])->values()->all();
        }

        return $results;
    }

    /**
     * Health Marketor scope.
     * Searches: Health Institutions, Campaigns, Health Stories.
     */
    private function searchHealthMarketor(string $q, User $user): array
    {
        $results = [];

        $institutions = HealthInstitution::where('user_id', $user->id)
            ->where(fn ($iq) => $iq
                ->where('name', 'like', "%{$q}%")
                ->orWhere('city', 'like', "%{$q}%")
            )
            ->limit(self::LIMIT)
            ->get();

        if ($institutions->isNotEmpty()) {
            $results['Health Institutions'] = $institutions->map(fn ($i) => [
                'id'       => $i->id,
                'title'    => $i->name,
                'subtitle' => $i->city . ', ' . $i->country,
                'url'      => route('health-directory.institutions.show', $i->id),
                'type'     => 'Health Institutions',
            ])->values()->all();
        }

        $campaigns = RCampaign::where('title', 'like', "%{$q}%")
            ->where('status', RCampaign::STATUS_ACTIVE)
            ->limit(self::LIMIT)
            ->get();

        if ($campaigns->isNotEmpty()) {
            $results['Campaigns'] = $campaigns->map(fn ($c) => [
                'id'       => $c->id,
                'title'    => $c->title,
                'subtitle' => $c->status_label ?? ucfirst($c->status),
                'url'      => route('advocacy.campaigns.show', $c->id),
                'type'     => 'Campaigns',
            ])->values()->all();
        }

        $stories = RHealthStory::where('title', 'like', "%{$q}%")
            ->where('user_id', $user->id)
            ->limit(self::LIMIT)
            ->get();

        if ($stories->isNotEmpty()) {
            $results['Health Stories'] = $stories->map(fn ($s) => [
                'id'       => $s->id,
                'title'    => $s->title,
                'subtitle' => ucfirst($s->status ?? ''),
                'url'      => route('advocacy.stories.show', $s->id),
                'type'     => 'Health Stories',
            ])->values()->all();
        }

        return $results;
    }
}
