<?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
    {
        $driver = Schema::getConnection()->getDriverName();

        if ($driver === 'sqlite') {
            Schema::disableForeignKeyConstraints();

            Schema::rename('audit_logs', 'audit_logs_old');

            foreach ([
                'audit_logs_tenant_id_action_index',
                'audit_logs_tenant_id_resource_type_index',
                'audit_logs_managed_environment_id_action_index',
                'audit_logs_managed_environment_id_resource_type_index',
                'audit_logs_recorded_at_index',
            ] as $indexName) {
                DB::statement("DROP INDEX IF EXISTS {$indexName}");
            }

            Schema::create('audit_logs', function (Blueprint $table) {
                $table->id();
                $table->foreignId('managed_environment_id')->nullable()->constrained()->cascadeOnDelete();
                $table->foreignId('workspace_id')->nullable()->constrained()->nullOnDelete();
                $table->unsignedBigInteger('actor_id')->nullable();
                $table->string('actor_email')->nullable();
                $table->string('actor_name')->nullable();
                $table->string('action');
                $table->string('resource_type')->nullable();
                $table->string('resource_id')->nullable();
                $table->string('status')->default('success');
                $table->json('metadata')->nullable();
                $table->timestamp('recorded_at')->useCurrent();
                $table->timestamps();

                $table->index(['managed_environment_id', 'action']);
                $table->index(['managed_environment_id', 'resource_type']);
                $table->index(['workspace_id', 'action']);
                $table->index(['workspace_id', 'resource_type']);
                $table->index('recorded_at');
            });

            DB::table('audit_logs_old')->orderBy('id')->chunkById(500, function ($rows): void {
                foreach ($rows as $row) {
                    DB::table('audit_logs')->insert([
                        'id' => $row->id,
                        'managed_environment_id' => $row->managed_environment_id,
                        'workspace_id' => null,
                        'actor_id' => $row->actor_id,
                        'actor_email' => $row->actor_email,
                        'actor_name' => $row->actor_name,
                        'action' => $row->action,
                        'resource_type' => $row->resource_type,
                        'resource_id' => $row->resource_id,
                        'status' => $row->status,
                        'metadata' => $row->metadata,
                        'recorded_at' => $row->recorded_at,
                        'created_at' => $row->created_at,
                        'updated_at' => $row->updated_at,
                    ]);
                }
            }, 'id');

            Schema::drop('audit_logs_old');
            Schema::enableForeignKeyConstraints();

            return;
        }

        DB::statement('ALTER TABLE audit_logs ALTER COLUMN managed_environment_id DROP NOT NULL');

        Schema::table('audit_logs', function (Blueprint $table) {
            $table->foreignId('workspace_id')->nullable()->constrained()->nullOnDelete()->after('managed_environment_id');

            $table->index(['workspace_id', 'action']);
            $table->index(['workspace_id', 'resource_type']);
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        $driver = Schema::getConnection()->getDriverName();

        if ($driver === 'sqlite') {
            Schema::disableForeignKeyConstraints();

            Schema::rename('audit_logs', 'audit_logs_new');

            foreach ([
                'audit_logs_tenant_id_action_index',
                'audit_logs_tenant_id_resource_type_index',
                'audit_logs_managed_environment_id_action_index',
                'audit_logs_managed_environment_id_resource_type_index',
                'audit_logs_recorded_at_index',
                'audit_logs_workspace_id_action_index',
                'audit_logs_workspace_id_resource_type_index',
            ] as $indexName) {
                DB::statement("DROP INDEX IF EXISTS {$indexName}");
            }

            Schema::create('audit_logs', function (Blueprint $table) {
                $table->id();
                $table->foreignId('managed_environment_id')->constrained()->cascadeOnDelete();
                $table->unsignedBigInteger('actor_id')->nullable();
                $table->string('actor_email')->nullable();
                $table->string('actor_name')->nullable();
                $table->string('action');
                $table->string('resource_type')->nullable();
                $table->string('resource_id')->nullable();
                $table->string('status')->default('success');
                $table->json('metadata')->nullable();
                $table->timestamp('recorded_at')->useCurrent();
                $table->timestamps();

                $table->index(['managed_environment_id', 'action']);
                $table->index(['managed_environment_id', 'resource_type']);
                $table->index('recorded_at');
            });

            DB::table('audit_logs_new')->whereNotNull('managed_environment_id')->orderBy('id')->chunkById(500, function ($rows): void {
                foreach ($rows as $row) {
                    DB::table('audit_logs')->insert([
                        'id' => $row->id,
                        'managed_environment_id' => $row->managed_environment_id,
                        'actor_id' => $row->actor_id,
                        'actor_email' => $row->actor_email,
                        'actor_name' => $row->actor_name,
                        'action' => $row->action,
                        'resource_type' => $row->resource_type,
                        'resource_id' => $row->resource_id,
                        'status' => $row->status,
                        'metadata' => $row->metadata,
                        'recorded_at' => $row->recorded_at,
                        'created_at' => $row->created_at,
                        'updated_at' => $row->updated_at,
                    ]);
                }
            }, 'id');

            Schema::drop('audit_logs_new');
            Schema::enableForeignKeyConstraints();

            return;
        }

        Schema::table('audit_logs', function (Blueprint $table) {
            $table->dropConstrainedForeignId('workspace_id');
            $table->dropIndex(['workspace_id', 'action']);
            $table->dropIndex(['workspace_id', 'resource_type']);
        });

        DB::statement('ALTER TABLE audit_logs ALTER COLUMN managed_environment_id SET NOT NULL');
    }
};
