<?php

namespace App\Services\Quote;

use App\Models\Quote\Quote;
use App\Models\Quote\QuoteFormula;
use App\Models\Quote\QuoteFormulaCategory;
use App\Services\Service;
use Illuminate\Support\Collection;

/**
 * 견적 자동산출 서비스
 *
 * DB에 저장된 수식(quote_formulas)을 기반으로 견적 품목과 금액을 자동 계산합니다.
 * 제품 카테고리(스크린/철재)별 계산 로직을 지원합니다.
 */
class QuoteCalculationService extends Service
{
    public function __construct(
        private FormulaEvaluatorService $formulaEvaluator
    ) {}

    /**
     * 견적 자동산출 실행
     *
     * @param  array  $inputs  입력 파라미터
     * @param  string|null  $productCategory  제품 카테고리
     * @param  int|null  $productId  제품 ID (제품별 전용 수식 조회용)
     * @return array 산출 결과
     */
    public function calculate(array $inputs, ?string $productCategory = null, ?int $productId = null): array
    {
        $category = $productCategory ?? Quote::CATEGORY_SCREEN;

        // 입력값 검증 및 변수 설정
        $validatedInputs = $this->validateInputs($inputs, $category);

        // DB에서 수식 조회
        $formulasByCategory = $this->getFormulasByCategory($productId);

        if ($formulasByCategory->isEmpty()) {
            return [
                'inputs' => $validatedInputs,
                'outputs' => [],
                'items' => [],
                'costs' => [
                    'material_cost' => 0,
                    'labor_cost' => 0,
                    'install_cost' => 0,
                    'subtotal' => 0,
                ],
                'errors' => [__('error.no_formulas_configured')],
            ];
        }

        // 수식 실행
        $result = $this->formulaEvaluator->executeAll($formulasByCategory, $validatedInputs);

        // 비용 계산
        $costs = $this->calculateCosts($result['items']);

        return [
            'inputs' => $validatedInputs,
            'outputs' => $result['variables'],
            'items' => $result['items'],
            'costs' => $costs,
            'errors' => $result['errors'],
        ];
    }

    /**
     * 견적 미리보기 (저장 없이 계산만)
     */
    public function preview(array $inputs, ?string $productCategory = null, ?int $productId = null): array
    {
        return $this->calculate($inputs, $productCategory, $productId);
    }

    /**
     * BOM 기반 견적 산출 (10단계 디버깅 포함)
     *
     * MNG FormulaEvaluatorService의 calculateBomWithDebug와 동일한 로직을 사용합니다.
     * React 견적등록 화면에서 자동 견적 산출 시 호출됩니다.
     *
     * @param  string  $finishedGoodsCode  완제품 코드
     * @param  array  $inputs  입력 변수 (W0, H0, QTY, PC, GT, MP, CT, WS, INSP)
     * @param  bool  $debug  디버그 모드 (기본 false)
     * @return array 산출 결과 (finished_goods, variables, items, grouped_items, subtotals, grand_total)
     */
    public function calculateBom(string $finishedGoodsCode, array $inputs, bool $debug = false): array
    {
        $tenantId = $this->tenantId();

        if (! $tenantId) {
            return [
                'success' => false,
                'error' => __('error.tenant_not_set'),
            ];
        }

        // FormulaEvaluatorService의 calculateBomWithDebug 호출
        $result = $this->formulaEvaluator->calculateBomWithDebug(
            $finishedGoodsCode,
            $inputs,
            $tenantId
        );

        // 디버그 모드가 아니면 debug_steps 제거
        if (! $debug && isset($result['debug_steps'])) {
            unset($result['debug_steps']);
        }

        return $result;
    }

    /**
     * 다건 BOM 기반 견적 산출
     *
     * 여러 품목의 견적을 일괄 계산합니다.
     * React 견적등록 화면에서 품목 목록의 자동 견적 산출 시 호출됩니다.
     *
     * @param  array  $inputItems  입력 품목 배열 (QuoteBomBulkCalculateRequest::getInputItems() 결과)
     * @param  bool  $debug  디버그 모드 (기본 false)
     * @return array 산출 결과 배열
     */
    public function calculateBomBulk(array $inputItems, bool $debug = false): array
    {
        $results = [];
        $successCount = 0;
        $failCount = 0;
        $grandTotal = 0;

        foreach ($inputItems as $item) {
            $index = $item['index'];
            $finishedGoodsCode = $item['finished_goods_code'];
            $inputs = $item['inputs'];

            try {
                $result = $this->calculateBom($finishedGoodsCode, $inputs, $debug);

                if ($result['success'] ?? false) {
                    $successCount++;
                    $grandTotal += $result['grand_total'] ?? 0;
                } else {
                    $failCount++;
                }

                $results[] = [
                    'index' => $index,
                    'finished_goods_code' => $finishedGoodsCode,
                    'inputs' => $inputs,
                    'result' => $result,
                ];
            } catch (\Throwable $e) {
                $failCount++;
                $results[] = [
                    'index' => $index,
                    'finished_goods_code' => $finishedGoodsCode,
                    'inputs' => $inputs,
                    'result' => [
                        'success' => false,
                        'error' => $e->getMessage(),
                    ],
                ];
            }
        }

        return [
            'success' => $failCount === 0,
            'summary' => [
                'total_count' => count($inputItems),
                'success_count' => $successCount,
                'fail_count' => $failCount,
                'grand_total' => round($grandTotal, 2),
            ],
            'items' => $results,
        ];
    }

