<?php

namespace App\Console\Commands;

use App\Domain\Attendance\Models\AttendanceRecord;
use App\Domain\Training\Models\Enrollment;
use App\Domain\Training\Models\TrainingSession;
use Illuminate\Console\Command;

/**
 * Give every scheduled session the "expected" rows its register needs.
 *
 * Runs at 02:30, half an hour after `sessions:generate-upcoming`, so it is the
 * command that turns last night's generated sessions into a markable register.
 *
 * Branch matters here even though console runs with enforcement off
 * (docs/agent-rules/19): `attendance_records` is strictly branch-scoped, so a
 * record written with a null `branch_id` belongs to no branch and never appears
 * on the attendance screen of any of them — the coach simply cannot mark that
 * player. Nothing stamps it for us either, because BelongsToBranch resolves the
 * active branch from the request and a cron has none. So it is written
 * explicitly, from the session, falling back to the session's group.
 */
class BackfillAttendanceRecords extends Command
{
    protected $signature = 'attendance:backfill {--group= : Specific group ID to backfill}';
    protected $description = 'Generate missing attendance records for all active enrollments and scheduled sessions';

    public function handle(): int
    {
        $groupFilter = $this->option('group');

        $query = TrainingSession::query()
            ->whereIn('status', ['scheduled', 'in_progress'])
            ->with('group');

        if ($groupFilter) {
            $query->where('training_group_id', $groupFilter);
        }

        $sessions = $query->get();
        $inserted = 0;
        $unattributed = 0;
        $subjectType = \App\Domain\Participant\Models\Participant::class;

        foreach ($sessions as $session) {
            // The session owns the branch; the group is the fallback for a
            // session generated by a job that could not stamp one.
            $branchId = $session->branch_id ?? $session->group?->branch_id;

            $enrollments = Enrollment::where('training_group_id', $session->training_group_id)
                ->where('status', 'active')
                ->where('enrollment_date', '<=', $session->session_date)
                ->get();

            foreach ($enrollments as $enrollment) {
                $exists = AttendanceRecord::where('training_session_id', $session->id)
                    ->where('subject_type', $subjectType)
                    ->where('subject_id', $enrollment->participant_id)
                    ->exists();

                if (!$exists) {
                    AttendanceRecord::create([
                        'academy_id' => $session->academy_id,
                        'branch_id' => $branchId ?? $enrollment->branch_id,
                        'training_session_id' => $session->id,
                        'subject_type' => $subjectType,
                        'subject_id' => $enrollment->participant_id,
                        'status' => 'expected',
                        'is_auto_generated' => true,
                    ]);
                    $inserted++;

                    if (!($branchId ?? $enrollment->branch_id)) {
                        $unattributed++;
                    }
                }
            }
        }

        if ($inserted > 0) {
            $this->info("Backfilled {$inserted} missing attendance records.");
        } else {
            $this->info("No missing attendance records found.");
        }

        if ($unattributed > 0) {
            // Loud, because these are the records a coach will never see: the
            // session, its group and the enrolment all lack a branch.
            $this->warn("{$unattributed} record(s) could not be attributed to a branch and will not show on any attendance screen.");
        }

        return self::SUCCESS;
    }
}
