<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        if (! Schema::hasTable('loan_repayment_schedules') || ! Schema::hasColumn('loan_repayment_schedules', 'fee_due')) {
            return;
        }

        $hasUpdatedAt = Schema::hasColumn('loan_repayment_schedules', 'updated_at');

        DB::table('loan_repayment_schedules')
            ->where('fee_due', '<>', 0)
            ->orderBy('id')
            ->chunkById(100, function ($schedules) use ($hasUpdatedAt): void {
                foreach ($schedules as $schedule) {
                    $newTotal = round((float) $schedule->principal_due + (float) $schedule->interest_due + (float) $schedule->penalty_due, 2);
                    $newPaid = min((float) $schedule->paid_amount, $newTotal);
                    $status = $schedule->status;

                    if ($newTotal <= 0 || $newPaid >= $newTotal) {
                        $status = 'paid';
                    } elseif ($newPaid > 0) {
                        $status = 'partial';
                    } elseif ($status === 'paid') {
                        $status = 'pending';
                    }

                    $updates = [
                        'fee_due' => 0,
                        'total_due' => $newTotal,
                        'paid_amount' => round($newPaid, 2),
                        'status' => $status,
                    ];

                    if ($hasUpdatedAt) {
                        $updates['updated_at'] = now();
                    }

                    DB::table('loan_repayment_schedules')
                        ->where('id', $schedule->id)
                        ->update($updates);
                }
            });

        if (! Schema::hasTable('loans')) {
            return;
        }

        $hasCurrentColumn = Schema::hasColumn('loan_repayment_schedules', 'is_current');
        $hasLoanUpdatedAt = Schema::hasColumn('loans', 'updated_at');

        DB::table('loans')
            ->orderBy('id')
            ->chunkById(100, function ($loans) use ($hasCurrentColumn, $hasLoanUpdatedAt): void {
                foreach ($loans as $loan) {
                    $scheduleQuery = DB::table('loan_repayment_schedules')
                        ->where('loan_id', $loan->id);

                    if ($hasCurrentColumn) {
                        $scheduleQuery->where('is_current', true);
                    }

                    $schedules = $scheduleQuery->get();

                    if ($schedules->isEmpty()) {
                        continue;
                    }

                    $scheduleTotal = round((float) $schedules->sum('total_due'), 2);
                    $balance = round((float) $schedules->sum(fn ($schedule) => max(0, (float) $schedule->total_due - (float) $schedule->paid_amount)), 2);
                    $updates = [
                        'balance' => $balance,
                        'total_payable' => round($scheduleTotal + (float) ($loan->processing_fee ?? 0), 2),
                    ];

                    if ($balance <= 0 && in_array($loan->status, ['active', 'disbursed'], true)) {
                        $updates['status'] = 'completed';
                    }

                    if ($hasLoanUpdatedAt) {
                        $updates['updated_at'] = now();
                    }

                    DB::table('loans')
                        ->where('id', $loan->id)
                        ->update($updates);
                }
            });
    }

    public function down(): void
    {
        //
    }
};
