<?php

namespace App\Http\Middleware;

use App\Models\Configuration;
use App\Services\SchoolYears\SchoolYearWriteGuard;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use RuntimeException;
use Symfony\Component\HttpFoundation\Response;

class EnsureSchoolYearEditable
{
    public function __construct(private SchoolYearWriteGuard $guard)
    {
    }

    public function handle(Request $request, Closure $next): Response
    {
        if (!in_array(strtoupper($request->method()), ['POST', 'PUT', 'PATCH', 'DELETE'], true)) {
            return $next($request);
        }

        try {
            $this->guard->assertEditable($this->resolveSchoolYears($request));
        } catch (RuntimeException $e) {
            return response()->json([
                'ok' => false,
                'message' => $e->getMessage(),
            ], 409);
        }

        return $next($request);
    }

    private function resolveSchoolYears(Request $request): array
    {
        $years = [];

        foreach (['school_year', 'current_school_year'] as $field) {
            $value = $request->input($field, $request->query($field));
            if (is_string($value) && trim($value) !== '') {
                $years[] = trim($value);
            }
        }

        $routeYears = [
            ['param' => 'invoiceId', 'table' => 'invoices', 'column' => 'school_year'],
            ['param' => 'invoice', 'table' => 'invoices', 'column' => 'school_year'],
            ['param' => 'paymentId', 'table' => 'payments', 'column' => 'school_year'],
            ['param' => 'payment', 'table' => 'payments', 'column' => 'school_year'],
            ['param' => 'refundId', 'table' => 'refunds', 'column' => 'school_year'],
            ['param' => 'refund', 'table' => 'refunds', 'column' => 'school_year'],
            ['param' => 'promotionId', 'table' => 'student_promotion_records', 'column' => 'current_school_year'],
            ['param' => 'promotion', 'table' => 'student_promotion_records', 'column' => 'current_school_year'],
            ['param' => 'eventCharge', 'table' => 'event_charges', 'column' => 'school_year'],
            ['param' => 'eventId', 'table' => 'events', 'column' => 'school_year'],
            ['param' => 'classSection', 'table' => 'classSection', 'column' => 'school_year'],
            ['param' => 'classSectionId', 'table' => 'classSection', 'column' => 'school_year'],
        ];

        foreach ($routeYears as $mapping) {
            $value = $request->route($mapping['param']);
            if ($value === null || $value === '') {
                continue;
            }

            $resolved = $this->lookupYear((string) $value, $mapping['table'], $mapping['column']);
            if ($resolved !== null) {
                $years[] = $resolved;
            }
        }

        if ($years === []) {
            $current = trim((string) (Configuration::getConfig('school_year') ?? ''));
            if ($current !== '') {
                $years[] = $current;
            }
        }

        return $years;
    }

    private function lookupYear(string $id, string $table, string $column): ?string
    {
        if (!ctype_digit($id) || !DB::getSchemaBuilder()->hasTable($table)) {
            return null;
        }

        $primaryKey = match ($table) {
            'classSection' => 'class_section_id',
            'student_promotion_records' => 'promotion_id',
            default => 'id',
        };

        $value = DB::table($table)->where($primaryKey, (int) $id)->value($column);

        return is_string($value) && trim($value) !== '' ? trim($value) : null;
    }
}
