<?php

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

return new class extends Migration
{
    public function up(): void
    {
        Schema::table('admin_users', function (Blueprint $table) {
            $table->string('username', 64)->nullable()->after('id');
        });

        $this->backfillUsernames();

        Schema::table('admin_users', function (Blueprint $table) {
            $table->string('username', 64)->nullable(false)->change();
            $table->unique('username');
        });

        Schema::table('admin_users', function (Blueprint $table) {
            $table->dropUnique(['email']);
        });

        Schema::table('admin_users', function (Blueprint $table) {
            $table->string('email')->nullable()->change();
        });
    }

    public function down(): void
    {
        Schema::table('admin_users', function (Blueprint $table) {
            $table->dropUnique(['username']);
        });

        Schema::table('admin_users', function (Blueprint $table) {
            $table->dropColumn('username');
        });

        Schema::table('admin_users', function (Blueprint $table) {
            $table->string('email')->nullable(false)->change();
        });

        Schema::table('admin_users', function (Blueprint $table) {
            $table->unique('email');
        });
    }

    private function backfillUsernames(): void
    {
        $reserved = [];

        foreach (DB::table('admin_users')->orderBy('id')->cursor() as $row) {
            $email = (string) $row->email;
            $local = Str::lower(Str::before($email, '@'));
            $slug = preg_replace('/[^a-z0-9._-]/', '', $local);
            $base = Str::substr($slug !== '' ? $slug : 'admin'.(string) $row->id, 0, 50);
            if ($base === '') {
                $base = 'admin'.(string) $row->id;
            }

            $candidate = $base;
            $n = 0;
            while (in_array($candidate, $reserved, true)
                || DB::table('admin_users')->where('username', $candidate)->where('id', '!=', $row->id)->exists()) {
                $n++;
                $suffix = '_'.$n;
                $candidate = Str::substr($base, 0, 64 - strlen($suffix)).$suffix;
            }

            $reserved[] = $candidate;

            DB::table('admin_users')->where('id', $row->id)->update(['username' => $candidate]);
        }
    }
};
