<?php

namespace App\Livewire\HR;

use App\Domain\Attendance\Enums\AttendanceStatus;
use App\Domain\Attendance\Models\AttendanceRecord;
use App\Domain\HR\Models\Trainer;
use App\Domain\HR\Services\TrainerService;
use App\Domain\Scheduling\Models\Assignment;
use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Training\Models\TrainingGroup;
use App\Domain\Training\Models\TrainingSession;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('ملف المدرب')]
class TrainerShow extends Component
{
    public Trainer $trainer;
    public string $activeTab = 'overview';
    public ?int $assignGroupId = null;

    // Delete confirmation
    public bool $showDeleteModal = false;
    public string $deleteConfirmation = '';

    public function mount(Trainer $trainer): void
    {
        $this->authorize('trainers.list');
        $this->trainer = $trainer->load([
            'employee.person',
            'employee.branch',
            'person',
            'qualifications',
            'availabilities',
            'compensations',
        ]);
    }

    public function assignGroup(): void
    {
        $this->authorize('trainers.update');

        $trainerUserId = $this->trainer->employee?->user_id;
        if (!$this->assignGroupId || !$trainerUserId) {
            return;
        }

        $exists = Assignment::where('assignable_type', TrainingGroup::class)
            ->where('assignable_id', $this->assignGroupId)
            ->where('user_id', $trainerUserId)
            ->where('status', 'active')
            ->exists();

        if ($exists) {
            session()->flash('error', __('هذا المدرب مُعيَّن بالفعل لهذه المجموعة'));
            return;
        }

        // Branch-scoped: a group id from another branch resolves to null here,
        // so the assignment is simply not made.
        $group = TrainingGroup::find($this->assignGroupId);
        if (!$group) {
            return;
        }

        Assignment::create([
            'academy_id' => $group->academy_id,
            // The assignment belongs where the group is. Left to the creating
            // stamp it would take the operator's branch, which in all-branches
            // mode is their pivot branch or nothing at all.
            'branch_id' => $group->branch_id,
            'user_id' => $trainerUserId,
            'assignable_type' => TrainingGroup::class,
            'assignable_id' => $this->assignGroupId,
            'role_label' => 'مدرب',
            'scope' => 'full',
            'status' => 'active',
            'is_primary' => false,
            'start_date' => now()->toDateString(),
            'created_by' => auth()->id(),
        ]);

        $this->assignGroupId = null;
        session()->flash('success', __('تم تعيين المجموعة بنجاح'));
    }

    public function removeGroupAssignment(int $assignmentId): void
    {
        $this->authorize('trainers.update');

        Assignment::where('id', $assignmentId)
            ->where('user_id', $this->trainer->employee?->user_id)
            ->update(['status' => 'cancelled']);

        session()->flash('success', __('تم إلغاء تعيين المجموعة'));
    }

    public function openDeleteModal(): void
    {
        $this->authorize('trainers.delete');
        $this->deleteConfirmation = '';
        $this->showDeleteModal = true;
    }

    public function closeDeleteModal(): void
    {
        $this->showDeleteModal = false;
        $this->deleteConfirmation = '';
    }

    public function confirmDelete(TrainerService $service): void
    {
        $this->authorize('trainers.delete');

        $person = $this->trainer->employee?->person ?? $this->trainer->person;
        $expectedName = $person?->name_ar ?? '';

        $normalize = fn (string $s) => trim(preg_replace('/\s+/u', ' ',
            str_replace(['ي', 'ة', 'أ', 'إ', 'آ'], ['ى', 'ه', 'ا', 'ا', 'ا'], $s)
        ));

        if ($normalize($this->deleteConfirmation) !== $normalize($expectedName)) {
            $this->addError('deleteConfirmation', __('الاسم المدخل لا يتطابق مع اسم المدرب'));
            return;
        }

        try {
            $service->delete($this->trainer, auth()->user());
            session()->flash('success', __('تم حذف المدرب وأرشفة بياناته بنجاح'));
            $this->redirect(route('trainers.list'), navigate: true);
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
            $this->showDeleteModal = false;
        } catch (\Throwable $e) {
            session()->flash('error', __('حدث خطأ أثناء الحذف'));
            $this->showDeleteModal = false;
        }
    }

