<?php

namespace App\Console\Commands;

use App\Models\Items\Item;
use App\Models\Process;
use App\Models\ProcessItem;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

/**
 * 5130 기준 품목-공정 매핑 (A+B+C 전략)
 *
 * A. 품목명 키워드 기반:
 *    - "스크린용", "스크린" → P-002 스크린
 *    - "철재용", "철재", "슬랫" → P-001 슬랫
 *
 * B. BD 코드 기반:
 *    - BD-* → P-003 절곡
 *
 * C. 재고생산(LOT) 기반 (5130 lot 테이블 분석):
 *    - PT-* 코드 → P-004 재고생산
 *    - 가이드레일, 케이스, 연기차단재, L-Bar → P-004 재고생산
 */
class MapItemsToProcesses extends Command
{
    protected $signature = 'items:map-to-processes
                            {--tenant= : 특정 테넌트 ID (기본: 모든 테넌트)}
                            {--dry-run : 실제 실행 없이 미리보기만}
                            {--clear : 기존 매핑 삭제 후 새로 매핑}';

    protected $description = '5130 기준 품목-공정 자동 매핑 (A: 키워드 + B: BD코드 + C: 재고생산)';

    /**
     * 공정별 매핑 규칙 정의
     *
     * 5130 LOT 생산 품목 분류:
     * - R: 가이드레일-벽면형, S: 가이드레일-측면형
     * - C: 케이스 (린텔부, 전면부, 점검구, 후면코너부)
     * - B: 하단마감재-스크린, T: 하단마감재-철재
     * - G: 연기차단재
     * - L: L-Bar
     */
    /**
     * FG(완제품), RM(원자재) 제외 - 공정별 생산 품목만 매핑
     * EST-INSPECTION(검사비), EST-MOTOR/EST-CTRL(구매품)도 제외
     */
    private array $globalExcludes = ['FG-%', 'RM-%', 'EST-INSPECTION'];

    private array $mappingRules = [
        'P-001' => [
            'name' => '슬랫',
            'code_patterns' => ['EST-RAW-슬랫-%'],  // 슬랫 원자재 (방화/방범/조인트바)
            'name_keywords' => ['슬랫'],
            'name_excludes' => ['스크린', '가이드레일', '하단마감', '연기차단', '케이스'],
        ],
        'P-002' => [
            'name' => '스크린',
            'code_patterns' => ['EST-RAW-스크린-%'],  // 스크린 원자재 (실리카/와이어 등)
            'name_keywords' => ['스크린용', '스크린', '원단', '실리카', '방충', '와이어'],
            'name_excludes' => ['가이드레일', '하단마감', '연기차단', '케이스'],
        ],
        'P-003' => [
            'name' => '절곡',
            'code_patterns' => ['BD-%'],  // BD 코드는 절곡
            'name_keywords' => ['절곡', '연기차단재'],  // 연기차단재는 절곡 공정에서 조립
            'name_excludes' => [],
        ],
        'P-004' => [
            'name' => '재고생산',
            'code_patterns' => ['PT-%'],  // PT 코드는 재고생산 부품
            'name_keywords' => ['가이드레일', '케이스', 'L-Bar', 'L-BAR', 'LBar', '하단마감', '린텔', '하장바', '환봉', '감기샤프트', '각파이프', '앵글'],
            'name_excludes' => [],
            'code_excludes' => ['BD-%', 'EST-SMOKE-%'],  // BD는 P-003, EST-SMOKE는 P-003
        ],
    ];

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

        $this->info('=== 5130 기준 품목-공정 매핑 (A+B+C 전략) ===');
        $this->info('A. 품목명 키워드: 스크린용→P-002, 철재용→P-001');
        $this->info('B. BD 코드: BD-* → P-003 절곡');
        $this->info('C. 재고생산: PT-* 또는 가이드레일/케이스/연기차단재/L-Bar → P-004');
        $this->newLine();

        // 공정 조회
        $processQuery = Process::query();
        if ($tenantId) {
            $processQuery->where('tenant_id', $tenantId);
        }
        $processes = $processQuery->whereIn('process_code', array_keys($this->mappingRules))->get()->keyBy('process_code');

