<?php

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

/**
 * 작업지시 공정유형 변경 마이그레이션
 *
 * 변경 사항:
 * - process_type (varchar: screen/slat/bending) 제거
 * - process_id (FK → processes.id) 추가
 *
 * 데이터 마이그레이션:
 * - screen → processes.process_name = '스크린' (P-002)
 * - slat → processes.process_name = '슬랫' (P-001)
 * - bending → processes.process_name = '절곡' (신규 생성)
 */
return new class extends Migration
{
    public function up(): void
    {
        // 이미 마이그레이션이 완료된 경우 (process_type이 없고 process_id가 있음) 건너뜀
        if (! Schema::hasColumn('work_orders', 'process_type') && Schema::hasColumn('work_orders', 'process_id')) {
            return;
        }

        // 1. 절곡 공정이 없으면 각 테넌트별로 생성
        $this->ensureBendingProcessExists();

        // 2. process_id 컬럼 추가 (이미 존재하면 스킵)
        if (! Schema::hasColumn('work_orders', 'process_id')) {
            Schema::table('work_orders', function (Blueprint $table) {
                $table->unsignedBigInteger('process_id')
                    ->nullable()
                    ->after('sales_order_id')
                    ->comment('공정 ID (FK → processes.id)');
            });
        }

        // 3. 기존 process_type 데이터를 process_id로 마이그레이션
        $this->migrateProcessTypeToProcessId();

        // 4. process_id에 FK 제약 추가 (이미 존재하면 스킵)
        $hasFk = DB::select("
            SELECT COUNT(*) as cnt FROM information_schema.KEY_COLUMN_USAGE
            WHERE TABLE_SCHEMA = DATABASE()
            AND TABLE_NAME = 'work_orders'
            AND COLUMN_NAME = 'process_id'
            AND REFERENCED_TABLE_NAME IS NOT NULL
        ")[0]->cnt > 0;

        if (! $hasFk) {
            Schema::table('work_orders', function (Blueprint $table) {
                $table->foreign('process_id')
                    ->references('id')
                    ->on('processes')
                    ->onDelete('restrict');
            });
        }

        // 5. 기존 process_type 컬럼 제거 (존재하면 제거)
        if (Schema::hasColumn('work_orders', 'process_type')) {
            Schema::table('work_orders', function (Blueprint $table) {
                $table->dropColumn('process_type');
            });
        }
    }

    public function down(): void
    {
        // 1. process_type 컬럼 복원
        Schema::table('work_orders', function (Blueprint $table) {
            $table->string('process_type', 30)
                ->default('screen')
                ->after('sales_order_id')
                ->comment('공정유형: screen/slat/bending');
        });

        // 2. process_id에서 process_type으로 데이터 복원
        $this->migrateProcessIdToProcessType();

        // 3. FK 및 process_id 컬럼 제거
        Schema::table('work_orders', function (Blueprint $table) {
            $table->dropForeign(['process_id']);
            $table->dropColumn('process_id');
        });
    }

    /**
     * 절곡 공정이 없는 테넌트에 절곡 공정 생성
     */
    private function ensureBendingProcessExists(): void
    {
        // 작업지시에서 bending을 사용하는 테넌트 조회
        $tenantIds = DB::table('work_orders')
            ->where('process_type', 'bending')
            ->distinct()
            ->pluck('tenant_id');

        foreach ($tenantIds as $tenantId) {
            // 해당 테넌트에 절곡 공정이 있는지 확인
            $exists = DB::table('processes')
                ->where('tenant_id', $tenantId)
                ->where('process_name', '절곡')
                ->exists();

            if (! $exists) {
                // 마지막 공정코드 조회
                $lastCode = DB::table('processes')
                    ->where('tenant_id', $tenantId)
                    ->orderByDesc('process_code')
                    ->value('process_code');

                // 새 공정코드 생성 (P-003 형식)
                $newCodeNum = 1;
                if ($lastCode && preg_match('/P-(\d+)/', $lastCode, $matches)) {
                    $newCodeNum = (int) $matches[1] + 1;
                }
                $newCode = sprintf('P-%03d', $newCodeNum);

                // 절곡 공정 생성
                DB::table('processes')->insert([
                    'tenant_id' => $tenantId,
                    'process_code' => $newCode,
                    'process_name' => '절곡',
                    'process_type' => '생산',
                    'description' => '절곡 공정 (마이그레이션에 의해 자동 생성)',
                    'is_active' => true,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
            }
        }
    }

    /**
     * process_type → process_id 데이터 마이그레이션
     */
    private function migrateProcessTypeToProcessId(): void
    {
        // 공정명 매핑 (process_type → process_name)
        $mappings = [
            'screen' => '스크린',
            'slat' => '슬랫',
            'bending' => '절곡',
        ];

        foreach ($mappings as $processType => $processName) {
            // 각 테넌트별로 해당 공정 ID 조회 후 업데이트
            $workOrders = DB::table('work_orders')
                ->where('process_type', $processType)
                ->whereNull('process_id')
                ->get(['id', 'tenant_id']);

            foreach ($workOrders as $workOrder) {
                $processId = DB::table('processes')
                    ->where('tenant_id', $workOrder->tenant_id)
                    ->where('process_name', $processName)
                    ->value('id');

                if ($processId) {
                    DB::table('work_orders')
                        ->where('id', $workOrder->id)
                        ->update(['process_id' => $processId]);
                }
            }
        }

        // process_id가 설정되지 않은 레코드 확인 (데이터 무결성)
        $orphanCount = DB::table('work_orders')
            ->whereNull('process_id')
            ->count();

        if ($orphanCount > 0) {
            throw new \RuntimeException(
                "마이그레이션 실패: {$orphanCount}개의 작업지시에 대응하는 공정을 찾을 수 없습니다. ".
                'processes 테이블에 스크린, 슬랫, 절곡 공정이 등록되어 있는지 확인하세요.'
            );
        }
    }

    /**
     * process_id → process_type 데이터 복원 (롤백용)
     */
    private function migrateProcessIdToProcessType(): void
    {
        // 공정명 → process_type 역매핑
        $mappings = [
            '스크린' => 'screen',
            '슬랫' => 'slat',
            '절곡' => 'bending',
        ];

        foreach ($mappings as $processName => $processType) {
            DB::table('work_orders')
                ->whereIn('process_id', function ($query) use ($processName) {
                    $query->select('id')
                        ->from('processes')
                        ->where('process_name', $processName);
                })
                ->update(['process_type' => $processType]);
        }

        // 매핑되지 않은 공정은 기본값 screen으로 설정
        DB::table('work_orders')
            ->where('process_type', '')
            ->orWhereNull('process_type')
            ->update(['process_type' => 'screen']);
    }
};
