<?php

namespace App\Services\Calculation;

use App\Models\Calculation\CalculationConfig;
use App\Models\Design\BomTemplate;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;

class CalculationEngine
{
    protected FormulaParser $parser;

    protected ParameterValidator $validator;

    public function __construct(FormulaParser $parser, ParameterValidator $validator)
    {
        $this->parser = $parser;
        $this->validator = $validator;
    }

    /**
     * BOM 계산 실행
     *
     * @param  int  $bomTemplateId  BOM 템플릿 ID
     * @param  array  $parameters  입력 파라미터
     * @param  string|null  $companyName  업체명 (null시 기본값 사용)
     * @return array 계산 결과
     */
    public function calculateBOM(int $bomTemplateId, array $parameters, ?string $companyName = null): array
    {
        try {
            // BOM 템플릿 조회
            $bomTemplate = BomTemplate::with(['items', 'modelVersion.model'])
                ->findOrFail($bomTemplateId);

            // 파라미터 검증
            $this->validateParameters($bomTemplate, $parameters);

            // 중간 계산값 도출 (W1, H1, 면적, 중량 등)
            $calculatedValues = $this->calculateIntermediateValues($bomTemplate, $parameters, $companyName);

            // BOM 아이템별 수량 계산
            $bomItems = $this->calculateBomItems($bomTemplate->items, $calculatedValues, $parameters, $companyName);

            return [
                'success' => true,
                'bom_template' => [
                    'id' => $bomTemplate->id,
                    'name' => $bomTemplate->name,
                    'company_type' => $bomTemplate->company_type,
                    'formula_version' => $bomTemplate->formula_version,
                ],
                'input_parameters' => $parameters,
                'calculated_values' => $calculatedValues,
                'bom_items' => $bomItems,
                'calculation_timestamp' => now(),
            ];

        } catch (\Exception $e) {
            Log::error('BOM 계산 실패', [
                'bom_template_id' => $bomTemplateId,
                'parameters' => $parameters,
                'error' => $e->getMessage(),
            ]);

            return [
                'success' => false,
                'error' => $e->getMessage(),
                'bom_template_id' => $bomTemplateId,
            ];
        }
    }

    /**
     * 견적시 필요한 파라미터 스키마 추출
     *
     * @param  int  $bomTemplateId  BOM 템플릿 ID
     * @return array 파라미터 스키마
     */
    public function getRequiredParameters(int $bomTemplateId): array
    {
        $bomTemplate = BomTemplate::findOrFail($bomTemplateId);

        $schema = $bomTemplate->calculation_schema;
        if (! $schema) {
            return $this->getDefaultParameterSchema($bomTemplate);
        }

        return $schema;
    }

    /**
     * 중간 계산값 도출 (W1, H1, 면적, 중량 등)
     */
    protected function calculateIntermediateValues(BomTemplate $bomTemplate, array $parameters, ?string $companyName): array
    {
        $company = $companyName ?: $bomTemplate->company_type;
        $calculated = [];

        // 기본 파라미터에서 추출
        $W0 = $parameters['W0'] ?? 0;
        $H0 = $parameters['H0'] ?? 0;
        $productType = $parameters['product_type'] ?? 'screen';

        // 업체별 제작사이즈 계산
        $sizeFormula = $this->getCalculationConfig($company, 'manufacturing_size');
        if ($sizeFormula) {
            $calculated = array_merge($calculated, $this->parser->execute($sizeFormula->formula_expression, [
                'W0' => $W0,
                'H0' => $H0,
                'product_type' => $productType,
            ]));
        } else {
            // 기본 공식 (경동기업 기준)
            if ($productType === 'screen') {
                $calculated['W1'] = $W0 + 160;
                $calculated['H1'] = $H0 + 350;
            } else {
                $calculated['W1'] = $W0 + 110;
                $calculated['H1'] = $H0 + 350;
            }
        }

        // 면적 계산
        $calculated['area'] = ($calculated['W1'] * $calculated['H1']) / 1000000;

        // 중량 계산
        $weightFormula = $this->getCalculationConfig($company, 'weight_calculation');
        if ($weightFormula) {
            $weightResult = $this->parser->execute($weightFormula->formula_expression, array_merge($parameters, $calculated));
            $calculated['weight'] = $weightResult['weight'] ?? 0;
        } else {
            // 기본 중량 공식 (스크린)
            if ($productType === 'screen') {
                $calculated['weight'] = ($calculated['area'] * 2) + ($W0 / 1000 * 14.17);
            } else {
                $calculated['weight'] = $calculated['area'] * 40;
            }
        }

        return $calculated;
    }

