<?php

namespace App\Console\Commands;

use App\Models\Documents\Document;
use App\Models\Documents\DocumentData;
use App\Models\Documents\DocumentTemplateSection;
use Illuminate\Console\Attributes\AsCommand;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

#[AsCommand(name: 'documents:normalize-data', description: '기존 document_data의 field_key를 정규화 형식으로 변환')]
class NormalizeDocumentData extends Command
{
    protected $signature = 'documents:normalize-data
                            {--document= : 특정 문서 ID만 처리 (쉼표 구분)}
                            {--dry-run : 실제 변경 없이 시뮬레이션만 수행}
                            {--force : 확인 없이 실행}';

    public function handle(): int
    {
        $dryRun = $this->option('dry-run');
        $documentIds = $this->option('document')
            ? array_map('intval', explode(',', $this->option('document')))
            : null;

        $this->info('=== document_data 정규화 마이그레이션 ===');
        $this->info('Mode: ' . ($dryRun ? 'DRY-RUN (시뮬레이션)' : 'LIVE'));

        if ($documentIds) {
            $this->info('대상 문서: ' . implode(', ', $documentIds));
        }

        $this->newLine();

        // 정규화 대상 레코드 조회: section_id가 NULL이고 field_key가 s{N}_ 패턴인 레코드
        $query = DocumentData::query()
            ->whereNull('section_id')
            ->where(function ($q) {
                // MNG 형식: s{sectionId}_r{rowIndex}_c{colId}...
                $q->where('field_key', 'regexp', '^s[0-9]+_r[0-9]+_c[0-9]+')
                    // React 형식: {itemId}_n{N}, {itemId}_okng_n{N}, {itemId}_result
                    ->orWhere('field_key', 'regexp', '^[0-9]+_(n[0-9]+|okng_n[0-9]+|result)$')
                    // 푸터 형식: footer_remark, footer_judgement
                    ->orWhereIn('field_key', ['footer_remark', 'footer_judgement']);
            });

        if ($documentIds) {
            $query->whereIn('document_id', $documentIds);
        }

        $records = $query->get();

        if ($records->isEmpty()) {
            $this->info('정규화 대상 레코드가 없습니다.');

            return self::SUCCESS;
        }

        $this->info("대상 레코드: {$records->count()}개");

        // 관련 문서 ID 수집 및 템플릿 정보 사전 로드
        $docIds = $records->pluck('document_id')->unique();
        $documents = Document::whereIn('id', $docIds)
            ->with(['template.sections.items', 'template.columns'])
            ->get()
            ->keyBy('id');

        // 변환 결과 집계
        $stats = ['mng' => 0, 'react' => 0, 'footer' => 0, 'skipped' => 0];
        $updates = [];

        foreach ($records as $record) {
            $doc = $documents->get($record->document_id);
            if (! $doc || ! $doc->template) {
                $stats['skipped']++;

                continue;
            }

            $result = $this->normalizeRecord($record, $doc);
            if ($result) {
                $updates[] = $result;
                $stats[$result['type']]++;
            } else {
                $stats['skipped']++;
            }
        }

        // 결과 테이블 출력
        $this->newLine();
        $this->table(
            ['유형', '건수'],
            [
                ['MNG 형식 (s{}_r{}_c{})', $stats['mng']],
                ['React 형식 ({itemId}_*)', $stats['react']],
                ['Footer 형식', $stats['footer']],
                ['건너뜀', $stats['skipped']],
                ['총 변환', count($updates)],
            ]
        );

        if (empty($updates)) {
            $this->info('변환할 레코드가 없습니다.');

            return self::SUCCESS;
        }

        // 변환 상세 샘플
        $this->newLine();
        $this->info('변환 샘플 (최대 10건):');
        $this->table(
            ['ID', 'doc_id', '기존 field_key', '→ section_id', '→ column_id', '→ row_index', '→ field_key'],
            collect($updates)->take(10)->map(fn ($u) => [
                $u['id'],
                $u['document_id'],
                $u['old_field_key'],
                $u['section_id'] ?? 'NULL',
                $u['column_id'] ?? 'NULL',
                $u['row_index'],
                $u['field_key'],
            ])->toArray()
        );

        if ($dryRun) {
            $this->warn('DRY-RUN 모드: 실제 변경 없음. --dry-run 제거하여 실행.');

            return self::SUCCESS;
        }

        // 실행 확인
        if (! $this->option('force') && ! $this->confirm(count($updates) . '건의 레코드를 정규화하시겠습니까?')) {
            $this->info('취소되었습니다.');

            return self::SUCCESS;
        }

        // 트랜잭션으로 일괄 업데이트
        DB::transaction(function () use ($updates) {
            foreach ($updates as $update) {
                DocumentData::where('id', $update['id'])->update([
                    'section_id' => $update['section_id'],
                    'column_id' => $update['column_id'],
                    'row_index' => $update['row_index'],
                    'field_key' => $update['field_key'],
                ]);
            }
        });

        $this->info(count($updates) . '건 정규화 완료.');

        return self::SUCCESS;
    }

