<?php

namespace App\Console\Commands;

use Illuminate\Console\Attributes\AsCommand;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

#[AsCommand(name: 'migrate:5130-items', description: '5130 품목 데이터를 SAM items 테이블로 마이그레이션')]
class Migrate5130Items extends Command
{
    protected $signature = 'migrate:5130-items
                            {--tenant_id=287 : Target tenant ID (default: 287 경동기업)}
                            {--dry-run : 실제 저장 없이 시뮬레이션만 수행}
                            {--step=all : 실행할 단계 (all|models|parts|parts_sub|bdmodels|relations)}
                            {--rollback : 마이그레이션 롤백 (source=5130 데이터 삭제)}';

    // 5130 DB 연결
    private string $sourceDb = 'chandj';

    // SAM DB 연결
    private string $targetDb = 'samdb';

    // 매핑 캐시 (source_table:source_id => item_id)
    private array $idMappings = [];

    public function handle(): int
    {
        $tenantId = (int) $this->option('tenant_id');
        $dryRun = $this->option('dry-run');
        $step = $this->option('step');
        $rollback = $this->option('rollback');

        $this->info('=== 5130 → SAM 품목 마이그레이션 ===');
        $this->info("Tenant ID: {$tenantId}");
        $this->info('Mode: '.($dryRun ? 'DRY-RUN (시뮬레이션)' : 'LIVE'));
        $this->info("Step: {$step}");
        $this->newLine();

        if ($rollback) {
            return $this->rollbackMigration($tenantId, $dryRun);
        }

        // 기존 매핑 로드
        $this->loadExistingMappings();

        $steps = $step === 'all'
            ? ['models', 'parts', 'parts_sub', 'bdmodels', 'relations']
            : [$step];

        foreach ($steps as $currentStep) {
            $this->line(">>> Step: {$currentStep}");

            match ($currentStep) {
                'models' => $this->migrateModels($tenantId, $dryRun),
                'parts' => $this->migrateParts($tenantId, $dryRun),
                'parts_sub' => $this->migratePartsSub($tenantId, $dryRun),
                'bdmodels' => $this->migrateBDModels($tenantId, $dryRun),
                'relations' => $this->migrateRelations($tenantId, $dryRun),
                default => $this->error("Unknown step: {$currentStep}"),
            };

            $this->newLine();
        }

        $this->info('=== 마이그레이션 완료 ===');
        $this->showSummary();

        return self::SUCCESS;
    }

    /**
     * 기존 매핑 로드 (중복 방지)
     */
    private function loadExistingMappings(): void
    {
        $mappings = DB::connection('mysql')->table('item_id_mappings')->get();

        foreach ($mappings as $mapping) {
            $key = "{$mapping->source_table}:{$mapping->source_id}";
            $this->idMappings[$key] = $mapping->item_id;
        }

        $this->line('Loaded '.count($this->idMappings).' existing mappings');
    }

