<?php

namespace App\Livewire\Attendance;

use App\Domain\Attendance\Enums\AttendanceStatus;
use App\Domain\Attendance\Models\AttendanceRecord;
use App\Domain\Attendance\Services\AttendanceGenerationService;
use App\Domain\Attendance\Services\AttendanceMarkingService;
use App\Domain\Financial\Enums\InvoiceStatus;
use App\Domain\Financial\Models\Invoice;
use App\Domain\Participant\Models\Participant;
use App\Domain\Training\Models\Enrollment;
use App\Domain\Training\Models\TrainingSession;
use App\Models\User;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('تسجيل الحضور')]
class TakeAttendance extends Component
{
    public TrainingSession $session;

    public string $sessionNotes = '';

    /** @var array<int, string> Per-record notes keyed by record id */
    public array $recordNotes = [];

    public function mount(TrainingSession $session, AttendanceGenerationService $generationService): void
    {
        $this->authorize('attendance.mark');
        $this->session = $session->load(['group']);
        $this->sessionNotes = $this->session->notes ?? '';

        $hasRecords = AttendanceRecord::where('training_session_id', $this->session->id)->exists();
        if (!$hasRecords) {
            $generationService->generateForSession($this->session);
        }
    }

    public function saveNotes(): void
    {
        $this->session->update(['notes' => $this->sessionNotes]);
        session()->flash('notes_saved', __('تم حفظ ملاحظات الجلسة'));
    }

    public function saveRecordNote(int $recordId): void
    {
        $record = AttendanceRecord::findOrFail($recordId);
        $note = $this->recordNotes[$recordId] ?? '';
        $record->update(['notes' => $note]);
        session()->flash("record_note_saved_{$recordId}", __('تم حفظ الملاحظة'));
    }

    public function markAs(int $recordId, string $status, AttendanceMarkingService $service): void
    {
        $record = AttendanceRecord::findOrFail($recordId);

        if (!$this->canMarkRecord($record)) {
            return;
        }

        $statusEnum = AttendanceStatus::from($status);
        $service->markStatus($record, $statusEnum, auth()->user());
    }

    public function markPresent(int $recordId, AttendanceMarkingService $service): void
    {
        $record = AttendanceRecord::findOrFail($recordId);

        if (!$this->canMarkRecord($record)) {
            return;
        }

        $service->markPresent($record, auth()->user());
    }

    public function markAllPresent(AttendanceMarkingService $service): void
    {
        $records = AttendanceRecord::where('training_session_id', $this->session->id)
            ->where('status', AttendanceStatus::Expected)
            ->get();

        foreach ($records as $record) {
            if ($this->canMarkRecord($record)) {
                $service->markPresent($record, auth()->user());
            }
        }
    }

    private function canMarkRecord(AttendanceRecord $record): bool
    {
        $user = auth()->user();

        if ($record->subject_type === Participant::class) {
            return true;
        }

        if ($record->subject_type === User::class) {
            if ($this->canManageTrainers()) {
                return true;
            }
            return $record->subject_id === $user->id;
        }

        return true;
    }

    private function canManageTrainers(): bool
    {
        $user = auth()->user();

        if ($user->is_super_admin) {
            return true;
        }

        $roleLevel = $user->roles->max('level') ?? 0;

        return $roleLevel >= 60;
    }

    public function render()
    {
        $records = AttendanceRecord::where('training_session_id', $this->session->id)
            ->with('subject')
            ->orderBy('subject_type')
            ->orderBy('status')
            ->get();

        // Split into trainers and participants
        $trainerRecords = $records->where('subject_type', User::class)->values();
        $participantRecords = $records->where('subject_type', Participant::class)->values();

        // Populate per-record notes from DB (only on first load or if not yet set)
        foreach ($records as $record) {
            if (!array_key_exists($record->id, $this->recordNotes)) {
                $this->recordNotes[$record->id] = $record->notes ?? '';
            }
        }

        // Detect unpaid/unrenewed participants for red highlight
        $participantIds = $participantRecords
            ->pluck('subject_id')
            ->unique()
            ->toArray();

        $notPaidParticipantIds = [];
        if ($participantIds) {
            $unpaidInvoiceIds = Invoice::where('billable_type', Participant::class)
                ->whereIn('billable_id', $participantIds)
                ->whereIn('status', [InvoiceStatus::Sent, InvoiceStatus::Overdue, InvoiceStatus::PartiallyPaid])
                ->where('due_amount', '>', 0)
                ->whereNull('deleted_at')
                ->pluck('billable_id')
                ->unique()
                ->toArray();

            $overdueEnrollmentIds = Enrollment::whereIn('participant_id', $participantIds)
                ->where('status', 'active')
                ->where('training_group_id', $this->session->training_group_id)
                ->whereNotNull('next_billing_date')
                ->where('next_billing_date', '<', now()->toDateString())
                ->pluck('participant_id')
                ->unique()
                ->toArray();

            $notPaidParticipantIds = array_unique(array_merge($unpaidInvoiceIds, $overdueEnrollmentIds));
        }

        $summary = [
            'total' => $records->count(),
            'present' => $records->where('status', AttendanceStatus::Present)->count(),
            'late' => $records->where('status', AttendanceStatus::Late)->count(),
            'absent' => $records->where('status', AttendanceStatus::Absent)->count(),
            'expected' => $records->where('status', AttendanceStatus::Expected)->count(),
            'excused' => $records->where('status', AttendanceStatus::Excused)->count(),
        ];

        $canManageTrainers = $this->canManageTrainers();

        return view('livewire.attendance.take-attendance', [
            'trainerRecords' => $trainerRecords,
            'participantRecords' => $participantRecords,
            'records' => $records,
            'summary' => $summary,
            'statuses' => AttendanceStatus::cases(),
            'notPaidParticipantIds' => $notPaidParticipantIds,
            'canManageTrainers' => $canManageTrainers,
            'currentUserId' => auth()->id(),
        ]);
    }
}
