<?php

namespace App\Services;

use App\Models\ItemField;
use App\Models\SystemFieldDefinition;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;

/**
 * 품목기준 필드 시딩 서비스
 *
 * 테넌트별 시스템 필드 시딩 및 커스텀 필드 관리
 * DB 기반 시스템 필드 정의 사용 (system_field_definitions 테이블)
 */
class ItemFieldSeedingService
{
    /**
     * 최근 오류 목록 (세션 저장용)
     */
    protected array $errors = [];

    /**
     * 테이블별 시딩 상태 조회
     */
    public function getSeedingStatus(int $tenantId): array
    {
        $statuses = [];

        $sourceTables = SystemFieldDefinition::getSourceTableOptions();

        foreach ($sourceTables as $sourceTable => $label) {
            $totalCount = SystemFieldDefinition::getFieldCountFor($sourceTable);

            // 현재 등록된 시스템 필드 수
            $currentCount = ItemField::where('tenant_id', $tenantId)
                ->where('source_table', $sourceTable)
                ->where('storage_type', 'column')
                ->count();

            $statuses[$sourceTable] = [
                'label' => $label,
                'source_table' => $sourceTable,
                'total_count' => $totalCount,
                'current_count' => $currentCount,
                'is_complete' => $currentCount >= $totalCount,
                'status' => $currentCount >= $totalCount ? 'complete' : ($currentCount > 0 ? 'partial' : 'empty'),
            ];
        }

        return $statuses;
    }

    /**
     * 특정 소스 테이블의 시딩 가능한 필드 목록 조회
     *
     * @param  bool  $onlyDefault  true면 기본 시딩 대상만, false면 전체
     */
    public function getAvailableFields(string $sourceTable, bool $onlyDefault = false): Collection
    {
        if ($onlyDefault) {
            return SystemFieldDefinition::getSeedDefaultFieldsFor($sourceTable);
        }

        return SystemFieldDefinition::getFieldsFor($sourceTable);
    }

