<?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
    {
        /**
         * 1) MENUS: 권한관리용 필드 추가
         *  - slug: 메뉴/퍼미션 키 매핑용 고유 식별자 (테넌트 범위 유니크)
         *  - SoftDeletes + acted-by 컬럼
         */
        Schema::table('menus', function (Blueprint $table) {
            // slug 추가 (권한 키로 활용) - 테넌트 내 유니크
            if (! Schema::hasColumn('menus', 'slug')) {
                $table->string('slug', 150)->nullable()->after('name')->comment('메뉴 슬러그(권한 키)');
            }

            // Soft delete
            if (! Schema::hasColumn('menus', 'deleted_at')) {
                $table->softDeletes()->comment('소프트삭제 시각');
            }

            // acted-by (누가 생성/수정/삭제 했는지)
            if (! Schema::hasColumn('menus', 'created_by')) {
                $table->unsignedBigInteger('created_by')->nullable()->after('updated_at')->comment('생성자 사용자 ID');
            }
            if (! Schema::hasColumn('menus', 'updated_by')) {
                $table->unsignedBigInteger('updated_by')->nullable()->after('created_by')->comment('수정자 사용자 ID');
            }
            if (! Schema::hasColumn('menus', 'deleted_by')) {
                $table->unsignedBigInteger('deleted_by')->nullable()->after('updated_by')->comment('삭제자 사용자 ID');
            }

            // 인덱스/유니크
            // slug는 테넌트 범위에서 유니크 보장
            $table->unique(['tenant_id', 'slug'], 'menus_tenant_slug_unique');
            $table->index(['tenant_id', 'is_active', 'hidden'], 'menus_tenant_active_hidden_idx');
            $table->index(['sort_order'], 'menus_sort_idx');
        });

        /**
         * 2) 부서 테이블
         */
        if (! Schema::hasTable('departments')) {
            Schema::create('departments', function (Blueprint $table) {
                $table->bigIncrements('id')->comment('PK: 부서 ID');
                $table->unsignedBigInteger('tenant_id')->comment('테넌트 ID');
                $table->string('code', 50)->nullable()->comment('부서 코드');
                $table->string('name', 100)->comment('부서명');
                $table->string('description', 255)->nullable()->comment('설명');
                $table->tinyInteger('is_active')->default(1)->comment('활성여부(1=활성,0=비활성)');
                $table->integer('sort_order')->default(0)->comment('정렬순서');

                $table->timestamps();
                $table->softDeletes();

                // acted-by
                $table->unsignedBigInteger('created_by')->nullable()->comment('생성자 사용자 ID');
                $table->unsignedBigInteger('updated_by')->nullable()->comment('수정자 사용자 ID');
                $table->unsignedBigInteger('deleted_by')->nullable()->comment('삭제자 사용자 ID');

                // 인덱스
                $table->unique(['tenant_id', 'code'], 'dept_tenant_code_unique');
                $table->index(['tenant_id', 'name'], 'dept_tenant_name_idx');
                $table->index(['tenant_id', 'is_active'], 'dept_tenant_active_idx');
            });
        }

        /**
         * 3) 부서-사용자 매핑
         * - 동일 부서-사용자 중복 매핑 방지(tenant_id 포함)
         */
        if (! Schema::hasTable('department_user')) {
            Schema::create('department_user', function (Blueprint $table) {
                $table->bigIncrements('id')->comment('PK');
                $table->unsignedBigInteger('tenant_id')->comment('테넌트 ID');
                $table->unsignedBigInteger('department_id')->comment('부서 ID');
                $table->unsignedBigInteger('user_id')->comment('사용자 ID');

                $table->tinyInteger('is_primary')->default(0)->comment('주 부서 여부(1=Y,0=N)');
                $table->timestamp('joined_at')->nullable()->comment('부서 배정일');
                $table->timestamp('left_at')->nullable()->comment('부서 이탈일');

                $table->timestamps();
                $table->softDeletes();

                // 인덱스/유니크
                $table->unique(['tenant_id', 'department_id', 'user_id'], 'dept_user_unique');
                $table->index(['tenant_id', 'user_id'], 'dept_user_user_idx');
                $table->index(['tenant_id', 'department_id'], 'dept_user_dept_idx');
            });
        }

        /**
         * 4) 부서별 권한 매핑
         * - Spatie permissions 테이블의 permission_id와 연결(실 FK는 미사용)
         * - ALLOW/DENY는 is_allowed로 표현
         * - 필요시 메뉴 단위 범위 제한을 위해 menu_id(옵션)
         */
        if (! Schema::hasTable('department_permissions')) {
            Schema::create('department_permissions', function (Blueprint $table) {
                $table->bigIncrements('id')->comment('PK');
                $table->unsignedBigInteger('tenant_id')->comment('테넌트 ID');
                $table->unsignedBigInteger('department_id')->comment('부서 ID');
                $table->unsignedBigInteger('permission_id')->comment('Spatie permissions.id');
                $table->unsignedBigInteger('menu_id')->nullable()->comment('메뉴 ID (선택), 특정 메뉴 범위 권한');

                $table->tinyInteger('is_allowed')->default(1)->comment('허용여부(1=ALLOW,0=DENY)');

                $table->timestamps();
                $table->softDeletes();

                // 인덱스/유니크 (동일 권한 중복 방지)
                $table->unique(
                    ['tenant_id', 'department_id', 'permission_id', 'menu_id'],
                    'dept_perm_unique'
                );
                $table->index(['tenant_id', 'department_id'], 'dept_perm_dept_idx');
                $table->index(['tenant_id', 'permission_id'], 'dept_perm_perm_idx');
                $table->index(['tenant_id', 'menu_id'], 'dept_perm_menu_idx');
            });
        }

        /**
         * 5) 사용자 퍼미션 오버라이드 (개인 단위 허용/차단)
         * - 개인 DENY가 최우선 → 해석 레이어에서 우선순위 처리
         */
        if (! Schema::hasTable('user_permission_overrides')) {
            Schema::create('user_permission_overrides', function (Blueprint $table) {
                $table->bigIncrements('id')->comment('PK');
                $table->unsignedBigInteger('tenant_id')->comment('테넌트 ID');
                $table->unsignedBigInteger('user_id')->comment('사용자 ID');
                $table->unsignedBigInteger('permission_id')->comment('Spatie permissions.id');
                $table->unsignedBigInteger('menu_id')->nullable()->comment('메뉴 ID (선택)');

                $table->tinyInteger('is_allowed')->default(1)->comment('허용여부(1=ALLOW,0=DENY)');
                $table->string('reason', 255)->nullable()->comment('사유/메모');
                $table->timestamp('effective_from')->nullable()->comment('효력 시작');
                $table->timestamp('effective_to')->nullable()->comment('효력 종료');

                $table->timestamps();
                $table->softDeletes();

                // 중복 방지
                $table->unique(
                    ['tenant_id', 'user_id', 'permission_id', 'menu_id'],
                    'user_perm_override_unique'
                );
                $table->index(['tenant_id', 'user_id'], 'user_perm_user_idx');
                $table->index(['tenant_id', 'permission_id'], 'user_perm_perm_idx');
            });
        }
    }

    public function down(): void
    {
        // 생성 테이블 역순 드롭
        Schema::dropIfExists('user_permission_overrides');
        Schema::dropIfExists('department_permissions');
        Schema::dropIfExists('department_user');
        Schema::dropIfExists('departments');

        // MENUS 원복: 추가했던 컬럼/인덱스 제거
        Schema::table('menus', function (Blueprint $table) {
            // 인덱스/유니크 먼저 제거
            if ($this->indexExists('menus', 'menus_tenant_slug_unique')) {
                $table->dropUnique('menus_tenant_slug_unique');
            }
            if ($this->indexExists('menus', 'menus_tenant_active_hidden_idx')) {
                $table->dropIndex('menus_tenant_active_hidden_idx');
            }
            if ($this->indexExists('menus', 'menus_sort_idx')) {
                $table->dropIndex('menus_sort_idx');
            }

            // 컬럼 제거 (존재 체크는 직접 불가하므로 try-catch는 생략)
            if (Schema::hasColumn('menus', 'slug')) {
                $table->dropColumn('slug');
            }
            if (Schema::hasColumn('menus', 'deleted_at')) {
                $table->dropSoftDeletes();
            }
            if (Schema::hasColumn('menus', 'deleted_by')) {
                $table->dropColumn('deleted_by');
            }
            if (Schema::hasColumn('menus', 'updated_by')) {
                $table->dropColumn('updated_by');
            }
            if (Schema::hasColumn('menus', 'created_by')) {
                $table->dropColumn('created_by');
            }
        });
    }

    /**
     * Laravel의 Blueprint에서는 인덱스 존재 체크가 불가하므로
     * 스키마 매니저를 직접 조회하는 헬퍼.
     */
    private function indexExists(string $table, string $indexName): bool
    {
        try {
            $connection = Schema::getConnection();
            $schemaManager = $connection->getDoctrineSchemaManager();
            $doctrineTable = $schemaManager->introspectTable(
                $connection->getTablePrefix().$table
            );
            foreach ($doctrineTable->getIndexes() as $idx) {
                if ($idx->getName() === $indexName) {
                    return true;
                }
            }
        } catch (\Throwable $e) {
            // 무시
        }

        return false;
    }
};
