<?php

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

return new class extends Migration
{
    public function up(): void
    {
        // Change column type to text/longer string temporarily (nullable) to allow backfill without truncation
        $driver = DB::connection()->getDriverName();
        if ($driver === 'pgsql') {
            DB::statement('ALTER TABLE person ALTER COLUMN nu DROP NOT NULL');
            DB::statement('ALTER TABLE person ALTER COLUMN nu TYPE TEXT USING nu::text');
        } elseif ($driver === 'mysql') {
            DB::statement('ALTER TABLE person MODIFY nu VARCHAR(32) NULL');
        } else {
            // Fallback: try schema change (may require doctrine/dbal)
            Schema::table('person', function (Blueprint $table) {
                $table->string('nu', 32)->nullable()->change();
            });
        }

        // Backfill unique 6-char alphanumeric 'nu' values
        $rows = DB::table('person')->select('id', 'nu')->orderBy('id')->get();
        $used = [];
        foreach ($rows as $row) {
            if (is_string($row->nu) && preg_match('/^[A-Za-z0-9]{6}$/', $row->nu)) {
                if (! isset($used[$row->nu])) {
                    $used[$row->nu] = true;

                    continue;
                }
                // duplicate will be regenerated below
            }
            // mark to regenerate
            $used[$row->nu] = false;
        }

        $updates = [];
        foreach ($rows as $row) {
            $needsNew = true;
            if (is_string($row->nu) && preg_match('/^[A-Za-z0-9]{6}$/', $row->nu) && ($used[$row->nu] === true)) {
                // valid and unique
                $needsNew = false;
            }
            if ($needsNew) {
                do {
                    $nu = Str::random(6); // [A-Za-z0-9]
                } while (isset($used[$nu]));
                $used[$nu] = true;
                $updates[] = ['id' => $row->id, 'nu' => $nu];
            }
        }

        // Apply updates in chunks
        foreach (array_chunk($updates, 500) as $chunk) {
            foreach ($chunk as $u) {
                DB::table('person')->where('id', $u['id'])->update(['nu' => $u['nu']]);
            }
        }

        // Add unique index and then narrow type to VARCHAR(6) and make not nullable
        Schema::table('person', function (Blueprint $table) {
            $table->unique('nu');
        });
        if ($driver === 'pgsql') {
            DB::statement('ALTER TABLE person ALTER COLUMN nu TYPE VARCHAR(6) USING nu::varchar(6)');
            DB::statement('ALTER TABLE person ALTER COLUMN nu SET NOT NULL');
        } elseif ($driver === 'mysql') {
            DB::statement('ALTER TABLE person MODIFY nu VARCHAR(6) NOT NULL');
        } else {
            Schema::table('person', function (Blueprint $table) {
                $table->string('nu', 6)->nullable(false)->change();
            });
        }
    }

    public function down(): void
    {
        // Drop unique and revert to integer (best-effort)
        Schema::table('person', function (Blueprint $table) {
            $table->dropUnique(['nu']);
        });
        $driver = DB::connection()->getDriverName();
        // Coerce values back to numeric to avoid issues on some DBs
        DB::table('person')->update(['nu' => '0']);
        if ($driver === 'pgsql') {
            DB::statement('ALTER TABLE person ALTER COLUMN nu TYPE BIGINT USING nu::bigint');
            DB::statement('ALTER TABLE person ALTER COLUMN nu SET DEFAULT 0');
            DB::statement('ALTER TABLE person ALTER COLUMN nu SET NOT NULL');
        } elseif ($driver === 'mysql') {
            DB::statement('ALTER TABLE person MODIFY nu BIGINT UNSIGNED NOT NULL DEFAULT 0');
        } else {
            Schema::table('person', function (Blueprint $table) {
                $table->unsignedBigInteger('nu')->default(0)->change();
            });
        }
    }
};
