<?php

namespace App\Services\Quote;

use App\Models\Quote\QuoteFormula;
use App\Models\Quote\QuoteFormulaItem;
use App\Models\Quote\QuoteFormulaMapping;
use App\Models\Quote\QuoteFormulaRange;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class QuoteFormulaService
{
    /**
     * 수식 목록 조회 (페이지네이션)
     */
    public function getFormulas(array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        $tenantId = session('selected_tenant_id');

        $query = QuoteFormula::query()
            ->with(['category'])
            ->withCount(['ranges', 'mappings', 'items']);

        // 테넌트 필터
        if ($tenantId && $tenantId !== 'all') {
            $query->where('tenant_id', $tenantId);
        }

        // 카테고리 필터
        if (! empty($filters['category_id'])) {
            $query->where('category_id', $filters['category_id']);
        }

        // 제품 필터 (공통/특정)
        if (isset($filters['product_id'])) {
            if ($filters['product_id'] === 'common' || $filters['product_id'] === '') {
                $query->whereNull('product_id');
            } else {
                $query->where('product_id', $filters['product_id']);
            }
        }

        // 유형 필터
        if (! empty($filters['type'])) {
            $query->where('type', $filters['type']);
        }

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

        // 활성화 필터
        if (isset($filters['is_active']) && $filters['is_active'] !== '') {
            $query->where('is_active', (bool) $filters['is_active']);
        }

        // 정렬
        $sortBy = $filters['sort_by'] ?? 'sort_order';
        $sortDirection = $filters['sort_direction'] ?? 'asc';

        if ($sortBy === 'category') {
            $query->join('quote_formula_categories', 'quote_formulas.category_id', '=', 'quote_formula_categories.id')
                ->orderBy('quote_formula_categories.sort_order', $sortDirection)
                ->orderBy('quote_formulas.sort_order', $sortDirection)
                ->select('quote_formulas.*');
        } else {
            $query->orderBy($sortBy, $sortDirection);
        }

        return $query->paginate($perPage);
    }

    /**
     * 카테고리별 수식 목록 (실행 순서용)
     */
    public function getFormulasByCategory(?int $productId = null): Collection
    {
        $tenantId = session('selected_tenant_id');

        return QuoteFormula::query()
            ->where('tenant_id', $tenantId)
            ->where('is_active', true)
            ->where(function ($q) use ($productId) {
                $q->whereNull('product_id');
                if ($productId) {
                    $q->orWhere('product_id', $productId);
                }
            })
            ->with(['category', 'ranges', 'mappings', 'items'])
            ->get()
            ->groupBy('category.code')
            ->sortBy(fn ($formulas) => $formulas->first()->category->sort_order);
    }

    /**
     * 수식 상세 조회
     */
    public function getFormulaById(int $id, bool $withRelations = false): ?QuoteFormula
    {
        $query = QuoteFormula::query();

        if ($withRelations) {
            $query->with(['category', 'ranges', 'mappings', 'items']);
        }

        return $query->find($id);
    }

    /**
     * 수식 생성
     */
    public function createFormula(array $data): QuoteFormula
    {
        $tenantId = session('selected_tenant_id');

        return DB::transaction(function () use ($data, $tenantId) {
            // 자동 sort_order
            if (! isset($data['sort_order'])) {
                $maxOrder = QuoteFormula::where('tenant_id', $tenantId)
                    ->where('category_id', $data['category_id'])
                    ->max('sort_order');
                $data['sort_order'] = ($maxOrder ?? 0) + 1;
            }

            $formula = QuoteFormula::create([
                'tenant_id' => $tenantId,
                'category_id' => $data['category_id'],
                'product_id' => $data['product_id'] ?? null,
                'name' => $data['name'],
                'variable' => $data['variable'],
                'type' => $data['type'],
                'formula' => $data['formula'] ?? null,
                'output_type' => $data['output_type'] ?? 'variable',
                'description' => $data['description'] ?? null,
                'sort_order' => $data['sort_order'],
                'is_active' => $data['is_active'] ?? true,
                'created_by' => auth()->id(),
            ]);

            // 범위별 규칙 저장
            if ($data['type'] === QuoteFormula::TYPE_RANGE && ! empty($data['ranges'])) {
                $this->saveRanges($formula, $data['ranges']);
            }

            // 매핑 규칙 저장
            if ($data['type'] === QuoteFormula::TYPE_MAPPING && ! empty($data['mappings'])) {
                $this->saveMappings($formula, $data['mappings']);
            }

            // 품목 출력 저장
            if (($data['output_type'] ?? 'variable') === QuoteFormula::OUTPUT_ITEM && ! empty($data['items'])) {
                $this->saveItems($formula, $data['items']);
            }

            return $formula->load(['ranges', 'mappings', 'items']);
        });
    }

    /**
     * 수식 수정
     */
    public function updateFormula(int $id, array $data): QuoteFormula
    {
        $formula = QuoteFormula::findOrFail($id);

        return DB::transaction(function () use ($formula, $data) {
            $formula->update([
                'category_id' => $data['category_id'] ?? $formula->category_id,
                'product_id' => array_key_exists('product_id', $data) ? $data['product_id'] : $formula->product_id,
                'name' => $data['name'] ?? $formula->name,
                'variable' => $data['variable'] ?? $formula->variable,
                'type' => $data['type'] ?? $formula->type,
                'formula' => array_key_exists('formula', $data) ? $data['formula'] : $formula->formula,
                'output_type' => $data['output_type'] ?? $formula->output_type,
                'description' => array_key_exists('description', $data) ? $data['description'] : $formula->description,
                'sort_order' => $data['sort_order'] ?? $formula->sort_order,
                'is_active' => $data['is_active'] ?? $formula->is_active,
                'updated_by' => auth()->id(),
            ]);

            // 범위 규칙 업데이트
            if (isset($data['ranges'])) {
                $formula->ranges()->delete();
                if ($formula->type === QuoteFormula::TYPE_RANGE) {
                    $this->saveRanges($formula, $data['ranges']);
                }
            }

            // 매핑 규칙 업데이트
            if (isset($data['mappings'])) {
                $formula->mappings()->delete();
                if ($formula->type === QuoteFormula::TYPE_MAPPING) {
                    $this->saveMappings($formula, $data['mappings']);
                }
            }

            // 품목 출력 업데이트
            if (isset($data['items'])) {
                $formula->items()->delete();
                if ($formula->output_type === QuoteFormula::OUTPUT_ITEM) {
                    $this->saveItems($formula, $data['items']);
                }
            }

            return $formula->fresh(['category', 'ranges', 'mappings', 'items']);
        });
    }

    /**
     * 수식 삭제
     */
    public function deleteFormula(int $id): void
    {
        $formula = QuoteFormula::findOrFail($id);
        $formula->delete();
    }

    /**
     * 수식 활성/비활성 토글
     */
    public function toggleActive(int $id): QuoteFormula
    {
        $formula = QuoteFormula::findOrFail($id);

        $formula->is_active = ! $formula->is_active;
        $formula->updated_by = auth()->id();
        $formula->save();

        return $formula;
    }

    /**
     * 수식 복원
     */
    public function restoreFormula(int $id): void
    {
        $formula = QuoteFormula::withTrashed()->findOrFail($id);
        $formula->restore();
    }

    /**
     * 수식 영구 삭제
     */
    public function forceDeleteFormula(int $id): void
    {
        $formula = QuoteFormula::withTrashed()->findOrFail($id);

        DB::transaction(function () use ($formula) {
            $formula->ranges()->delete();
            $formula->mappings()->delete();
            $formula->items()->delete();
            $formula->forceDelete();
        });
    }

    /**
     * 변수명 중복 체크 (테넌트 전체 범위)
     */
    public function isVariableExists(string $variable, ?int $excludeId = null): bool
    {
        $tenantId = session('selected_tenant_id');

        $query = QuoteFormula::where('tenant_id', $tenantId)
            ->where('variable', $variable);

        if ($excludeId) {
            $query->where('id', '!=', $excludeId);
        }

        return $query->exists();
    }

    /**
     * 수식 순서 변경
     */
    public function reorder(array $formulaIds): void
    {
        foreach ($formulaIds as $index => $id) {
            QuoteFormula::where('id', $id)->update([
                'sort_order' => $index + 1,
                'updated_by' => auth()->id(),
            ]);
        }
    }

    /**
     * 모든 활성 수식 조회
     */
    public function getAllActiveFormulas(): Collection
    {
        $tenantId = session('selected_tenant_id');

        return QuoteFormula::query()
            ->where('tenant_id', $tenantId)
            ->where('is_active', true)
            ->with(['category', 'ranges', 'mappings', 'items'])
            ->orderBy('category_id')
            ->orderBy('sort_order')
            ->get();
    }

    /**
     * 수식 복제
     */
    public function duplicateFormula(int $id): QuoteFormula
    {
        $original = QuoteFormula::with(['ranges', 'mappings', 'items'])->findOrFail($id);
        $tenantId = session('selected_tenant_id');

        return DB::transaction(function () use ($original, $tenantId) {
            // 새로운 변수명 생성
            $newVariable = $this->generateUniqueVariable($original->variable);

            // 수식 복제
            $formula = QuoteFormula::create([
                'tenant_id' => $tenantId,
                'category_id' => $original->category_id,
                'product_id' => $original->product_id,
                'name' => $original->name.' (복제)',
                'variable' => $newVariable,
                'type' => $original->type,
                'formula' => $original->formula,
                'output_type' => $original->output_type,
                'description' => $original->description,
                'sort_order' => $original->sort_order + 1,
                'is_active' => false, // 복제본은 비활성 상태로 생성
                'created_by' => auth()->id(),
            ]);

            // 범위 규칙 복제
            foreach ($original->ranges as $range) {
                QuoteFormulaRange::create([
                    'formula_id' => $formula->id,
                    'min_value' => $range->min_value,
                    'max_value' => $range->max_value,
                    'condition_variable' => $range->condition_variable,
                    'result_value' => $range->result_value,
                    'result_type' => $range->result_type,
                    'sort_order' => $range->sort_order,
                ]);
            }

            // 매핑 규칙 복제
            foreach ($original->mappings as $mapping) {
                QuoteFormulaMapping::create([
                    'formula_id' => $formula->id,
                    'source_variable' => $mapping->source_variable,
                    'source_value' => $mapping->source_value,
                    'result_value' => $mapping->result_value,
                    'result_type' => $mapping->result_type,
                    'sort_order' => $mapping->sort_order,
                ]);
            }

            // 품목 출력 복제
            foreach ($original->items as $item) {
                QuoteFormulaItem::create([
                    'formula_id' => $formula->id,
                    'item_code' => $item->item_code,
                    'item_name' => $item->item_name,
                    'specification' => $item->specification,
                    'unit' => $item->unit,
                    'quantity_formula' => $item->quantity_formula,
                    'unit_price_formula' => $item->unit_price_formula,
                    'sort_order' => $item->sort_order,
                ]);
            }

            return $formula->load(['category', 'ranges', 'mappings', 'items']);
        });
    }

    /**
     * 고유한 변수명 생성
     */
    private function generateUniqueVariable(string $baseVariable): string
    {
        $tenantId = session('selected_tenant_id');
        $suffix = 1;
        $newVariable = $baseVariable.'_COPY';

        while (QuoteFormula::where('tenant_id', $tenantId)->where('variable', $newVariable)->exists()) {
            $suffix++;
            $newVariable = $baseVariable.'_COPY'.$suffix;
        }

        return $newVariable;
    }

    /**
     * 변수 목록 조회 (수식 입력 시 참조용)
     */
    public function getAvailableVariables(?int $productId = null): array
    {
        $tenantId = session('selected_tenant_id');

        $formulas = QuoteFormula::query()
            ->where('tenant_id', $tenantId)
            ->where('is_active', true)
            ->where('output_type', 'variable')
            ->where(function ($q) use ($productId) {
                $q->whereNull('product_id');
                if ($productId) {
                    $q->orWhere('product_id', $productId);
                }
            })
            ->with('category')
            ->orderBy('category_id')
            ->orderBy('sort_order')
            ->get();

        return $formulas->map(fn ($f) => [
            'variable' => $f->variable,
            'name' => $f->name,
            'category' => $f->category->name,
            'type' => $f->type,
        ])->toArray();
    }

    /**
     * 수식 통계
     */
    public function getFormulaStats(): array
    {
        $tenantId = session('selected_tenant_id');

        return [
            'total' => QuoteFormula::where('tenant_id', $tenantId)->count(),
            'active' => QuoteFormula::where('tenant_id', $tenantId)->where('is_active', true)->count(),
            'by_type' => [
                'input' => QuoteFormula::where('tenant_id', $tenantId)->where('type', 'input')->count(),
                'calculation' => QuoteFormula::where('tenant_id', $tenantId)->where('type', 'calculation')->count(),
                'range' => QuoteFormula::where('tenant_id', $tenantId)->where('type', 'range')->count(),
                'mapping' => QuoteFormula::where('tenant_id', $tenantId)->where('type', 'mapping')->count(),
            ],
        ];
    }

    // =========================================================================
    // Private Methods
    // =========================================================================

    /**
     * 범위 규칙 저장
     */
    private function saveRanges(QuoteFormula $formula, array $ranges): void
    {
        foreach ($ranges as $index => $range) {
            QuoteFormulaRange::create([
                'formula_id' => $formula->id,
                'min_value' => $range['min_value'] ?? null,
                'max_value' => $range['max_value'] ?? null,
                'condition_variable' => $range['condition_variable'],
                'result_value' => $range['result_value'],
                'result_type' => $range['result_type'] ?? 'fixed',
                'sort_order' => $index + 1,
            ]);
        }
    }

    /**
     * 매핑 규칙 저장
     */
    private function saveMappings(QuoteFormula $formula, array $mappings): void
    {
        foreach ($mappings as $index => $mapping) {
            QuoteFormulaMapping::create([
                'formula_id' => $formula->id,
                'source_variable' => $mapping['source_variable'],
                'source_value' => $mapping['source_value'],
                'result_value' => $mapping['result_value'],
                'result_type' => $mapping['result_type'] ?? 'fixed',
                'sort_order' => $index + 1,
            ]);
        }
    }

    /**
     * 품목 출력 저장
     */
    private function saveItems(QuoteFormula $formula, array $items): void
    {
        foreach ($items as $index => $item) {
            QuoteFormulaItem::create([
                'formula_id' => $formula->id,
                'item_code' => $item['item_code'],
                'item_name' => $item['item_name'],
                'specification' => $item['specification'] ?? null,
                'unit' => $item['unit'],
                'quantity_formula' => $item['quantity_formula'],
                'unit_price_formula' => $item['unit_price_formula'] ?? null,
                'sort_order' => $index + 1,
            ]);
        }
    }
}
