<?php

namespace App\Console\Commands;

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

#[AsCommand(name: 'migrate:5130-bending-stock', description: '5130 레거시 절곡품 코드 생성 + BD-* 전체 품목 초기 재고 셋팅')]
class Migrate5130BendingStock extends Command
{
    protected $signature = 'migrate:5130-bending-stock
                            {--tenant_id=287 : Target tenant ID (default: 287 경동기업)}
                            {--dry-run : 실제 저장 없이 시뮬레이션만 수행}
                            {--min-stock=100 : 품목별 초기 재고 수량 (기본: 100)}
                            {--rollback : 초기 재고 셋팅 롤백 (init_stock 소스 데이터 삭제)}';

    private string $sourceDb = 'chandj';

    private string $targetDb = 'mysql';

    // 5130 prod 코드 → 한글명
    private array $prodNames = [
        'R' => '가이드레일(벽면)', 'S' => '가이드레일(측면)',
        'G' => '연기차단재', 'B' => '하단마감재(스크린)',
        'T' => '하단마감재(철재)', 'L' => 'L-Bar', 'C' => '케이스',
    ];

    // 5130 spec 코드 → 한글명
    private array $specNames = [
        'I' => '화이바원단', 'S' => 'SUS', 'U' => 'SUS2', 'E' => 'EGI',
        'A' => '스크린용', 'D' => 'D형', 'C' => 'C형', 'M' => '본체',
        'T' => '본체(철재)', 'B' => '후면코너부', 'L' => '린텔부',
        'P' => '점검구', 'F' => '전면부',
    ];

    // 5130 slength 코드 → 한글명
    private array $slengthNames = [
        '53' => 'W50×3000', '54' => 'W50×4000', '83' => 'W80×3000',
        '84' => 'W80×4000', '12' => '1219mm', '24' => '2438mm',
        '30' => '3000mm', '35' => '3500mm', '40' => '4000mm',
        '41' => '4150mm', '42' => '4200mm', '43' => '4300mm',
    ];

    private array $stats = [
        'items_found' => 0,
        'items_created_5130' => 0,
        'items_category_updated' => 0,
        'stocks_created' => 0,
        'stocks_skipped' => 0,
        'lots_created' => 0,
        'transactions_created' => 0,
    ];

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

        $this->info('=== BD-* 절곡품 초기 재고 셋팅 ===');
        $this->info("Tenant ID: {$tenantId}");
        $this->info('Mode: '.($dryRun ? 'DRY-RUN (시뮬레이션)' : 'LIVE'));
        $this->info("초기 재고: {$minStock}개/품목");
        $this->newLine();

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

        // 0. 5130 레거시 데이터에서 BD-{PROD}{SPEC}-{SLENGTH} 아이템 생성
        $this->info('📥 Step 0: 5130 레거시 코드 → BD 아이템 생성...');
        $this->createLegacyItems($tenantId, $dryRun);
        $this->newLine();

        // 1. 전체 BD-* 아이템 조회 (기존 58개 + 5130 생성분)
        $this->info('📥 Step 1: BD-* 절곡품 품목 조회...');
        $items = DB::connection($this->targetDb)
            ->table('items')
            ->where('tenant_id', $tenantId)
            ->where('code', 'like', 'BD-%')
            ->whereNull('deleted_at')
            ->select('id', 'code', 'name', 'item_type', 'item_category', 'unit', 'options')
            ->orderBy('code')
            ->get();

        $this->stats['items_found'] = $items->count();
        $this->info("  - BD-* 품목: {$items->count()}건");

        if ($items->isEmpty()) {
            $this->warn('BD-* 품목이 없습니다. 종료합니다.');

            return self::SUCCESS;
        }

        // 2. item_category 미설정 품목 업데이트
        $this->newLine();
        $this->info('🏷️ Step 2: item_category 업데이트...');
        $needsCategoryUpdate = $items->filter(fn ($item) => $item->item_category !== 'BENDING');

        if ($needsCategoryUpdate->isNotEmpty()) {
            $this->info("  - item_category 미설정/불일치: {$needsCategoryUpdate->count()}건");
            if (! $dryRun) {
                DB::connection($this->targetDb)
                    ->table('items')
                    ->where('tenant_id', $tenantId)
                    ->where('code', 'like', 'BD-%')
                    ->whereNull('deleted_at')
                    ->where(function ($q) {
                        $q->whereNull('item_category')
                            ->orWhere('item_category', '!=', 'BENDING');
                    })
                    ->update(['item_category' => 'BENDING', 'updated_at' => now()]);
            }
            $this->stats['items_category_updated'] = $needsCategoryUpdate->count();
        } else {
            $this->info('  - 모든 품목 BENDING 카테고리 설정 완료');
        }

