<?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
{
    public function up(): void
    {
        $driver = Schema::getConnection()->getDriverName();
        $tenantStatusIndex = 'subscriptions_tenant_id_status_index';
        $mysqlLike = $driver === 'mysql' || $driver === 'mariadb';

        // Drop before changing `status`. On MySQL/MariaDB, dropping `status` can leave the old
        // default-named index on `tenant_id` only; `hasIndex([...])` misses it and adding the same
        // index name errors. That index is also required by `subscriptions_tenant_id_foreign`, so
        // drop the FK first, then the index (SQLite keeps the original path: drop by columns only).
        if ($mysqlLike) {
            $hasTenantFk = collect(Schema::getForeignKeys('subscriptions'))
                ->contains(fn (array $fk): bool => $fk['name'] === 'subscriptions_tenant_id_foreign');

            if ($hasTenantFk) {
                Schema::table('subscriptions', function (Blueprint $table): void {
                    $table->dropForeign(['tenant_id']);
                });
            }

            if (Schema::hasIndex('subscriptions', $tenantStatusIndex)) {
                Schema::table('subscriptions', function (Blueprint $table) use ($tenantStatusIndex): void {
                    $table->dropIndex($tenantStatusIndex);
                });
            }
        } elseif (Schema::hasIndex('subscriptions', ['tenant_id', 'status'])) {
            Schema::table('subscriptions', function (Blueprint $table): void {
                $table->dropIndex(['tenant_id', 'status']);
            });
        }

        Schema::table('subscriptions', function (Blueprint $table) {
            $table->string('status_new', 32)->default('active')->after('plan_id');
        });

        DB::table('subscriptions')->orderBy('id')->each(function (object $row): void {
            DB::table('subscriptions')->where('id', $row->id)->update([
                'status_new' => (string) $row->status,
            ]);
        });

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

        Schema::table('subscriptions', function (Blueprint $table) {
            $table->renameColumn('status_new', 'status');
        });

        if (! Schema::hasIndex('subscriptions', ['tenant_id', 'status'])) {
            Schema::table('subscriptions', function (Blueprint $table) {
                $table->index(['tenant_id', 'status']);
            });
        }

        if ($mysqlLike) {
            $hasTenantFk = collect(Schema::getForeignKeys('subscriptions'))
                ->contains(fn (array $fk): bool => $fk['name'] === 'subscriptions_tenant_id_foreign');

            if (! $hasTenantFk) {
                Schema::table('subscriptions', function (Blueprint $table): void {
                    $table->foreign('tenant_id')->references('id')->on('tenants')->cascadeOnDelete();
                });
            }
        }

        Schema::table('subscriptions', function (Blueprint $table) {
            $table->timestamp('grace_ends_at')->nullable()->after('trial_ends_at');
        });
    }

    public function down(): void
    {
        Schema::table('subscriptions', function (Blueprint $table) {
            $table->dropColumn('grace_ends_at');
        });
    }
};