    public function render()
    {
        $person = $this->trainer->employee?->person ?? $this->trainer->person;
        $trainerUserId = $this->trainer->employee?->user_id;

        // Everything below reads through models that carry BranchScope —
        // Assignment, TrainingGroup, TrainingSession, AttendanceRecord,
        // TrainerCompensation, TrainerAdvance — so a coach who works two
        // branches shows this branch's groups, sessions and figures only.
        // Groups where this trainer is head trainer OR assigned via assignments
        $assignedGroupIds = Assignment::where('user_id', $trainerUserId)
            ->where('assignable_type', TrainingGroup::class)
            ->where('status', 'active')
            ->pluck('assignable_id')
            ->toArray();

        $groups = TrainingGroup::where(function ($q) use ($trainerUserId, $assignedGroupIds) {
                $q->where('head_trainer_id', $trainerUserId)
                  ->orWhereIn('id', $assignedGroupIds);
            })
            ->with(['program', 'schedules', 'branch'])
            ->withCount(['enrollments as active_enrollments_count' => function ($q) {
                $q->where('status', 'active');
            }])
            ->get();

        // Assignments for this trainer (for UI remove buttons)
        $trainerAssignments = Assignment::where('user_id', $trainerUserId)
            ->where('assignable_type', TrainingGroup::class)
            ->where('status', 'active')
            ->get()
            ->keyBy('assignable_id');

        // Available groups not yet assigned
        $availableGroups = TrainingGroup::whereNotIn('id', array_merge(
                $assignedGroupIds,
                TrainingGroup::where('head_trainer_id', $trainerUserId)->pluck('id')->toArray()
            ))
            ->whereIn('status', ['active', 'forming'])
            ->with('program')
            ->orderBy('name_ar')
            ->get(['id', 'name_ar', 'name', 'training_program_id']);

        // Upcoming sessions (next 7 days)
        $upcomingSessions = TrainingSession::whereHas('group', function ($q) use ($trainerUserId) {
                $q->where('head_trainer_id', $trainerUserId);
            })
            ->where('session_date', '>=', now()->toDateString())
            ->where('session_date', '<=', now()->addDays(7)->toDateString())
            ->with(['group'])
            ->orderBy('session_date')
            ->orderBy('start_time')
            ->limit(20)
            ->get();

        // Attendance stats for this trainer (records stored as User::class)
        $attendanceQuery = AttendanceRecord::where('subject_type', \App\Models\User::class)
            ->where('subject_id', $trainerUserId);

        $totalSessionsAttended = (clone $attendanceQuery)->count();
        $presentCount = (clone $attendanceQuery)->where('status', AttendanceStatus::Present)->count();
        $lateCount = (clone $attendanceQuery)->where('status', AttendanceStatus::Late)->count();
        $absentCount = (clone $attendanceQuery)->whereIn('status', [AttendanceStatus::Absent, AttendanceStatus::NoShow])->count();
        $cancelledExempt = (clone $attendanceQuery)->whereIn('status', [AttendanceStatus::Cancelled, AttendanceStatus::Exempt])->count();

        $attendanceDenominator = $totalSessionsAttended - $cancelledExempt;
        $attendanceRate = $attendanceDenominator > 0
            ? round(($presentCount + $lateCount) / $attendanceDenominator * 100, 1)
            : 0;

        // Total participants across all groups
        $totalParticipants = $groups->sum('active_enrollments_count');

        // Capacity utilization
        $totalCapacity = $groups->sum('max_capacity');
        $capacityRate = $totalCapacity > 0
            ? round($totalParticipants / $totalCapacity * 100, 1)
            : 0;

        // Recent compensations
        $recentCompensations = $this->trainer->compensations()
            ->orderByDesc('date')
            ->limit(6)
            ->get();

        // Monthly earnings (current month)
        $monthlyEarnings = $this->trainer->compensations()
            ->where('date', '>=', now()->startOfMonth())
            ->where('date', '<=', now()->endOfMonth())
            ->sum('amount');

        // Advances balance
        $pendingAdvances = $this->trainer->advances()
            ->where('status', 'active')
            ->sum('remaining_balance');

        return view('livewire.hr.trainer-show', [
            'person' => $person,
            'groups' => $groups,
            'upcomingSessions' => $upcomingSessions,
            'totalSessionsAttended' => $totalSessionsAttended,
            'presentCount' => $presentCount,
            'lateCount' => $lateCount,
            'absentCount' => $absentCount,
            'attendanceRate' => $attendanceRate,
            'totalParticipants' => $totalParticipants,
            'capacityRate' => $capacityRate,
            'recentCompensations' => $recentCompensations,
            'monthlyEarnings' => $monthlyEarnings,
            'pendingAdvances' => $pendingAdvances,
            'trainerAssignments' => $trainerAssignments,
            'availableGroups' => $availableGroups,
        ]);
    }
}
