<?php

use Carbon\CarbonImmutable;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        if (Schema::hasTable('attendance_management_events')) {
            Schema::table('attendance_management_events', function (Blueprint $table) {
                if (! Schema::hasColumn('attendance_management_events', 'school_year')) {
                    $table->string('school_year', 20)->nullable()->after('event_date')->index();
                }
                if (! Schema::hasColumn('attendance_management_events', 'semester')) {
                    $table->string('semester', 20)->nullable()->after('school_year')->index();
                }
            });

            DB::table('attendance_management_events')
                ->select('id', 'event_date', 'school_year', 'semester')
                ->orderBy('id')
                ->chunkById(200, function ($rows): void {
                    foreach ($rows as $row) {
                        $schoolYear = trim((string) ($row->school_year ?? ''));
                        $semester = trim((string) ($row->semester ?? ''));
                        if ($schoolYear !== '' && $semester !== '') {
                            continue;
                        }

                        $date = CarbonImmutable::parse((string) $row->event_date);
                        DB::table('attendance_management_events')
                            ->where('id', $row->id)
                            ->update([
                                'school_year' => $schoolYear !== '' ? $schoolYear : $this->deriveSchoolYearForDate($date),
                                'semester' => $semester !== '' ? $semester : $this->deriveSemesterForDate($date),
                            ]);
                    }
                });
        }

        if (Schema::hasTable('badge_exceptions')) {
            Schema::table('badge_exceptions', function (Blueprint $table) {
                if (! Schema::hasColumn('badge_exceptions', 'school_year')) {
                    $table->string('school_year', 20)->nullable()->after('exception_date')->index();
                }
                if (! Schema::hasColumn('badge_exceptions', 'semester')) {
                    $table->string('semester', 20)->nullable()->after('school_year')->index();
                }
            });

            DB::table('badge_exceptions')
                ->select('id', 'exception_date', 'school_year', 'semester')
                ->orderBy('id')
                ->chunkById(200, function ($rows): void {
                    foreach ($rows as $row) {
                        $schoolYear = trim((string) ($row->school_year ?? ''));
                        $semester = trim((string) ($row->semester ?? ''));
                        if ($schoolYear !== '' && $semester !== '') {
                            continue;
                        }

                        $date = CarbonImmutable::parse((string) $row->exception_date);
                        DB::table('badge_exceptions')
                            ->where('id', $row->id)
                            ->update([
                                'school_year' => $schoolYear !== '' ? $schoolYear : $this->deriveSchoolYearForDate($date),
                                'semester' => $semester !== '' ? $semester : $this->deriveSemesterForDate($date),
                            ]);
                    }
                });
        }

        if (Schema::hasTable('late_slip_reprints')) {
            Schema::table('late_slip_reprints', function (Blueprint $table) {
                if (! Schema::hasColumn('late_slip_reprints', 'school_year')) {
                    $table->string('school_year', 20)->nullable()->after('reprinted_at')->index();
                }
                if (! Schema::hasColumn('late_slip_reprints', 'semester')) {
                    $table->string('semester', 20)->nullable()->after('school_year')->index();
                }
            });

            DB::table('late_slip_reprints')
                ->leftJoin('attendance_management_events as ame', 'ame.id', '=', 'late_slip_reprints.attendance_management_event_id')
                ->select(
                    'late_slip_reprints.id',
                    'late_slip_reprints.reprinted_at',
                    'late_slip_reprints.school_year',
                    'late_slip_reprints.semester',
                    'ame.school_year as event_school_year',
                    'ame.semester as event_semester',
                )
                ->orderBy('late_slip_reprints.id')
                ->chunkById(200, function ($rows): void {
                    foreach ($rows as $row) {
                        $schoolYear = trim((string) ($row->school_year ?? ''));
                        $semester = trim((string) ($row->semester ?? ''));
                        if ($schoolYear !== '' && $semester !== '') {
                            continue;
                        }

                        $date = CarbonImmutable::parse((string) $row->reprinted_at);
                        DB::table('late_slip_reprints')
                            ->where('id', $row->id)
                            ->update([
                                'school_year' => $schoolYear !== '' ? $schoolYear : (trim((string) ($row->event_school_year ?? '')) ?: $this->deriveSchoolYearForDate($date)),
                                'semester' => $semester !== '' ? $semester : (trim((string) ($row->event_semester ?? '')) ?: $this->deriveSemesterForDate($date)),
                            ]);
                    }
                }, 'late_slip_reprints.id', 'id');
        }
    }

    public function down(): void
    {
        if (Schema::hasTable('late_slip_reprints')) {
            Schema::table('late_slip_reprints', function (Blueprint $table) {
                if (Schema::hasColumn('late_slip_reprints', 'semester')) {
                    $table->dropColumn('semester');
                }
                if (Schema::hasColumn('late_slip_reprints', 'school_year')) {
                    $table->dropColumn('school_year');
                }
            });
        }

        if (Schema::hasTable('badge_exceptions')) {
            Schema::table('badge_exceptions', function (Blueprint $table) {
                if (Schema::hasColumn('badge_exceptions', 'semester')) {
                    $table->dropColumn('semester');
                }
                if (Schema::hasColumn('badge_exceptions', 'school_year')) {
                    $table->dropColumn('school_year');
                }
            });
        }

        if (Schema::hasTable('attendance_management_events')) {
            Schema::table('attendance_management_events', function (Blueprint $table) {
                if (Schema::hasColumn('attendance_management_events', 'semester')) {
                    $table->dropColumn('semester');
                }
                if (Schema::hasColumn('attendance_management_events', 'school_year')) {
                    $table->dropColumn('school_year');
                }
            });
        }
    }

    private function deriveSchoolYearForDate(CarbonImmutable $date): string
    {
        $startYear = $date->month >= 8 ? $date->year : ($date->year - 1);

        return sprintf('%d-%d', $startYear, $startYear + 1);
    }

    private function deriveSemesterForDate(CarbonImmutable $date): string
    {
        return ($date->month >= 8 || $date->month === 1) ? 'Fall' : 'Spring';
    }
};