    /**
     * 단일 레코드 정규화
     */
    private function normalizeRecord(DocumentData $record, Document $doc): ?array
    {
        $key = $record->field_key;

        // 1. Footer 형식
        if ($key === 'footer_remark') {
            return $this->buildUpdate($record, null, null, 0, 'remark', 'footer');
        }
        if ($key === 'footer_judgement') {
            return $this->buildUpdate($record, null, null, 0, 'overall_result', 'footer');
        }

        // 2. MNG 형식: s{sectionId}_r{rowIndex}_c{colId}[_suffix]
        if (preg_match('/^s(\d+)_r(\d+)_c(\d+)(?:_(.+))?$/', $key, $m)) {
            $sectionId = (int) $m[1];
            $rowIndex = (int) $m[2];
            $columnId = (int) $m[3];
            $suffix = $m[4] ?? null;

            // suffix 정규화: n1, n1_ok, n1_ng, sub0 등은 그대로, 없으면 value
            $fieldKey = $suffix ?: 'value';

            return $this->buildUpdate($record, $sectionId, $columnId, $rowIndex, $fieldKey, 'mng');
        }

        // 3. React 형식: {itemId}_n{N} 또는 {itemId}_okng_n{N} 또는 {itemId}_result
        if (preg_match('/^(\d+)_(n\d+|okng_n\d+|result)$/', $key, $m)) {
            $itemId = (int) $m[1];
            $suffix = $m[2];

            $template = $doc->template;
            $sectionId = null;
            $rowIndex = 0;

            // 아이템 ID로 섹션과 행 인덱스 찾기
            foreach ($template->sections as $section) {
                foreach ($section->items as $idx => $item) {
                    if ($item->id === $itemId) {
                        $sectionId = $section->id;
                        $rowIndex = $idx;
                        break 2;
                    }
                }
            }

            if ($sectionId === null) {
                return null; // 아이템을 찾을 수 없음
            }

            // suffix → 정규화된 field_key
            if ($suffix === 'result') {
                $fieldKey = 'value';
                // 결과 컬럼 ID 찾기
                $resultCol = $template->columns
                    ->first(fn ($c) => in_array($c->column_type, ['select', 'check'])
                        || str_contains($c->label, '판정'));
                $columnId = $resultCol?->id;
            } elseif (str_starts_with($suffix, 'okng_')) {
                // okng_n1 → n1_ok (checked value로 저장된 경우)
                $nPart = str_replace('okng_', '', $suffix);
                $fieldKey = $nPart . '_ok';
                $complexCol = $template->columns->first(fn ($c) => $c->column_type === 'complex');
                $columnId = $complexCol?->id;
            } else {
                // n1, n2, ... 그대로
                $fieldKey = $suffix;
                $complexCol = $template->columns->first(fn ($c) => $c->column_type === 'complex');
                $columnId = $complexCol?->id;
            }

            return $this->buildUpdate($record, $sectionId, $columnId, $rowIndex, $fieldKey, 'react');
        }

        return null;
    }

    private function buildUpdate(
        DocumentData $record,
        ?int $sectionId,
        ?int $columnId,
        int $rowIndex,
        string $fieldKey,
        string $type
    ): array {
        return [
            'id' => $record->id,
            'document_id' => $record->document_id,
            'old_field_key' => $record->field_key,
            'section_id' => $sectionId,
            'column_id' => $columnId,
            'row_index' => $rowIndex,
            'field_key' => $fieldKey,
            'type' => $type,
        ];
    }
}
