<?php

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

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('personal_access_tokens', function (Blueprint $table): void {
            $table->id();
            $table->morphs('tokenable');
            $table->text('name');
            $table->string('token', 64)->unique();
            $table->text('abilities')->nullable();
            $table->timestamp('last_used_at')->nullable();
            $table->dateTime('expires_at')->nullable()->index();
            $table->timestamps();
        });

        Schema::create('api_refresh_tokens', function (Blueprint $table): void {
            $table->id();
            $table->uuid('uuid')->unique();
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            $table->uuid('token_family')->index();
            $table->string('jti_hash', 64)->unique();
            $table->string('token_hash', 64)->unique();
            $table->string('device_identifier_hash', 64)->index();
            $table->string('device_name')->nullable();
            $table->ipAddress('issued_ip')->nullable();
            $table->text('user_agent')->nullable();
            $table->dateTime('expires_at')->index();
            $table->timestamp('last_used_at')->nullable();
            $table->timestamp('revoked_at')->nullable()->index();
            $table->string('revocation_reason')->nullable();
            $table->foreignId('replaced_by')->nullable()->constrained('api_refresh_tokens')->nullOnDelete();
            $table->timestamps();

            $table->index(['user_id', 'revoked_at', 'expires_at']);
            $table->index(['token_family', 'revoked_at']);
        });

        Schema::create('otp_challenges', function (Blueprint $table): void {
            $table->id();
            $table->uuid('uuid')->unique();
            $table->foreignId('user_id')->nullable()->constrained()->cascadeOnDelete();
            $table->string('purpose', 40)->index();
            $table->string('channel', 20);
            $table->text('destination')->nullable();
            $table->string('destination_hash', 64)->index();
            $table->string('otp_hash');
            $table->unsignedTinyInteger('attempts')->default(0);
            $table->unsignedTinyInteger('max_attempts')->default(5);
            $table->dateTime('expires_at')->index();
            $table->timestamp('consumed_at')->nullable()->index();
            $table->timestamp('invalidated_at')->nullable();
            $table->ipAddress('requested_ip')->nullable();
            $table->json('metadata')->nullable();
            $table->timestamps();

            $table->index(['destination_hash', 'purpose', 'created_at']);
        });

        Schema::create('api_logs', function (Blueprint $table): void {
            $table->id();
            $table->uuid('request_id')->unique();
            $table->foreignId('user_id')->nullable()->constrained()->nullOnDelete();
            $table->foreignId('admin_id')->nullable()->constrained()->nullOnDelete();
            $table->foreignId('api_key_id')->nullable()->constrained()->nullOnDelete();
            $table->string('api_version', 10)->default('v1')->index();
            $table->string('method', 10)->index();
            $table->string('path', 500);
            $table->string('route_name')->nullable()->index();
            $table->unsignedSmallInteger('response_status')->index();
            $table->string('error_code', 20)->nullable()->index();
            $table->longText('request_payload')->nullable();
            $table->longText('response_payload')->nullable();
            $table->ipAddress('ip_address')->nullable()->index();
            $table->text('user_agent')->nullable();
            $table->unsignedInteger('duration_ms')->default(0)->index();
            $table->unsignedInteger('query_count')->default(0);
            $table->unsignedInteger('request_size')->default(0);
            $table->unsignedInteger('response_size')->default(0);
            $table->string('correlation_id', 100)->nullable()->index();
            $table->timestamp('created_at')->useCurrent()->index();

            $table->index(['user_id', 'created_at']);
            $table->index(['method', 'response_status', 'created_at']);
            $table->index(['duration_ms', 'created_at']);
        });

        Schema::create('api_idempotency_keys', function (Blueprint $table): void {
            $table->id();
            $table->uuid('uuid')->unique();
            $table->foreignId('user_id')->nullable()->constrained()->cascadeOnDelete();
            $table->string('actor_hash', 64);
            $table->string('key_hash', 64);
            $table->string('scope', 100);
            $table->string('request_hash', 64);
            $table->unsignedSmallInteger('response_status')->nullable();
            $table->longText('response_body')->nullable();
            $table->string('status', 20)->default('processing')->index();
            $table->dateTime('locked_at');
            $table->timestamp('completed_at')->nullable();
            $table->dateTime('expires_at')->index();
            $table->timestamps();

            $table->unique(['actor_hash', 'scope', 'key_hash'], 'api_idempotency_identity_unique');
        });

        Schema::create('api_request_nonces', function (Blueprint $table): void {
            $table->id();
            $table->string('client_identifier_hash', 64);
            $table->string('nonce_hash', 64);
            $table->string('signature_hash', 64)->nullable();
            $table->dateTime('request_timestamp')->index();
            $table->dateTime('expires_at')->index();
            $table->timestamp('created_at')->useCurrent();

            $table->unique(['client_identifier_hash', 'nonce_hash']);
        });

        Schema::create('api_webhook_endpoints', function (Blueprint $table): void {
            $table->id();
            $table->uuid('uuid')->unique();
            $table->string('name');
            $table->text('url');
            $table->string('url_hash', 64)->unique();
            $table->text('encrypted_secret');
            $table->json('subscribed_events');
            $table->json('authentication_headers')->nullable();
            $table->boolean('verify_tls')->default(true);
            $table->unsignedSmallInteger('max_attempts')->default(5);
            $table->unsignedInteger('timeout_seconds')->default(10);
            $table->string('status', 20)->default('active')->index();
            $table->foreignId('created_by')->nullable()->constrained('admins')->nullOnDelete();
            $table->timestamps();
            $table->softDeletes();
        });

        Schema::create('api_webhook_deliveries', function (Blueprint $table): void {
            $table->id();
            $table->uuid('uuid')->unique();
            $table->foreignId('api_webhook_endpoint_id')->constrained()->cascadeOnDelete();
            $table->string('event_id', 100);
            $table->string('event_type', 100)->index();
            $table->longText('payload');
            $table->string('payload_hash', 64);
            $table->unsignedSmallInteger('attempt')->default(1);
            $table->unsignedSmallInteger('response_status')->nullable();
            $table->longText('response_body')->nullable();
            $table->string('status', 20)->default('queued')->index();
            $table->timestamp('next_retry_at')->nullable()->index();
            $table->timestamp('delivered_at')->nullable();
            $table->timestamp('created_at')->useCurrent();

            $table->unique(['api_webhook_endpoint_id', 'event_id', 'attempt'], 'api_webhook_attempt_unique');
            $table->index(['status', 'next_retry_at']);
        });

        Schema::create('api_metric_buckets', function (Blueprint $table): void {
            $table->id();
            $table->string('api_version', 10);
            $table->string('route_name')->index();
            $table->dateTime('bucket_start')->index();
            $table->unsignedInteger('request_count')->default(0);
            $table->unsignedInteger('success_count')->default(0);
            $table->unsignedInteger('client_error_count')->default(0);
            $table->unsignedInteger('server_error_count')->default(0);
            $table->unsignedBigInteger('total_duration_ms')->default(0);
            $table->unsignedInteger('maximum_duration_ms')->default(0);
            $table->timestamps();

            $table->unique(['api_version', 'route_name', 'bucket_start'], 'api_metric_bucket_unique');
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('api_metric_buckets');
        Schema::dropIfExists('api_webhook_deliveries');
        Schema::dropIfExists('api_webhook_endpoints');
        Schema::dropIfExists('api_request_nonces');
        Schema::dropIfExists('api_idempotency_keys');
        Schema::dropIfExists('api_logs');
        Schema::dropIfExists('otp_challenges');
        Schema::dropIfExists('api_refresh_tokens');
        Schema::dropIfExists('personal_access_tokens');
    }
};