        if ($processes->isEmpty()) {
            $this->error('매핑 대상 공정이 없습니다. (P-001, P-002, P-003, P-004)');

            return self::FAILURE;
        }

        $this->info('대상 공정:');
        foreach ($processes as $code => $process) {
            $this->line("  - {$code}: {$process->process_name} (ID: {$process->id})");
        }
        $this->newLine();

        // 기존 매핑 삭제 (--clear 옵션)
        if ($clear) {
            $processIds = $processes->pluck('id')->toArray();
            $existingCount = ProcessItem::whereIn('process_id', $processIds)->count();

            if ($dryRun) {
                $this->warn("[DRY-RUN] 기존 매핑 {$existingCount}개 삭제 예정");
            } else {
                ProcessItem::whereIn('process_id', $processIds)->delete();
                $this->warn("기존 매핑 {$existingCount}개 삭제 완료");
            }
            $this->newLine();
        }

        // 매핑 결과 저장
        $results = [
            'P-001' => ['items' => collect(), 'process' => $processes->get('P-001')],
            'P-002' => ['items' => collect(), 'process' => $processes->get('P-002')],
            'P-003' => ['items' => collect(), 'process' => $processes->get('P-003')],
            'P-004' => ['items' => collect(), 'process' => $processes->get('P-004')],
        ];

        // 품목 조회 및 분류
        $itemQuery = Item::query();
        if ($tenantId) {
            $itemQuery->where('tenant_id', $tenantId);
        }
        $items = $itemQuery->get();

        $this->info("전체 품목 수: {$items->count()}개");
        $this->newLine();

        $mappedCount = 0;
        $unmappedItems = collect();

        foreach ($items as $item) {
            $processCode = $this->classifyItem($item);

            if ($processCode && isset($results[$processCode])) {
                $results[$processCode]['items']->push($item);
                $mappedCount++;
            } else {
                $unmappedItems->push($item);
            }
        }

        // 결과 출력
        $this->info('=== 분류 결과 ===');
        $this->newLine();

        $tableData = [];
        foreach ($results as $code => $data) {
            $count = $data['items']->count();
            $processName = $data['process']?->process_name ?? '(없음)';
            $tableData[] = [$code, $processName, $count];
        }
        $tableData[] = ['-', '미분류', $unmappedItems->count()];
        $tableData[] = ['=', '합계', $items->count()];

        $this->table(['공정코드', '공정명', '품목 수'], $tableData);
        $this->newLine();

        // 샘플 출력
        foreach ($results as $code => $data) {
            if ($data['items']->isNotEmpty()) {
                $this->info("[{$code} {$data['process']?->process_name}] 샘플 (최대 10개):");
                foreach ($data['items']->take(10) as $item) {
                    $this->line("  - {$item->code}: {$item->name}");
                }
                $this->newLine();
            }
        }

        // 미분류 샘플
        if ($unmappedItems->isNotEmpty()) {
            $this->info('[미분류] 샘플 (최대 10개):');
            foreach ($unmappedItems->take(10) as $item) {
                $this->line("  - {$item->code}: {$item->name}");
            }
            $this->newLine();
        }

        // 실제 매핑 실행
        if (! $dryRun) {
            $this->info('=== 매핑 실행 ===');

            DB::transaction(function () use ($results) {
                foreach ($results as $code => $data) {
                    $process = $data['process'];
                    if (! $process) {
                        continue;
                    }

                    $priority = 0;
                    foreach ($data['items'] as $item) {
                        // 중복 체크
                        $exists = ProcessItem::where('process_id', $process->id)
                            ->where('item_id', $item->id)
                            ->exists();

                        if (! $exists) {
                            ProcessItem::create([
                                'process_id' => $process->id,
                                'item_id' => $item->id,
                                'priority' => $priority++,
                                'is_active' => true,
                            ]);
                        }
                    }

                    $this->info("  {$code}: {$data['items']->count()}개 매핑 완료");
                }
            });

            $this->newLine();
            $this->info("총 {$mappedCount}개 품목 매핑 완료!");
        } else {
            $this->newLine();
            $this->warn('[DRY-RUN] 실제 매핑은 수행되지 않았습니다.');
            $this->line('실제 실행: php artisan items:map-to-processes --clear');
        }