        // 3. 현재 재고 현황 표시
        $this->newLine();
        $this->info('📊 Step 3: 현재 재고 현황...');
        $this->showCurrentStockStatus($tenantId, $items);

        // 4. 재고 셋팅 대상 확인
        $this->newLine();
        $this->info('📦 Step 4: 재고 셋팅 대상 확인...');
        $itemsNeedingStock = $this->getItemsNeedingStock($tenantId, $items, $minStock);

        if ($itemsNeedingStock->isEmpty()) {
            $this->info("  - 모든 품목이 이미 {$minStock}개 이상 재고 보유. 추가 작업 불필요.");
            $this->showStats();

            return self::SUCCESS;
        }

        $this->info("  - 재고 셋팅 필요: {$itemsNeedingStock->count()}건");
        $this->table(
            ['코드', '품목명', '현재고', '목표', '추가수량'],
            $itemsNeedingStock->map(fn ($item) => [
                $item->code,
                mb_strlen($item->name) > 30 ? mb_substr($item->name, 0, 30).'...' : $item->name,
                number_format($item->current_qty),
                number_format($minStock),
                number_format($item->supplement_qty),
            ])->toArray()
        );

        if ($dryRun) {
            $this->stats['stocks_created'] = $itemsNeedingStock->filter(fn ($i) => ! $i->has_stock)->count();
            $this->stats['lots_created'] = $itemsNeedingStock->count();
            $this->stats['transactions_created'] = $itemsNeedingStock->count();
            $this->showStats();
            $this->info('🔍 DRY RUN 완료. 실제 실행은 --dry-run 플래그를 제거하세요.');

            return self::SUCCESS;
        }

        if (! $this->confirm('초기 재고를 셋팅하시겠습니까?')) {
            $this->info('취소되었습니다.');

            return self::SUCCESS;
        }

        // 5. 실행
        $this->newLine();
        $this->info('🚀 Step 5: 초기 재고 셋팅 실행...');
        DB::connection($this->targetDb)->transaction(function () use ($tenantId, $itemsNeedingStock, $minStock) {
            $this->executeStockSetup($tenantId, $itemsNeedingStock, $minStock);
        });

        $this->newLine();
        $this->showStats();
        $this->info('✅ 초기 재고 셋팅 완료!');

