<?php

namespace App\Services\Calculation;

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;

class ParameterValidator
{
    /**
     * 파라미터 검증
     *
     * @param  array  $schema  파라미터 스키마
     * @param  array  $parameters  검증할 파라미터
     *
     * @throws ValidationException
     */
    public function validate(array $schema, array $parameters): void
    {
        $rules = $this->buildValidationRules($schema);
        $messages = $this->buildValidationMessages($schema);

        $validator = Validator::make($parameters, $rules, $messages);

        if ($validator->fails()) {
            throw new ValidationException($validator);
        }
    }

    /**
     * 검증 규칙 생성
     *
     * @param  array  $schema  파라미터 스키마
     * @return array 라라벨 검증 규칙
     */
    protected function buildValidationRules(array $schema): array
    {
        $rules = [];

        if (! isset($schema['required_parameters'])) {
            return $rules;
        }

        foreach ($schema['required_parameters'] as $param) {
            $key = $param['key'];
            $paramRules = [];

            // 필수 여부
            if ($param['required'] ?? false) {
                $paramRules[] = 'required';
            } else {
                $paramRules[] = 'nullable';
            }

            // 데이터 타입
            $type = $param['type'] ?? 'string';
            switch ($type) {
                case 'integer':
                    $paramRules[] = 'integer';
                    break;
                case 'numeric':
                case 'decimal':
                    $paramRules[] = 'numeric';
                    break;
                case 'boolean':
                    $paramRules[] = 'boolean';
                    break;
                case 'select':
                    if (isset($param['options'])) {
                        $validOptions = is_array($param['options']) ? array_keys($param['options']) : $param['options'];
                        $paramRules[] = 'in:'.implode(',', $validOptions);
                    }
                    break;
                default:
                    $paramRules[] = 'string';
            }

            // 최소값/최대값
            if (isset($param['min'])) {
                $paramRules[] = 'min:'.$param['min'];
            }
            if (isset($param['max'])) {
                $paramRules[] = 'max:'.$param['max'];
            }

            // 정규표현식
            if (isset($param['pattern'])) {
                $paramRules[] = 'regex:'.$param['pattern'];
            }

            $rules[$key] = implode('|', $paramRules);
        }

        return $rules;
    }

    /**
     * 검증 메시지 생성
     *
     * @param  array  $schema  파라미터 스키마
     * @return array 검증 메시지
     */
    protected function buildValidationMessages(array $schema): array
    {
        $messages = [];

        if (! isset($schema['required_parameters'])) {
            return $messages;
        }

        foreach ($schema['required_parameters'] as $param) {
            $key = $param['key'];
            $label = $param['label'] ?? $key;

            $messages["{$key}.required"] = "{$label}은(는) 필수 입력 항목입니다.";
            $messages["{$key}.integer"] = "{$label}은(는) 정수여야 합니다.";
            $messages["{$key}.numeric"] = "{$label}은(는) 숫자여야 합니다.";
            $messages["{$key}.boolean"] = "{$label}은(는) 참/거짓 값이어야 합니다.";
            $messages["{$key}.string"] = "{$label}은(는) 문자열이어야 합니다.";

            if (isset($param['min'])) {
                $messages["{$key}.min"] = "{$label}은(는) 최소 {$param['min']} 이상이어야 합니다.";
            }
            if (isset($param['max'])) {
                $messages["{$key}.max"] = "{$label}은(는) 최대 {$param['max']} 이하여야 합니다.";
            }

            if (isset($param['options'])) {
                $validOptions = is_array($param['options']) ? array_values($param['options']) : $param['options'];
                $messages["{$key}.in"] = "{$label}은(는) 다음 중 하나여야 합니다: ".implode(', ', $validOptions);
            }

            if (isset($param['pattern'])) {
                $messages["{$key}.regex"] = "{$label}의 형식이 올바르지 않습니다.";
            }
        }

        return $messages;
    }

    /**
     * 범위 검증
     *
     * @param  array  $parameters  파라미터
     * @param  array  $ranges  범위 정의
     */
    public function validateRanges(array $parameters, array $ranges): void
    {
        foreach ($ranges as $key => $range) {
            if (! isset($parameters[$key])) {
                continue;
            }

            $value = $parameters[$key];

            if (isset($range['min']) && $value < $range['min']) {
                throw new ValidationException(validator([], []), [
                    $key => ["{$key}는 최소 {$range['min']} 이상이어야 합니다."],
                ]);
            }

            if (isset($range['max']) && $value > $range['max']) {
                throw new ValidationException(validator([], []), [
                    $key => ["{$key}는 최대 {$range['max']} 이하여야 합니다."],
                ]);
            }
        }
    }

    /**
     * 업체별 특수 검증
     *
     * @param  array  $parameters  파라미터
     * @param  string  $companyType  업체 타입
     */
    public function validateCompanySpecific(array $parameters, string $companyType): void
    {
        switch ($companyType) {
            case '경동기업':
                $this->validateKyungdongRules($parameters);
                break;
            case '삼성물산':
                $this->validateSamsungRules($parameters);
                break;
            default:
                // 기본 검증만 수행
                break;
        }
    }

    /**
     * 경동기업 특수 검증 규칙
     */
    protected function validateKyungdongRules(array $parameters): void
    {
        // 경동기업 특수 규칙 예시
        if (isset($parameters['W0']) && isset($parameters['H0'])) {
            $area = ($parameters['W0'] * $parameters['H0']) / 1000000;

            // 면적이 너무 크면 경고
            if ($area > 50) {
                throw new ValidationException(validator([], []), [
                    'area' => ['면적이 50㎡를 초과합니다. 특수 산출식이 필요할 수 있습니다.'],
                ]);
            }
        }

        // 제품타입별 사이즈 제한
        if ($parameters['product_type'] === 'screen' && isset($parameters['W0'])) {
            if ($parameters['W0'] > 12000) {
                throw new ValidationException(validator([], []), [
                    'W0' => ['스크린 제품은 가로 12,000mm를 초과할 수 없습니다.'],
                ]);
            }
        }
    }

    /**
     * 삼성물산 특수 검증 규칙
     */
    protected function validateSamsungRules(array $parameters): void
    {
        // 삼성물산 특수 규칙 (예시)
        // 실제로는 해당 업체의 요구사항에 따라 구현
    }
}