        return self::SUCCESS;
    }

    /**
     * 품목을 공정에 분류 (A+B+C 전략)
     */
    private function classifyItem(Item $item): ?string
    {
        $code = $item->code ?? '';
        $name = $item->name ?? '';

        // 0. 글로벌 제외 (FG 완제품, RM 원자재, EST-INSPECTION 서비스)
        foreach ($this->globalExcludes as $excludePattern) {
            $prefix = rtrim($excludePattern, '-%');
            if (str_starts_with($code, $prefix)) {
                return null;
            }
        }

        // 1. 코드 패턴 우선 매핑 (정확한 매칭)
        // EST-RAW-슬랫-* → P-001
        if (str_starts_with($code, 'EST-RAW-슬랫-')) {
            return 'P-001';
        }

        // EST-RAW-스크린-* → P-002
        if (str_starts_with($code, 'EST-RAW-스크린-')) {
            return 'P-002';
        }

        // BD-* → P-003 절곡
        if (str_starts_with($code, 'BD-')) {
            return 'P-003';
        }

        // EST-SMOKE-* → P-003 절곡 (연기차단재는 절곡 공정에서 조립)
        if (str_starts_with($code, 'EST-SMOKE-')) {
            return 'P-003';
        }

        // PT-* → P-004 재고생산
        if (str_starts_with($code, 'PT-')) {
            return 'P-004';
        }

        // EST-MOTOR/EST-CTRL → 구매품, 공정 없음
        if (str_starts_with($code, 'EST-MOTOR-') || str_starts_with($code, 'EST-CTRL-')) {
            return null;
        }

        // EST-SHAFT/EST-PIPE/EST-ANGLE → P-004 재고생산 (조달 품목)
        if (str_starts_with($code, 'EST-SHAFT-') || str_starts_with($code, 'EST-PIPE-') || str_starts_with($code, 'EST-ANGLE-')) {
            return 'P-004';
        }

        // 2. P-004 재고생산 키워드 체크
        foreach ($this->mappingRules['P-004']['name_keywords'] as $keyword) {
            if (mb_stripos($name, $keyword) !== false) {
                // code_excludes 체크
                $excluded = false;
                foreach ($this->mappingRules['P-004']['code_excludes'] ?? [] as $excludePattern) {
                    $prefix = rtrim($excludePattern, '-%');
                    if (str_starts_with($code, $prefix)) {
                        $excluded = true;
                        break;
                    }
                }
                if (! $excluded) {
                    return 'P-004';
                }
            }
        }

        // 3. P-003 절곡 키워드 체크
        foreach ($this->mappingRules['P-003']['name_keywords'] as $keyword) {
            if (mb_stripos($name, $keyword) !== false) {
                return 'P-003';
            }
        }

        // 4. P-002 스크린 키워드 체크
        foreach ($this->mappingRules['P-002']['name_keywords'] as $keyword) {
            if (mb_stripos($name, $keyword) !== false) {
                $excluded = false;
                foreach ($this->mappingRules['P-002']['name_excludes'] as $exclude) {
                    if (mb_stripos($name, $exclude) !== false) {
                        $excluded = true;
                        break;
                    }
                }
                if (! $excluded) {
                    return 'P-002';
                }
            }
        }

        // 5. P-001 슬랫 키워드 체크
        foreach ($this->mappingRules['P-001']['name_keywords'] as $keyword) {
            if (mb_stripos($name, $keyword) !== false) {
                $excluded = false;
                foreach ($this->mappingRules['P-001']['name_excludes'] as $exclude) {
                    if (mb_stripos($name, $exclude) !== false) {
                        $excluded = true;
                        break;
                    }
                }
                if (! $excluded) {
                    return 'P-001';
                }
            }
        }

        return null;
    }
}
