<?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 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);
        $statusEnum = AttendanceStatus::from($status);
        $service->markStatus($record, $statusEnum, auth()->user());
    }

    public function markPresent(int $recordId, AttendanceMarkingService $service): void
    {
        $record = AttendanceRecord::findOrFail($recordId);
        $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) {
            $service->markPresent($record, auth()->user());
        }
    }

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

        // 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 = $records
            ->where('subject_type', Participant::class)
            ->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(),
        ];

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