<?php

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

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('group_invitations', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('group_id')
                ->constrained('groups')
                ->cascadeOnDelete();
            $table->foreignId('invited_user_id')
                ->constrained('users')
                ->cascadeOnDelete();
            $table->foreignId('invited_by_user_id')
                ->nullable()
                ->constrained('users')
                ->nullOnDelete();
            $table->foreignId('source_group_member_id')
                ->nullable()
                ->constrained('group_members')
                ->nullOnDelete();
            $table->enum('role', ['admin', 'editor', 'member'])->default('member');
            $table->enum('status', [
                GroupInvitation::STATUS_PENDING,
                GroupInvitation::STATUS_ACCEPTED,
                GroupInvitation::STATUS_DECLINED,
                GroupInvitation::STATUS_REVOKED,
                GroupInvitation::STATUS_EXPIRED,
            ])->default(GroupInvitation::STATUS_PENDING);
            $table->string('token', 80)->unique();
            $table->text('note')->nullable();
            $table->timestamp('invited_at')->nullable();
            $table->timestamp('expires_at')->nullable();
            $table->timestamp('responded_at')->nullable();
            $table->timestamp('accepted_at')->nullable();
            $table->timestamp('revoked_at')->nullable();
            $table->timestamps();

            $table->index(['group_id', 'status', 'role'], 'group_invitations_status_role_idx');
            $table->index(['invited_user_id', 'status'], 'group_invitations_user_status_idx');
        });

        if (! Schema::hasTable('group_members')) {
            return;
        }

        DB::table('group_members')
            ->whereIn('status', ['pending', 'revoked'])
            ->orderBy('id')
            ->get()
            ->each(function (object $member): void {
                $status = match ((string) $member->status) {
                    'pending' => GroupInvitation::STATUS_PENDING,
                    default => GroupInvitation::STATUS_REVOKED,
                };

                DB::table('group_invitations')->insert([
                    'group_id' => (int) $member->group_id,
                    'invited_user_id' => (int) $member->user_id,
                    'invited_by_user_id' => $member->invited_by_user_id ? (int) $member->invited_by_user_id : null,
                    'source_group_member_id' => (int) $member->id,
                    'role' => (string) $member->role,
                    'status' => $status,
                    'token' => Str::random(64),
                    'note' => $member->note,
                    'invited_at' => $member->invited_at,
                    'expires_at' => $member->expires_at,
                    'responded_at' => $member->accepted_at ?? $member->revoked_at,
                    'accepted_at' => null,
                    'revoked_at' => $member->revoked_at,
                    'created_at' => $member->created_at ?? now(),
                    'updated_at' => $member->updated_at ?? now(),
                ]);
            });
    }

    public function down(): void
    {
        Schema::dropIfExists('group_invitations');
    }
};