    /**
     * 견적 품목 재계산 (기존 견적 기준)
     */
    public function recalculate(Quote $quote): array
    {
        $inputs = $quote->calculation_inputs ?? [];
        $category = $quote->product_category;
        $productId = $quote->product_id;

        return $this->calculate($inputs, $category, $productId);
    }

    /**
     * 카테고리별 수식 조회
     *
     * @param  int|null  $productId  제품 ID (공통 수식 + 제품별 수식 조회)
     * @return Collection 카테고리 코드 => 수식 목록
     */
    private function getFormulasByCategory(?int $productId = null): Collection
    {
        $tenantId = $this->tenantId();

        if (! $tenantId) {
            return collect();
        }

        // 카테고리 조회 (정렬순)
        $categories = QuoteFormulaCategory::query()
            ->where('tenant_id', $tenantId)
            ->active()
            ->ordered()
            ->with([
                'formulas' => function ($query) use ($productId) {
                    $query->active()
                        ->forProduct($productId)
                        ->ordered()
                        ->with(['ranges', 'mappings', 'items']);
                },
            ])
            ->get();

        // 카테고리 코드 => 수식 목록으로 변환
        return $categories->mapWithKeys(function ($category) {
            return [$category->code => $category->formulas];
        })->filter(fn ($formulas) => $formulas->isNotEmpty());
    }

    /**
     * 입력값 검증 및 기본값 설정
     */
    private function validateInputs(array $inputs, string $category): array
    {
        // 공통 입력값
        $validated = [
            'W0' => (float) ($inputs['W0'] ?? $inputs['open_size_width'] ?? 0),
            'H0' => (float) ($inputs['H0'] ?? $inputs['open_size_height'] ?? 0),
            'QTY' => (int) ($inputs['QTY'] ?? $inputs['quantity'] ?? 1),
        ];

        // 카테고리별 추가 입력값
        if ($category === Quote::CATEGORY_SCREEN) {
            $validated = array_merge($validated, [
                'INSTALL_TYPE' => $inputs['INSTALL_TYPE'] ?? 'wall', // wall, ceiling, floor
                'MOTOR_TYPE' => $inputs['MOTOR_TYPE'] ?? 'standard', // standard, heavy
                'CONTROL_TYPE' => $inputs['CONTROL_TYPE'] ?? 'switch', // switch, remote, smart
                'CHAIN_SIDE' => $inputs['CHAIN_SIDE'] ?? 'left', // left, right
            ]);
        } elseif ($category === Quote::CATEGORY_STEEL) {
            $validated = array_merge($validated, [
                'MATERIAL' => $inputs['MATERIAL'] ?? 'ss304', // ss304, ss316, galvanized
                'THICKNESS' => (float) ($inputs['THICKNESS'] ?? 1.5),
                'FINISH' => $inputs['FINISH'] ?? 'hairline', // hairline, mirror, matte
                'WELDING' => $inputs['WELDING'] ?? 'tig', // tig, mig, spot
            ]);
        }

        // 추가 사용자 입력값 병합 (DB 수식에서 사용할 수 있도록)
        foreach ($inputs as $key => $value) {
            if (! isset($validated[$key])) {
                $validated[$key] = $value;
            }
        }

        return $validated;
    }

    /**
     * 비용 계산
     */
    private function calculateCosts(array $items): array
    {
        $materialCost = 0;
        $laborCost = 0;
        $installCost = 0;

        foreach ($items as $item) {
            $category = $item['formula_category'] ?? 'material';
            $price = (float) ($item['total_price'] ?? 0);

            match ($category) {
                'material' => $materialCost += $price,
                'labor' => $laborCost += $price,
                'install' => $installCost += $price,
                default => $materialCost += $price,
            };
        }

        $subtotal = $materialCost + $laborCost + $installCost;

        return [
            'material_cost' => round($materialCost, 2),
            'labor_cost' => round($laborCost, 2),
            'install_cost' => round($installCost, 2),
            'subtotal' => round($subtotal, 2),
        ];
    }

    /**
     * 입력 스키마 반환 (프론트엔드용)
     * DB에서 input 타입 수식을 조회하여 동적으로 생성
     */
    public function getInputSchema(?string $productCategory = null, ?int $productId = null): array
    {
        $tenantId = $this->tenantId();

        if (! $tenantId) {
            return $this->getDefaultInputSchema($productCategory);
        }

        // DB에서 input 타입 수식 조회
        $inputFormulas = QuoteFormula::query()
            ->where('tenant_id', $tenantId)
            ->active()
            ->forProduct($productId)
            ->ofType(QuoteFormula::TYPE_INPUT)
            ->ordered()
            ->get();

        if ($inputFormulas->isEmpty()) {
            return $this->getDefaultInputSchema($productCategory);
        }

        $schema = [];

        foreach ($inputFormulas as $formula) {
            $schema[$formula->variable] = [
                'label' => $formula->name,
                'type' => 'number', // 기본값, 추후 formula.description에서 메타 정보 파싱 가능
                'required' => true,
                'description' => $formula->description,
            ];
        }

        return $schema;
    }