        return self::SUCCESS;
    }

    /**
     * 현재 재고 현황 표시
     */
    private function showCurrentStockStatus(int $tenantId, \Illuminate\Support\Collection $items): void
    {
        $itemIds = $items->pluck('id');

        $stocks = DB::connection($this->targetDb)
            ->table('stocks')
            ->where('tenant_id', $tenantId)
            ->whereIn('item_id', $itemIds)
            ->whereNull('deleted_at')
            ->get()
            ->keyBy('item_id');

        $hasStock = 0;
        $noStock = 0;

        foreach ($items as $item) {
            $stock = $stocks->get($item->id);
            if ($stock && (float) $stock->stock_qty > 0) {
                $hasStock++;
            } else {
                $noStock++;
            }
        }

        $this->info("  - 재고 있음: {$hasStock}건");
        $this->info("  - 재고 없음: {$noStock}건");
    }

    /**
     * 재고 셋팅이 필요한 품목 목록 조회
     */
    private function getItemsNeedingStock(int $tenantId, \Illuminate\Support\Collection $items, int $minStock): \Illuminate\Support\Collection
    {
        $itemIds = $items->pluck('id');

        $stocks = DB::connection($this->targetDb)
            ->table('stocks')
            ->where('tenant_id', $tenantId)
            ->whereIn('item_id', $itemIds)
            ->whereNull('deleted_at')
            ->get()
            ->keyBy('item_id');

        $result = collect();

        foreach ($items as $item) {
            $stock = $stocks->get($item->id);
            $currentQty = $stock ? (float) $stock->stock_qty : 0;

            if ($currentQty >= $minStock) {
                $this->stats['stocks_skipped']++;

                continue;
            }

            $supplementQty = $minStock - $currentQty;

            $item->has_stock = (bool) $stock;
            $item->stock_id = $stock?->id;
            $item->current_qty = $currentQty;
            $item->supplement_qty = $supplementQty;

            $result->push($item);
        }

        return $result;
    }

    /**
     * 초기 재고 셋팅 실행
     */
    private function executeStockSetup(int $tenantId, \Illuminate\Support\Collection $items, int $minStock): void
    {
        foreach ($items as $item) {
            $stockId = $item->stock_id;

            // Stock 레코드가 없으면 생성
            if (! $item->has_stock) {
                $stockId = DB::connection($this->targetDb)->table('stocks')->insertGetId([
                    'tenant_id' => $tenantId,
                    'item_id' => $item->id,
                    'item_code' => $item->code,
                    'item_name' => $item->name,
                    'item_type' => 'bent_part',
                    'unit' => $item->unit ?? 'EA',
                    'stock_qty' => 0,
                    'safety_stock' => 0,
                    'reserved_qty' => 0,
                    'available_qty' => 0,
                    'lot_count' => 0,
                    'status' => 'out',
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
                $this->stats['stocks_created']++;
                $this->line("  + Stock 생성: {$item->code}");
            }

            // FIFO 순서 계산
            $maxFifo = DB::connection($this->targetDb)
                ->table('stock_lots')
                ->where('stock_id', $stockId)
                ->max('fifo_order');
            $nextFifo = ($maxFifo ?? 0) + 1;

            // LOT 번호 생성
            $lotNo = 'INIT-'.now()->format('ymd').'-'.str_replace(['-', ' ', '*'], ['', '', 'x'], $item->code);

            // 중복 체크
            $existingLot = DB::connection($this->targetDb)
                ->table('stock_lots')
                ->where('tenant_id', $tenantId)
                ->where('stock_id', $stockId)
                ->where('lot_no', $lotNo)
                ->whereNull('deleted_at')
                ->first();

            if ($existingLot) {
                $this->warn("  ⚠️ 이미 LOT 존재 (skip): {$lotNo}");

                continue;
            }

            $supplementQty = $item->supplement_qty;

            // StockLot 생성
            $stockLotId = DB::connection($this->targetDb)->table('stock_lots')->insertGetId([
                'tenant_id' => $tenantId,
                'stock_id' => $stockId,
                'lot_no' => $lotNo,
                'fifo_order' => $nextFifo,
                'receipt_date' => now()->toDateString(),
                'qty' => $supplementQty,
                'reserved_qty' => 0,
                'available_qty' => $supplementQty,
                'unit' => $item->unit ?? 'EA',
                'status' => 'available',
                'created_at' => now(),
                'updated_at' => now(),
            ]);
            $this->stats['lots_created']++;

            // StockTransaction 생성
            DB::connection($this->targetDb)->table('stock_transactions')->insert([
                'tenant_id' => $tenantId,
                'stock_id' => $stockId,
                'stock_lot_id' => $stockLotId,
                'type' => 'IN',
                'qty' => $supplementQty,
                'balance_qty' => 0,
                'reference_type' => 'init_stock',
                'reference_id' => 0,
                'lot_no' => $lotNo,
                'reason' => 'receiving',
                'remark' => "절곡품 초기 재고 셋팅 (min-stock={$minStock})",
                'item_code' => $item->code,
                'item_name' => $item->name,
                'created_at' => now(),
            ]);
            $this->stats['transactions_created']++;

            // Stock 집계 갱신
            $this->refreshStockFromLots($stockId, $tenantId);

            $this->line("  ✅ {$item->code}: 0 → {$supplementQty} (+{$supplementQty})");
        }
    }

    /**
     * Stock 집계 갱신 (LOT 기반)
     */
    private function refreshStockFromLots(int $stockId, int $tenantId): void
    {
        $lotStats = DB::connection($this->targetDb)
            ->table('stock_lots')
            ->where('stock_id', $stockId)
            ->where('tenant_id', $tenantId)
            ->whereNull('deleted_at')
            ->selectRaw('
                COALESCE(SUM(qty), 0) as total_qty,
                COALESCE(SUM(reserved_qty), 0) as total_reserved,
                COALESCE(SUM(available_qty), 0) as total_available,
                COUNT(*) as lot_count,
                MIN(receipt_date) as oldest_lot_date,
                MAX(receipt_date) as latest_receipt_date
            ')
            ->first();

        $stockQty = (float) $lotStats->total_qty;

        DB::connection($this->targetDb)
            ->table('stocks')
            ->where('id', $stockId)
            ->update([
                'stock_qty' => $stockQty,
                'reserved_qty' => (float) $lotStats->total_reserved,
                'available_qty' => (float) $lotStats->total_available,
                'lot_count' => (int) $lotStats->lot_count,
                'oldest_lot_date' => $lotStats->oldest_lot_date,
                'last_receipt_date' => $lotStats->latest_receipt_date,
                'status' => $stockQty > 0 ? 'normal' : 'out',
                'updated_at' => now(),
            ]);
    }

    /**
     * 롤백: init_stock 참조 데이터 삭제
     */
    private function rollbackInitStock(int $tenantId, bool $dryRun): int
    {
        $this->warn('⚠️ 롤백: 초기 재고 셋팅 데이터를 삭제합니다.');

        // init_stock으로 생성된 트랜잭션
        $txCount = DB::connection($this->targetDb)
            ->table('stock_transactions')
            ->where('tenant_id', $tenantId)
            ->where('reference_type', 'init_stock')
            ->count();

        // init_stock 트랜잭션에 연결된 LOT
        $lotIds = DB::connection($this->targetDb)
            ->table('stock_transactions')
            ->where('tenant_id', $tenantId)
            ->where('reference_type', 'init_stock')
            ->whereNotNull('stock_lot_id')
            ->pluck('stock_lot_id')
            ->unique();

        // 5130으로 생성된 아이템
        $legacyItemCount = DB::connection($this->targetDb)
            ->table('items')
            ->where('tenant_id', $tenantId)
            ->where('options->source', '5130_migration')
            ->whereNull('deleted_at')
            ->count();

        $this->info('  삭제 대상:');
        $this->info("  - stock_transactions (reference_type=init_stock): {$txCount}건");
        $this->info("  - stock_lots (연결 LOT): {$lotIds->count()}건");
        $this->info("  - items (source=5130_migration): {$legacyItemCount}건");

        if ($dryRun) {
            $this->info('DRY RUN - 실제 삭제 없음');

            return self::SUCCESS;
        }

        if (! $this->confirm('정말 롤백하시겠습니까? 되돌릴 수 없습니다.')) {
            return self::SUCCESS;
        }

        DB::connection($this->targetDb)->transaction(function () use ($tenantId, $lotIds) {
            // 1. 트랜잭션 삭제
            DB::connection($this->targetDb)
                ->table('stock_transactions')
                ->where('tenant_id', $tenantId)
                ->where('reference_type', 'init_stock')
                ->delete();

            // 2. LOT에서 stock_id 목록 수집 (집계 갱신용)
            $affectedStockIds = collect();
            if ($lotIds->isNotEmpty()) {
                $affectedStockIds = DB::connection($this->targetDb)
                    ->table('stock_lots')
                    ->whereIn('id', $lotIds)
                    ->pluck('stock_id')
                    ->unique();

                // LOT 삭제
                DB::connection($this->targetDb)
                    ->table('stock_lots')
                    ->whereIn('id', $lotIds)
                    ->delete();
            }

            // 3. 영향받은 Stock 집계 갱신
            foreach ($affectedStockIds as $stockId) {
                $this->refreshStockFromLots($stockId, $tenantId);
            }

            // 4. 5130 migration으로 생성된 아이템 + 연결 stocks 삭제
            $migrationItemIds = DB::connection($this->targetDb)
                ->table('items')
                ->where('tenant_id', $tenantId)
                ->where('options->source', '5130_migration')
                ->whereNull('deleted_at')
                ->pluck('id');

            if ($migrationItemIds->isNotEmpty()) {
                $migrationStockIds = DB::connection($this->targetDb)
                    ->table('stocks')
                    ->where('tenant_id', $tenantId)
                    ->whereIn('item_id', $migrationItemIds)
                    ->pluck('id');

                if ($migrationStockIds->isNotEmpty()) {
                    DB::connection($this->targetDb)
                        ->table('stock_lots')
                        ->whereIn('stock_id', $migrationStockIds)
                        ->delete();

                    DB::connection($this->targetDb)
                        ->table('stocks')
                        ->whereIn('id', $migrationStockIds)
                        ->delete();
                }

                DB::connection($this->targetDb)
                    ->table('items')
                    ->whereIn('id', $migrationItemIds)
                    ->delete();
            }
        });

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

        return self::SUCCESS;
    }

    /**
     * 5130 레거시 데이터에서 BD-{PROD}{SPEC}-{SLENGTH} 아이템 생성
     */
    private function createLegacyItems(int $tenantId, bool $dryRun): void
    {
        // 5130 lot 테이블에서 고유 prod+spec+slength 조합 추출
        $lots = DB::connection($this->sourceDb)
            ->table('lot')
            ->where(function ($q) {
                $q->whereNull('is_deleted')
                    ->orWhere('is_deleted', 0);
            })
            ->whereNotNull('prod')
            ->where('prod', '!=', '')
            ->whereNotNull('surang')
            ->where('surang', '>', 0)
            ->select('prod', 'spec', 'slength')
            ->distinct()
            ->get();

        // bending_work_log 테이블에서도 추출 (lot에 없는 조합 포함)
        $workLogs = DB::connection($this->sourceDb)
            ->table('bending_work_log')
            ->where(function ($q) {
                $q->whereNull('is_deleted')
                    ->orWhere('is_deleted', 0);
            })
            ->whereNotNull('prod_code')
            ->where('prod_code', '!=', '')
            ->select('prod_code as prod', 'spec_code as spec', 'slength_code as slength')
            ->distinct()
            ->get();

        $allRecords = $lots->merge($workLogs);

        if ($allRecords->isEmpty()) {
            $this->info('  - 5130 데이터 없음');

            return;
        }

        // 고유 제품 조합 추출
        $uniqueProducts = [];
        foreach ($allRecords as $row) {
            $key = trim($row->prod).'-'.trim($row->spec ?? '').'-'.trim($row->slength ?? '');
            if (! isset($uniqueProducts[$key])) {
                $uniqueProducts[$key] = [
                    'prod' => trim($row->prod),
                    'spec' => trim($row->spec ?? ''),
                    'slength' => trim($row->slength ?? ''),
                ];
            }
        }

        $this->info("  - 5130 고유 제품 조합: ".count($uniqueProducts).'개');

        $created = 0;
        $skipped = 0;

        foreach ($uniqueProducts as $data) {
            $itemCode = "BD-{$data['prod']}{$data['spec']}-{$data['slength']}";
            $prodName = $this->prodNames[$data['prod']] ?? $data['prod'];
            $specName = $this->specNames[$data['spec']] ?? $data['spec'];
            $slengthName = $this->slengthNames[$data['slength']] ?? $data['slength'];
            $itemName = implode(' ', array_filter([$prodName, $specName, $slengthName]));

            // 이미 존재하는지 확인
            $existing = DB::connection($this->targetDb)
                ->table('items')
                ->where('tenant_id', $tenantId)
                ->where('code', $itemCode)
                ->whereNull('deleted_at')
                ->first();

            if ($existing) {
                $skipped++;

                continue;
            }

            if (! $dryRun) {
                DB::connection($this->targetDb)->table('items')->insert([
                    'tenant_id' => $tenantId,
                    'code' => $itemCode,
                    'name' => $itemName,
                    'item_type' => 'PT',
                    'item_category' => 'BENDING',
                    'unit' => 'EA',
                    'options' => json_encode([
                        'source' => '5130_migration',
                        'lot_managed' => true,
                        'consumption_method' => 'auto',
                        'production_source' => 'self_produced',
                        'input_tracking' => true,
                        'legacy_prod' => $data['prod'],
                        'legacy_spec' => $data['spec'],
                        'legacy_slength' => $data['slength'],
                    ]),
                    'is_active' => true,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
            }

            $created++;
        }

        $this->stats['items_created_5130'] = $created;
        $this->info("  - 신규 생성: {$created}건, 기존 존재 (skip): {$skipped}건");
    }

    /**
     * 통계 출력
     */
    private function showStats(): void
    {
        $this->newLine();
        $this->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
        $this->info('📊 실행 통계');
        $this->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
        $this->info("  5130 아이템 생성: {$this->stats['items_created_5130']}건");
        $this->info("  BD-* 품목 수 (전체): {$this->stats['items_found']}건");
        $this->info("  카테고리 업데이트: {$this->stats['items_category_updated']}건");
        $this->info("  Stock 레코드 생성: {$this->stats['stocks_created']}건");
        $this->info("  기존 재고 충분 (skip): {$this->stats['stocks_skipped']}건");
        $this->info("  StockLot 생성: {$this->stats['lots_created']}건");
        $this->info("  입고 트랜잭션: {$this->stats['transactions_created']}건");
        $this->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
    }
}