    /**
     * 단일 테이블 시스템 필드 시딩
     *
     * @param  array|null  $fieldIds  시딩할 필드 ID 목록 (null이면 is_seed_default=true인 것만)
     */
    public function seedTable(int $tenantId, string $sourceTable, ?array $fieldIds = null): array
    {
        // 필드 ID가 지정되면 해당 필드만, 아니면 기본 시딩 대상만
        if ($fieldIds !== null) {
            $fields = SystemFieldDefinition::whereIn('id', $fieldIds)
                ->where('source_table', $sourceTable)
                ->where('is_active', true)
                ->orderBy('order_no')
                ->get();
        } else {
            $fields = SystemFieldDefinition::getSeedDefaultFieldsFor($sourceTable);
        }

        if ($fields->isEmpty()) {
            return [
                'success' => false,
                'message' => '시딩할 필드가 없습니다.',
                'seeded_count' => 0,
            ];
        }

        $seededCount = 0;
        $skippedCount = 0;
        $errorCount = 0;
        $this->errors = [];

        foreach ($fields as $fieldDef) {
            try {
                // 이미 존재하는지 확인 (field_key + source_table 조합)
                $exists = ItemField::where('tenant_id', $tenantId)
                    ->where('source_table', $sourceTable)
                    ->where('field_key', $fieldDef->field_key)
                    ->exists();

                if ($exists) {
                    $skippedCount++;

                    continue;
                }

                // DB 유니크 제약조건 충돌 방지: tenant_id + field_key 조합 체크
                $existsGlobal = ItemField::where('tenant_id', $tenantId)
                    ->where('field_key', $fieldDef->field_key)
                    ->exists();

                if ($existsGlobal) {
                    // 다른 source_table에 같은 field_key가 있으면 고유한 키로 변환
                    $fieldKey = "{$sourceTable}_{$fieldDef->field_key}";

                    // 변환된 키도 이미 존재하는지 확인
                    $existsTransformed = ItemField::where('tenant_id', $tenantId)
                        ->where('field_key', $fieldKey)
                        ->exists();

                    if ($existsTransformed) {
                        $skippedCount++;

                        continue;
                    }
                } else {
                    $fieldKey = $fieldDef->field_key;
                }

                // 필드 생성
                ItemField::create([
                    'tenant_id' => $tenantId,
                    'group_id' => 1, // 품목관리 그룹
                    'field_key' => $fieldKey,
                    'field_name' => $fieldDef->field_name,
                    'field_type' => $fieldDef->field_type,
                    'order_no' => $fieldDef->order_no ?? 0,
                    'is_required' => $fieldDef->is_required ?? false,
                    'default_value' => $fieldDef->default_value ?? null,
                    'options' => $fieldDef->options ?? null,
                    'source_table' => $sourceTable,
                    'source_column' => $fieldDef->field_key, // 원본 컬럼명 유지
                    'storage_type' => 'column',
                    'is_active' => true,
                    'is_common' => true,
                    'created_by' => auth()->id(),
                ]);

                $seededCount++;

            } catch (\Illuminate\Database\QueryException $e) {
                $errorCount++;
                $errorInfo = [
                    'field_key' => $fieldDef->field_key,
                    'field_name' => $fieldDef->field_name,
                    'source_table' => $sourceTable,
                    'error_code' => $e->getCode(),
                    'error_message' => $e->getMessage(),
                    'sql_state' => $e->errorInfo[0] ?? null,
                    'timestamp' => now()->toDateTimeString(),
                ];
                $this->errors[] = $errorInfo;

                Log::error('ItemField 시딩 오류', [
                    'tenant_id' => $tenantId,
                    'source_table' => $sourceTable,
                    'field_key' => $fieldDef->field_key,
                    'error' => $e->getMessage(),
                ]);
            } catch (\Exception $e) {
                $errorCount++;
                $this->errors[] = [
                    'field_key' => $fieldDef->field_key,
                    'field_name' => $fieldDef->field_name,
                    'source_table' => $sourceTable,
                    'error_code' => 'UNKNOWN',
                    'error_message' => $e->getMessage(),
                    'timestamp' => now()->toDateTimeString(),
                ];

                Log::error('ItemField 시딩 예외', [
                    'tenant_id' => $tenantId,
                    'source_table' => $sourceTable,
                    'field_key' => $fieldDef->field_key,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        // 오류가 있으면 세션에 저장
        if (! empty($this->errors)) {
            $this->saveErrorsToSession($tenantId, $sourceTable);
        }

        $success = $errorCount === 0;
        $message = $success
            ? "시딩 완료: {$seededCount}개 추가, {$skippedCount}개 건너뜀"
            : "시딩 부분 완료: {$seededCount}개 추가, {$skippedCount}개 건너뜀, {$errorCount}개 오류";

        return [
            'success' => $success,
            'message' => $message,
            'seeded_count' => $seededCount,
            'skipped_count' => $skippedCount,
            'error_count' => $errorCount,
            'errors' => $this->errors,
            'has_errors' => $errorCount > 0,
        ];
    }

    /**
     * 오류 정보를 세션에 저장
     */
    protected function saveErrorsToSession(int $tenantId, string $sourceTable): void
    {
        $errorLog = [
            'tenant_id' => $tenantId,
            'source_table' => $sourceTable,
            'errors' => $this->errors,
            'timestamp' => now()->toDateTimeString(),
            'user_id' => auth()->id(),
            'user_name' => auth()->user()?->name,
        ];

        // 기존 오류 로그 가져오기
        $existingLogs = session('item_field_errors', []);

        // 최신 오류를 앞에 추가 (최대 10개 유지)
        array_unshift($existingLogs, $errorLog);
        $existingLogs = array_slice($existingLogs, 0, 10);

        session(['item_field_errors' => $existingLogs]);
    }

    /**
     * 저장된 오류 로그 조회
     */
    public function getErrorLogs(): array
    {
        return session('item_field_errors', []);
    }

    /**
     * 오류 로그 초기화
     */
    public function clearErrorLogs(): void
    {
        session()->forget('item_field_errors');
    }

    /**
     * 전체 테이블 시스템 필드 시딩
     */
    public function seedAll(int $tenantId): array
    {
        $results = [];
        $totalSeeded = 0;
        $totalSkipped = 0;

        $sourceTables = array_keys(SystemFieldDefinition::getSourceTableOptions());

        foreach ($sourceTables as $sourceTable) {
            $result = $this->seedTable($tenantId, $sourceTable);
            $results[$sourceTable] = $result;
            $totalSeeded += $result['seeded_count'];
            $totalSkipped += $result['skipped_count'] ?? 0;
        }

        return [
            'success' => true,
            'message' => "전체 시딩 완료: {$totalSeeded}개 추가, {$totalSkipped}개 건너뜀",
            'total_seeded' => $totalSeeded,
            'total_skipped' => $totalSkipped,
            'details' => $results,
        ];
    }

    /**
     * 단일 테이블 시스템 필드 초기화 (삭제 후 재시딩)
     */
    public function resetTable(int $tenantId, string $sourceTable): array
    {
        // 시스템 필드만 삭제 (커스텀 필드는 유지)
        $deletedCount = ItemField::where('tenant_id', $tenantId)
            ->where('source_table', $sourceTable)
            ->where('storage_type', 'column')
            ->forceDelete();

        // 재시딩
        $seedResult = $this->seedTable($tenantId, $sourceTable);

        return [
            'success' => true,
            'message' => "초기화 완료: {$deletedCount}개 삭제, {$seedResult['seeded_count']}개 재등록",
            'deleted_count' => $deletedCount,
            'seeded_count' => $seedResult['seeded_count'],
        ];
    }

    /**
     * 전체 테이블 시스템 필드 초기화
     */
    public function resetAll(int $tenantId): array
    {
        $results = [];
        $totalDeleted = 0;
        $totalSeeded = 0;

        $sourceTables = array_keys(SystemFieldDefinition::getSourceTableOptions());

        foreach ($sourceTables as $sourceTable) {
            $result = $this->resetTable($tenantId, $sourceTable);
            $results[$sourceTable] = $result;
            $totalDeleted += $result['deleted_count'];
            $totalSeeded += $result['seeded_count'];
        }

        return [
            'success' => true,
            'message' => "전체 초기화 완료: {$totalDeleted}개 삭제, {$totalSeeded}개 재등록",
            'total_deleted' => $totalDeleted,
            'total_seeded' => $totalSeeded,
            'details' => $results,
        ];
    }

    /**
     * 필드 목록 조회 (시스템 + 커스텀)
     *
     * @param  array  $filters  source_table, field_type, field_category (system|custom), search, per_page
     */
    public function getFields(int $tenantId, array $filters = []): \Illuminate\Contracts\Pagination\LengthAwarePaginator
    {
        $query = ItemField::withTrashed()->where('tenant_id', $tenantId);

        // 필드 유형 필터 (system=is_common:1, custom=is_common:0)
        if (! empty($filters['field_category'])) {
            if ($filters['field_category'] === 'system') {
                $query->where('is_common', true);
            } elseif ($filters['field_category'] === 'custom') {
                $query->where('is_common', false);
            }
        }

        // 소스 테이블 필터
        if (! empty($filters['source_table'])) {
            $query->where('source_table', $filters['source_table']);
        }

        // 필드 타입 필터
        if (! empty($filters['field_type'])) {
            $query->where('field_type', $filters['field_type']);
        }

        // 검색
        if (! empty($filters['search'])) {
            $search = $filters['search'];
            $query->where(function ($q) use ($search) {
                $q->where('field_key', 'like', "%{$search}%")
                    ->orWhere('field_name', 'like', "%{$search}%");
            });
        }

        // 페이지당 항목 수 (기본 20개)
        $perPage = ! empty($filters['per_page']) ? (int) $filters['per_page'] : 20;

        // 시스템 필드 우선 정렬 (is_common DESC), 그 다음 source_table, order_no
        return $query->orderByDesc('is_common')
            ->orderBy('source_table')
            ->orderBy('order_no')
            ->paginate($perPage)
            ->withQueryString();
    }

    /**
     * 커스텀 필드 목록 조회 (기존 호환성 유지)
     *
     * @deprecated Use getFields() instead
     */
    public function getCustomFields(int $tenantId, array $filters = []): Collection
    {
        // 기존 호환성 유지: 커스텀 필드만 반환
        $filters['field_category'] = 'custom';

        return $this->getFields($tenantId, $filters);
    }

    /**
     * 커스텀 필드 추가
     */
    public function createCustomField(int $tenantId, array $data): array
    {
        $sourceTable = $data['source_table'];
        $fieldKey = $data['field_key'];

        // 시스템 예약어 체크
        $systemFieldKeys = SystemFieldDefinition::getAllSystemFieldKeys($sourceTable);
        if (in_array($fieldKey, $systemFieldKeys)) {
            return [
                'success' => false,
                'message' => "\"{$fieldKey}\"은(는) 시스템 예약어로 사용할 수 없습니다.",
            ];
        }

        // 기존 필드 키 중복 체크
        $exists = ItemField::where('tenant_id', $tenantId)
            ->where('source_table', $sourceTable)
            ->where('field_key', $fieldKey)
            ->exists();

        if ($exists) {
            return [
                'success' => false,
                'message' => "\"{$fieldKey}\"는 이미 사용 중인 필드 키입니다.",
            ];
        }

        // 커스텀 필드 생성
        $field = ItemField::create([
            'tenant_id' => $tenantId,
            'group_id' => 1,
            'field_key' => $fieldKey,
            'field_name' => $data['field_name'],
            'field_type' => $data['field_type'],
            'order_no' => $data['order_no'] ?? 0,
            'is_required' => $data['is_required'] ?? false,
            'default_value' => $data['default_value'] ?? null,
            'options' => $data['options'] ?? null,
            'source_table' => $sourceTable,
            'source_column' => null,
            'storage_type' => 'json',
            'json_path' => "attributes.{$fieldKey}",
            'is_active' => true,
            'is_common' => false,
            'created_by' => auth()->id(),
        ]);

        return [
            'success' => true,
            'message' => '커스텀 필드가 추가되었습니다.',
            'field' => $field,
        ];
    }

    /**
     * 커스텀 필드 수정
     */
    public function updateCustomField(int $tenantId, int $fieldId, array $data): array
    {
        $field = ItemField::where('tenant_id', $tenantId)
            ->where('id', $fieldId)
            ->first();

        if (! $field) {
            return [
                'success' => false,
                'message' => '필드를 찾을 수 없습니다.',
            ];
        }

        // 시스템 필드(storage_type = column)의 경우 일부 필드만 수정 가능
        $isSystemField = $field->storage_type === 'column';

        // field_key 변경 시 중복 체크 (시스템 필드는 field_key 변경 불가)
        if (! $isSystemField && ! empty($data['field_key']) && $data['field_key'] !== $field->field_key) {
            $exists = ItemField::where('tenant_id', $tenantId)
                ->where('field_key', $data['field_key'])
                ->where('id', '!=', $fieldId)
                ->exists();

            if ($exists) {
                return [
                    'success' => false,
                    'message' => "\"{$data['field_key']}\"는 이미 사용 중인 필드 키입니다.",
                ];
            }
        }

        // 업데이트 데이터 준비
        $updateData = [
            'field_name' => $data['field_name'],
            'field_type' => $data['field_type'],
            'is_required' => $data['is_required'] ?? false,
            'default_value' => $data['default_value'] ?? null,
            'options' => $data['options'] ?? null,
            'updated_by' => auth()->id(),
        ];

        // 커스텀 필드만 source_table, field_key 변경 가능
        if (! $isSystemField) {
            if (isset($data['source_table'])) {
                $updateData['source_table'] = $data['source_table'];
            }
            if (isset($data['field_key'])) {
                $updateData['field_key'] = $data['field_key'];
                $updateData['json_path'] = "attributes.{$data['field_key']}";
            }
        }

        $field->update($updateData);

        return [
            'success' => true,
            'message' => '커스텀 필드가 수정되었습니다.',
            'field' => $field->fresh(),
        ];
    }

    /**
     * 커스텀 필드 삭제
     */
    public function deleteCustomField(int $tenantId, int $fieldId): array
    {
        $field = ItemField::where('tenant_id', $tenantId)
            ->where('id', $fieldId)
            ->first();

        if (! $field) {
            return [
                'success' => false,
                'message' => '필드를 찾을 수 없습니다.',
            ];
        }

        $field->forceDelete();

        return [
            'success' => true,
            'message' => '필드가 삭제되었습니다.',
        ];
    }

    /**
     * 커스텀 필드 일괄 삭제
     */
    public function deleteCustomFields(int $tenantId, array $fieldIds): array
    {
        $deletedCount = 0;

        foreach ($fieldIds as $fieldId) {
            $result = $this->deleteCustomField($tenantId, $fieldId);
            if ($result['success']) {
                $deletedCount++;
            }
        }

        return [
            'success' => true,
            'message' => "{$deletedCount}개의 커스텀 필드가 삭제되었습니다.",
            'deleted_count' => $deletedCount,
        ];
    }

    /**
     * 소프트 삭제된 커스텀 필드 복원
     */
    public function restoreCustomField(int $tenantId, int $fieldId): array
    {
        $field = ItemField::withTrashed()
            ->where('tenant_id', $tenantId)
            ->where('id', $fieldId)
            ->first();

        if (! $field) {
            return [
                'success' => false,
                'message' => '필드를 찾을 수 없습니다.',
            ];
        }

        if (is_null($field->deleted_at)) {
            return [
                'success' => false,
                'message' => '이미 활성화된 필드입니다.',
            ];
        }

        $field->restore();

        return [
            'success' => true,
            'message' => '필드가 복원되었습니다.',
        ];
    }

    /**
     * 커스텀 필드 영구 삭제
     */
    public function forceDeleteCustomField(int $tenantId, int $fieldId): array
    {
        $field = ItemField::withTrashed()
            ->where('tenant_id', $tenantId)
            ->where('id', $fieldId)
            ->first();

        if (! $field) {
            return [
                'success' => false,
                'message' => '필드를 찾을 수 없습니다.',
            ];
        }

        $field->forceDelete();

        return [
            'success' => true,
            'message' => '필드가 영구 삭제되었습니다.',
        ];
    }

    /**
     * 삭제된 필드 일괄 영구 삭제 (휴지통 비우기)
     */
    public function purgeDeletedFields(int $tenantId): array
    {
        // 삭제된 필드(soft deleted) 조회
        $deletedFields = ItemField::onlyTrashed()
            ->where('tenant_id', $tenantId)
            ->get();

        if ($deletedFields->isEmpty()) {
            return [
                'success' => true,
                'message' => '삭제된 필드가 없습니다.',
                'purged_count' => 0,
            ];
        }

        $purgedCount = 0;

        foreach ($deletedFields as $field) {
            $field->forceDelete();
            $purgedCount++;
        }

        return [
            'success' => true,
            'message' => "{$purgedCount}개의 삭제된 필드가 영구 삭제되었습니다.",
            'purged_count' => $purgedCount,
        ];
    }
}