    /**
     * BOM 아이템별 수량 계산
     */
    protected function calculateBomItems(Collection $bomItems, array $calculatedValues, array $parameters, ?string $companyName): array
    {
        $results = [];

        foreach ($bomItems as $item) {
            if (! $item->is_calculated) {
                // 고정 수량 아이템
                $results[] = [
                    'item_id' => $item->id,
                    'ref_type' => $item->ref_type,
                    'ref_id' => $item->ref_id,
                    'original_qty' => $item->qty,
                    'calculated_qty' => $item->qty,
                    'is_calculated' => false,
                    'calculation_formula' => null,
                ];

                continue;
            }

            // 계산식 적용 아이템
            try {
                $allParameters = array_merge($parameters, $calculatedValues);
                $calculatedQty = $this->parser->execute($item->calculation_formula, $allParameters);

                $results[] = [
                    'item_id' => $item->id,
                    'ref_type' => $item->ref_type,
                    'ref_id' => $item->ref_id,
                    'original_qty' => $item->qty,
                    'calculated_qty' => $calculatedQty['result'] ?? $item->qty,
                    'is_calculated' => true,
                    'calculation_formula' => $item->calculation_formula,
                    'depends_on' => $item->depends_on,
                ];
            } catch (\Exception $e) {
                Log::warning('BOM 아이템 계산 실패', [
                    'item_id' => $item->id,
                    'formula' => $item->calculation_formula,
                    'error' => $e->getMessage(),
                ]);

                // 계산 실패시 원래 수량 사용
                $results[] = [
                    'item_id' => $item->id,
                    'ref_type' => $item->ref_type,
                    'ref_id' => $item->ref_id,
                    'original_qty' => $item->qty,
                    'calculated_qty' => $item->qty,
                    'is_calculated' => false,
                    'calculation_error' => $e->getMessage(),
                ];
            }
        }

        return $results;
    }

    /**
     * 파라미터 검증
     */
    protected function validateParameters(BomTemplate $bomTemplate, array $parameters): void
    {
        $schema = $bomTemplate->calculation_schema;
        if (! $schema) {
            return;
        }

        $this->validator->validate($schema, $parameters);
    }

    /**
     * 업체별 산출식 설정 조회
     */
    protected function getCalculationConfig(string $companyName, string $formulaType): ?CalculationConfig
    {
        return CalculationConfig::where('company_name', $companyName)
            ->where('formula_type', $formulaType)
            ->where('is_active', true)
            ->latest('version')
            ->first();
    }

    /**
     * 기본 파라미터 스키마 생성
     */
    protected function getDefaultParameterSchema(BomTemplate $bomTemplate): array
    {
        return [
            'required_parameters' => [
                [
                    'key' => 'W0',
                    'label' => '오픈사이즈 가로(mm)',
                    'type' => 'integer',
                    'required' => true,
                    'min' => 500,
                    'max' => 15000,
                ],
                [
                    'key' => 'H0',
                    'label' => '오픈사이즈 세로(mm)',
                    'type' => 'integer',
                    'required' => true,
                    'min' => 500,
                    'max' => 5000,
                ],
                [
                    'key' => 'product_type',
                    'label' => '제품타입',
                    'type' => 'select',
                    'options' => ['screen' => '스크린', 'steel' => '철재'],
                    'required' => true,
                ],
                [
                    'key' => 'installation_type',
                    'label' => '설치방식',
                    'type' => 'select',
                    'options' => ['wall' => '벽면형', 'side' => '측면형', 'mixed' => '혼합형'],
                    'required' => false,
                ],
            ],
            'company_type' => $bomTemplate->company_type ?: 'default',
            'formula_version' => $bomTemplate->formula_version ?: 'v1.0',
        ];
    }
}