    /**
     * models → items (FG)
     */
    private function migrateModels(int $tenantId, bool $dryRun): void
    {
        $this->info('Migrating models → items (FG)...');

        $models = DB::connection('chandj')->table('models')
            ->where('is_deleted', 0)
            ->get();

        $this->line("Found {$models->count()} models");

        $bar = $this->output->createProgressBar($models->count());
        $bar->start();

        foreach ($models as $model) {
            $mappingKey = "models:{$model->model_id}";

            // 이미 마이그레이션된 경우 스킵
            if (isset($this->idMappings[$mappingKey])) {
                $bar->advance();

                continue;
            }

            $itemData = [
                'tenant_id' => $tenantId,
                'item_type' => 'FG',
                'code' => $model->model_name,
                'name' => $model->model_name,
                'unit' => 'SET',
                'description' => $model->description,
                'attributes' => json_encode([
                    'major_category' => $model->major_category,
                    'finishing_type' => $model->finishing_type,
                    'guiderail_type' => $model->guiderail_type,
                    'source' => '5130',
                    'source_table' => 'models',
                    'source_id' => $model->model_id,
                ]),
                'is_active' => 1,
                'created_at' => $model->created_at ?? now(),
                'updated_at' => $model->updated_at ?? now(),
            ];

            if (! $dryRun) {
                $itemId = DB::connection('mysql')->table('items')->insertGetId($itemData);

                // 매핑 기록
                DB::connection('mysql')->table('item_id_mappings')->insert([
                    'source_table' => 'models',
                    'source_id' => $model->model_id,
                    'item_id' => $itemId,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);

                $this->idMappings[$mappingKey] = $itemId;
            }

            $bar->advance();
        }

        $bar->finish();
        $this->newLine();
        $this->info('Models migration completed');
    }

    /**
     * parts → items (PT)
     */
    private function migrateParts(int $tenantId, bool $dryRun): void
    {
        $this->info('Migrating parts → items (PT)...');

        $parts = DB::connection('chandj')->table('parts')
            ->where('is_deleted', 0)
            ->get();

        $this->line("Found {$parts->count()} parts");

        $bar = $this->output->createProgressBar($parts->count());
        $bar->start();

        foreach ($parts as $part) {
            $mappingKey = "parts:{$part->part_id}";

            if (isset($this->idMappings[$mappingKey])) {
                $bar->advance();

                continue;
            }

            $code = $this->generateCode('PT', $part->part_name);

            $itemData = [
                'tenant_id' => $tenantId,
                'item_type' => 'PT',
                'code' => $code,
                'name' => $part->part_name ?: '(이름없음)',
                'unit' => $part->unit ?: 'EA',
                'description' => $part->memo,
                'attributes' => json_encode([
                    'spec' => $part->spec,
                    'unit_price' => $this->parseNumber($part->unitprice),
                    'image_url' => $part->img_url,
                    'source' => '5130',
                    'source_table' => 'parts',
                    'source_id' => $part->part_id,
                    'parent_model_id' => $part->model_id,
                ]),
                'is_active' => 1,
                'created_at' => $part->created_at ?? now(),
                'updated_at' => $part->updated_at ?? now(),
            ];

            if (! $dryRun) {
                $itemId = DB::connection('mysql')->table('items')->insertGetId($itemData);

                DB::connection('mysql')->table('item_id_mappings')->insert([
                    'source_table' => 'parts',
                    'source_id' => $part->part_id,
                    'item_id' => $itemId,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);

                $this->idMappings[$mappingKey] = $itemId;
            }

            $bar->advance();
        }

        $bar->finish();
        $this->newLine();
        $this->info('Parts migration completed');
    }

    /**
     * parts_sub → items (RM)
     */
    private function migratePartsSub(int $tenantId, bool $dryRun): void
    {
        $this->info('Migrating parts_sub → items (RM)...');

        $partsSub = DB::connection('chandj')->table('parts_sub')
            ->where('is_deleted', 0)
            ->get();

        $this->line("Found {$partsSub->count()} parts_sub");

        $bar = $this->output->createProgressBar($partsSub->count());
        $bar->start();

        foreach ($partsSub as $sub) {
            $mappingKey = "parts_sub:{$sub->subpart_id}";

            if (isset($this->idMappings[$mappingKey])) {
                $bar->advance();

                continue;
            }

            $code = $this->generateCode('RM', $sub->subpart_name);

            $itemData = [
                'tenant_id' => $tenantId,
                'item_type' => 'RM',
                'code' => $code,
                'name' => $sub->subpart_name ?: '(이름없음)',
                'unit' => 'EA',
                'description' => null,
                'attributes' => json_encode([
                    'material' => $sub->material,
                    'bend_sum' => $this->parseNumber($sub->bendSum),
                    'plate_sum' => $this->parseNumber($sub->plateSum),
                    'final_sum' => $this->parseNumber($sub->finalSum),
                    'unit_price' => $this->parseNumber($sub->unitPrice),
                    'computed_price' => $this->parseNumber($sub->computedPrice),
                    'line_total' => $this->parseNumber($sub->lineTotal),
                    'image_url' => $sub->image_url,
                    'source' => '5130',
                    'source_table' => 'parts_sub',
                    'source_id' => $sub->subpart_id,
                    'parent_part_id' => $sub->part_id,
                ]),
                'is_active' => 1,
                'created_at' => $sub->created_at ?? now(),
                'updated_at' => $sub->updated_at ?? now(),
            ];

            if (! $dryRun) {
                $itemId = DB::connection('mysql')->table('items')->insertGetId($itemData);

                DB::connection('mysql')->table('item_id_mappings')->insert([
                    'source_table' => 'parts_sub',
                    'source_id' => $sub->subpart_id,
                    'item_id' => $itemId,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);

                $this->idMappings[$mappingKey] = $itemId;
            }

            $bar->advance();
        }

        $bar->finish();
        $this->newLine();
        $this->info('Parts_sub migration completed');
    }

    /**
     * BDmodels → items (PT) + savejson → items (RM) + 관계
     */
    private function migrateBDModels(int $tenantId, bool $dryRun): void
    {
        $this->info('Migrating BDmodels → items (PT + RM with BOM)...');

        $bdmodels = DB::connection('chandj')->table('BDmodels')
            ->where('is_deleted', 0)
            ->get();

        $this->line("Found {$bdmodels->count()} BDmodels");

        $bar = $this->output->createProgressBar($bdmodels->count());
        $bar->start();

        $bomCount = 0;

        foreach ($bdmodels as $bd) {
            $mappingKey = "BDmodels:{$bd->num}";

            // 이미 마이그레이션된 경우 스킵
            if (isset($this->idMappings[$mappingKey])) {
                $bar->advance();

                continue;
            }

            // BDmodels → items (PT: 부품)
            $code = $this->generateCode('BD', $bd->seconditem ?: $bd->model_name ?: "BD{$bd->num}");

            $itemData = [
                'tenant_id' => $tenantId,
                'item_type' => 'PT',
                'code' => $code,
                'name' => $bd->seconditem ?: $bd->model_name ?: '(이름없음)',
                'unit' => 'EA',
                'description' => $bd->description,
                'attributes' => json_encode([
                    'model_name' => $bd->model_name,
                    'major_category' => $bd->major_category,
                    'spec' => $bd->spec,
                    'finishing_type' => $bd->finishing_type,
                    'check_type' => $bd->check_type,
                    'exit_direction' => $bd->exit_direction,
                    'unit_price' => $this->parseNumber($bd->unitprice),
                    'price_date' => $bd->priceDate,
                    'source' => '5130',
                    'source_table' => 'BDmodels',
                    'source_id' => $bd->num,
                ]),
                'is_active' => 1,
                'created_at' => $bd->created_at ?? now(),
                'updated_at' => $bd->updated_at ?? now(),
            ];

            $parentItemId = null;

            if (! $dryRun) {
                $parentItemId = DB::connection('mysql')->table('items')->insertGetId($itemData);

                DB::connection('mysql')->table('item_id_mappings')->insert([
                    'source_table' => 'BDmodels',
                    'source_id' => $bd->num,
                    'item_id' => $parentItemId,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);

                $this->idMappings[$mappingKey] = $parentItemId;
            }

            // savejson → 자식 items (RM: 원자재) + 관계
            if (! empty($bd->savejson)) {
                $bomItems = json_decode($bd->savejson, true);

                if (is_array($bomItems)) {
                    $orderNo = 0;
                    foreach ($bomItems as $bomItem) {
                        $orderNo++;
                        $childMappingKey = "BDmodels_bom:{$bd->num}:{$orderNo}";

                        if (isset($this->idMappings[$childMappingKey])) {
                            continue;
                        }

                        // col1: 품명, col2: 재질, col3: 여유, col4: 전개, col5: 합계
                        // col6: 단가, col7: 금액, col8: 수량, col9: 총액, col10: 비고
                        $childName = $bomItem['col1'] ?? '(BOM항목)';
                        $childCode = $this->generateCode('RM', $childName.'_'.$bd->num.'_'.$orderNo);

                        $childData = [
                            'tenant_id' => $tenantId,
                            'item_type' => 'RM',
                            'code' => $childCode,
                            'name' => $childName,
                            'unit' => 'EA',
                            'description' => $bomItem['col10'] ?? null,
                            'attributes' => json_encode([
                                'material' => $bomItem['col2'] ?? null,
                                'margin' => $this->parseNumber($bomItem['col3'] ?? null),
                                'unfold' => $this->parseNumber($bomItem['col4'] ?? null),
                                'total_length' => $this->parseNumber($bomItem['col5'] ?? null),
                                'unit_price' => $this->parseNumber($bomItem['col6'] ?? null),
                                'amount' => $this->parseNumber($bomItem['col7'] ?? null),
                                'quantity' => $this->parseNumber($bomItem['col8'] ?? null),
                                'line_total' => $this->parseNumber($bomItem['col9'] ?? null),
                                'source' => '5130',
                                'source_table' => 'BDmodels_bom',
                                'source_id' => "{$bd->num}:{$orderNo}",
                                'parent_bdmodel_id' => $bd->num,
                            ]),
                            'is_active' => 1,
                            'created_at' => now(),
                            'updated_at' => now(),
                        ];

                        if (! $dryRun) {
                            $childItemId = DB::connection('mysql')->table('items')->insertGetId($childData);

                            // BOM 항목은 item_id_mappings에 저장하지 않음
                            // (source_id가 bigint이라 "17:1" 같은 복합키 저장 불가)
                            // 대신 attributes에 source 정보가 있고 entity_relationships로 관계 추적

                            $this->idMappings[$childMappingKey] = $childItemId;

                            // 관계 생성 (BDmodel → BOM item)
                            if ($parentItemId) {
                                DB::connection('mysql')->table('entity_relationships')->insert([
                                    'tenant_id' => $tenantId,
                                    'group_id' => 1,
                                    'parent_type' => 'items',
                                    'parent_id' => $parentItemId,
                                    'child_type' => 'items',
                                    'child_id' => $childItemId,
                                    'order_no' => $orderNo,
                                    'metadata' => json_encode([
                                        'quantity' => $this->parseNumber($bomItem['col8'] ?? '1'),
                                        'relation' => 'bom',
                                        'source' => '5130',
                                    ]),
                                    'created_at' => now(),
                                    'updated_at' => now(),
                                ]);
                            }

                            $bomCount++;
                        }
                    }
                }
            }

            $bar->advance();
        }

        $bar->finish();
        $this->newLine();
        $this->info("BDmodels migration completed (BOM items: {$bomCount})");
    }

    /**
     * 관계 마이그레이션 (entity_relationships)
     */
    private function migrateRelations(int $tenantId, bool $dryRun): void
    {
        $this->info('Migrating relations → entity_relationships...');

        // 1. models ↔ parts 관계
        $this->info('  → models ↔ parts relations...');
        $parts = DB::connection('chandj')->table('parts')
            ->where('is_deleted', 0)
            ->get();

        $relCount = 0;
        foreach ($parts as $part) {
            $parentKey = "models:{$part->model_id}";
            $childKey = "parts:{$part->part_id}";

            if (! isset($this->idMappings[$parentKey]) || ! isset($this->idMappings[$childKey])) {
                continue;
            }

            $exists = DB::connection('mysql')->table('entity_relationships')
                ->where('tenant_id', $tenantId)
                ->where('parent_type', 'items')
                ->where('parent_id', $this->idMappings[$parentKey])
                ->where('child_type', 'items')
                ->where('child_id', $this->idMappings[$childKey])
                ->exists();

            if (! $exists && ! $dryRun) {
                DB::connection('mysql')->table('entity_relationships')->insert([
                    'tenant_id' => $tenantId,
                    'group_id' => 1,
                    'parent_type' => 'items',
                    'parent_id' => $this->idMappings[$parentKey],
                    'child_type' => 'items',
                    'child_id' => $this->idMappings[$childKey],
                    'order_no' => $part->part_id,
                    'metadata' => json_encode([
                        'quantity' => $part->quantity,
                        'relation' => 'bom',
                        'source' => '5130',
                    ]),
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
                $relCount++;
            }
        }
        $this->line("    Created {$relCount} model-part relations");

        // 2. parts ↔ parts_sub 관계
        $this->info('  → parts ↔ parts_sub relations...');
        $partsSub = DB::connection('chandj')->table('parts_sub')
            ->where('is_deleted', 0)
            ->get();

        $relCount = 0;
        foreach ($partsSub as $sub) {
            $parentKey = "parts:{$sub->part_id}";
            $childKey = "parts_sub:{$sub->subpart_id}";

            if (! isset($this->idMappings[$parentKey]) || ! isset($this->idMappings[$childKey])) {
                continue;
            }

            $exists = DB::connection('mysql')->table('entity_relationships')
                ->where('tenant_id', $tenantId)
                ->where('parent_type', 'items')
                ->where('parent_id', $this->idMappings[$parentKey])
                ->where('child_type', 'items')
                ->where('child_id', $this->idMappings[$childKey])
                ->exists();

            if (! $exists && ! $dryRun) {
                DB::connection('mysql')->table('entity_relationships')->insert([
                    'tenant_id' => $tenantId,
                    'group_id' => 1,
                    'parent_type' => 'items',
                    'parent_id' => $this->idMappings[$parentKey],
                    'child_type' => 'items',
                    'child_id' => $this->idMappings[$childKey],
                    'order_no' => $sub->subpart_id,
                    'metadata' => json_encode([
                        'quantity' => $sub->quantity,
                        'relation' => 'bom',
                        'source' => '5130',
                    ]),
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
                $relCount++;
            }
        }
        $this->line("    Created {$relCount} part-subpart relations");

        $this->info('Relations migration completed');
    }

    /**
     * 롤백 (source=5130 데이터 삭제)
     */
    private function rollbackMigration(int $tenantId, bool $dryRun): int
    {
        $this->warn('=== 롤백 모드 ===');

        if (! $this->confirm('5130에서 마이그레이션된 모든 데이터를 삭제하시겠습니까?')) {
            $this->info('롤백 취소됨');

            return self::SUCCESS;
        }

        // 1. entity_relationships 삭제
        $relCount = DB::connection('mysql')->table('entity_relationships')
            ->where('tenant_id', $tenantId)
            ->whereRaw("JSON_EXTRACT(metadata, '$.source') = '5130'")
            ->count();

        if (! $dryRun) {
            DB::connection('mysql')->table('entity_relationships')
                ->where('tenant_id', $tenantId)
                ->whereRaw("JSON_EXTRACT(metadata, '$.source') = '5130'")
                ->delete();
        }
        $this->line("Deleted {$relCount} entity_relationships");

        // 2. items 삭제 (매핑 기반)
        $mappings = DB::connection('mysql')->table('item_id_mappings')->get();
        $itemIds = $mappings->pluck('item_id')->toArray();

        if (! $dryRun && ! empty($itemIds)) {
            DB::connection('mysql')->table('items')
                ->whereIn('id', $itemIds)
                ->delete();
        }
        $this->line('Deleted '.count($itemIds).' items');

        // 3. item_id_mappings 삭제
        if (! $dryRun) {
            DB::connection('mysql')->table('item_id_mappings')->truncate();
        }
        $this->line('Cleared item_id_mappings');

        $this->info('롤백 완료');

        return self::SUCCESS;
    }

    /**
     * 코드 생성
     */
    private function generateCode(string $prefix, ?string $name): string
    {
        if (empty($name)) {
            return $prefix.'-'.Str::random(8);
        }

        // 한글은 유지, 특수문자 제거, 공백→언더스코어
        $code = preg_replace('/[^\p{L}\p{N}\s]/u', '', $name);
        $code = preg_replace('/\s+/', '_', trim($code));
        $code = Str::upper($code);

        return $prefix.'-'.Str::limit($code, 50, '');
    }

    /**
     * 숫자 파싱 (varchar → decimal)
     */
    private function parseNumber(?string $value): ?float
    {
        if (empty($value)) {
            return null;
        }

        $cleaned = preg_replace('/[^\d.-]/', '', $value);

        return is_numeric($cleaned) ? (float) $cleaned : null;
    }

    /**
     * 요약 출력
     */
    private function showSummary(): void
    {
        $this->newLine();
        $this->table(
            ['Source Table', 'Migrated Count'],
            [
                ['models', count(array_filter(array_keys($this->idMappings), fn ($k) => str_starts_with($k, 'models:')))],
                ['parts', count(array_filter(array_keys($this->idMappings), fn ($k) => str_starts_with($k, 'parts:') && ! str_starts_with($k, 'parts_sub:')))],
                ['parts_sub', count(array_filter(array_keys($this->idMappings), fn ($k) => str_starts_with($k, 'parts_sub:')))],
                ['BDmodels', count(array_filter(array_keys($this->idMappings), fn ($k) => str_starts_with($k, 'BDmodels:') && ! str_starts_with($k, 'BDmodels_bom:')))],
                ['BDmodels_bom', count(array_filter(array_keys($this->idMappings), fn ($k) => str_starts_with($k, 'BDmodels_bom:')))],
            ]
        );
    }
}
