<?php

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
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        $normalizedDomains = [];
        $duplicateTenantIdsByDomain = [];

        $tenants = DB::table('tenants')
            ->select(['id', 'dominio'])
            ->orderBy('id')
            ->get();

        foreach ($tenants as $tenant) {
            $normalizedDomain = $this->normalizeDomain($tenant->dominio, $tenant->id);

            if ($normalizedDomain === null) {
                continue;
            }

            $normalizedDomains[$tenant->id] = $normalizedDomain;
            $duplicateTenantIdsByDomain[$normalizedDomain][] = $tenant->id;
        }

        $duplicates = array_filter(
            $duplicateTenantIdsByDomain,
            static fn (array $tenantIds): bool => count($tenantIds) > 1,
        );

        if ($duplicates !== []) {
            $duplicateSummary = array_map(
                static fn (string $domain, array $tenantIds): string => sprintf(
                    '%s => [%s]',
                    $domain,
                    implode(', ', $tenantIds),
                ),
                array_keys($duplicates),
                array_values($duplicates),
            );

            throw new RuntimeException(
                'Cannot create a unique index for tenants.dominio because normalized duplicates exist: '
                .implode('; ', $duplicateSummary)
            );
        }

        foreach ($normalizedDomains as $tenantId => $normalizedDomain) {
            DB::table('tenants')
                ->where('id', $tenantId)
                ->update(['dominio' => $normalizedDomain]);
        }

        Schema::table('tenants', function (Blueprint $table) {
            $table->unique('dominio', 'tenants_dominio_unique');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::table('tenants', function (Blueprint $table) {
            $table->dropUnique('tenants_dominio_unique');
        });
    }

    private function normalizeDomain(mixed $domain, int $tenantId): ?string
    {
        if ($domain === null) {
            return null;
        }

        if (! is_string($domain)) {
            throw new RuntimeException("Cannot normalize tenant domain for tenant {$tenantId}.");
        }

        $decodedDomain = trim(urldecode($domain));

        if ($decodedDomain === '') {
            return null;
        }

        $candidate = str_contains($decodedDomain, '://')
            ? $decodedDomain
            : "//{$decodedDomain}";

        $host = parse_url($candidate, PHP_URL_HOST);

        if (! is_string($host) || $host === '') {
            throw new RuntimeException(
                "Cannot normalize tenant domain '{$domain}' for tenant {$tenantId}."
            );
        }

        return strtolower($host);
    }
};