    /**
     * 기본 입력 스키마 (DB에 수식이 없을 때 사용)
     */
    private function getDefaultInputSchema(?string $productCategory = null): array
    {
        $category = $productCategory ?? Quote::CATEGORY_SCREEN;

        $commonSchema = [
            'W0' => [
                'label' => '개구부 폭',
                'type' => 'number',
                'unit' => 'mm',
                'required' => true,
                'min' => 100,
                'max' => 10000,
            ],
            'H0' => [
                'label' => '개구부 높이',
                'type' => 'number',
                'unit' => 'mm',
                'required' => true,
                'min' => 100,
                'max' => 10000,
            ],
            'QTY' => [
                'label' => '수량',
                'type' => 'integer',
                'required' => true,
                'min' => 1,
                'default' => 1,
            ],
        ];

        if ($category === Quote::CATEGORY_SCREEN) {
            return array_merge($commonSchema, [
                'INSTALL_TYPE' => [
                    'label' => '설치 유형',
                    'type' => 'select',
                    'options' => [
                        ['value' => 'wall', 'label' => '벽면'],
                        ['value' => 'ceiling', 'label' => '천장'],
                        ['value' => 'floor', 'label' => '바닥'],
                    ],
                    'default' => 'wall',
                ],
                'MOTOR_TYPE' => [
                    'label' => '모터 유형',
                    'type' => 'select',
                    'options' => [
                        ['value' => 'standard', 'label' => '일반형'],
                        ['value' => 'heavy', 'label' => '고하중형'],
                    ],
                    'default' => 'standard',
                ],
                'CONTROL_TYPE' => [
                    'label' => '제어 방식',
                    'type' => 'select',
                    'options' => [
                        ['value' => 'switch', 'label' => '스위치'],
                        ['value' => 'remote', 'label' => '리모컨'],
                        ['value' => 'smart', 'label' => '스마트'],
                    ],
                    'default' => 'switch',
                ],
                'CHAIN_SIDE' => [
                    'label' => '체인 위치',
                    'type' => 'select',
                    'options' => [
                        ['value' => 'left', 'label' => '좌측'],
                        ['value' => 'right', 'label' => '우측'],
                    ],
                    'default' => 'left',
                ],
            ]);
        }

        if ($category === Quote::CATEGORY_STEEL) {
            return array_merge($commonSchema, [
                'MATERIAL' => [
                    'label' => '재질',
                    'type' => 'select',
                    'options' => [
                        ['value' => 'ss304', 'label' => 'SUS304'],
                        ['value' => 'ss316', 'label' => 'SUS316'],
                        ['value' => 'galvanized', 'label' => '아연도금'],
                    ],
                    'default' => 'ss304',
                ],
                'THICKNESS' => [
                    'label' => '두께',
                    'type' => 'number',
                    'unit' => 'mm',
                    'min' => 0.5,
                    'max' => 10,
                    'step' => 0.1,
                    'default' => 1.5,
                ],
                'FINISH' => [
                    'label' => '표면처리',
                    'type' => 'select',
                    'options' => [
                        ['value' => 'hairline', 'label' => '헤어라인'],
                        ['value' => 'mirror', 'label' => '미러'],
                        ['value' => 'matte', 'label' => '무광'],
                    ],
                    'default' => 'hairline',
                ],
                'WELDING' => [
                    'label' => '용접 방식',
                    'type' => 'select',
                    'options' => [
                        ['value' => 'tig', 'label' => 'TIG'],
                        ['value' => 'mig', 'label' => 'MIG'],
                        ['value' => 'spot', 'label' => '스팟'],
                    ],
                    'default' => 'tig',
                ],
            ]);
        }

        return $commonSchema;
    }

    /**
     * 품목 단가 조회
     *
     * 품목 코드 배열을 받아 단가를 조회합니다.
     * FormulaEvaluatorService의 getItemPrice 로직을 활용합니다.
     *
     * @param  array  $itemCodes  품목 코드 배열
     * @return array 품목별 단가 정보 [item_code => ['unit_price' => number, 'item_name' => string]]
     */
    public function getItemPrices(array $itemCodes): array
    {
        $tenantId = $this->tenantId();

        if (! $tenantId) {
            return [];
        }

        $result = [];

        foreach ($itemCodes as $itemCode) {
            $price = $this->formulaEvaluator->getItemPrice($itemCode, $tenantId);
            $result[$itemCode] = [
                'item_code' => $itemCode,
                'unit_price' => $price,
            ];
        }

        return $result;
    }
}
