<?php

namespace App\Services\Quote;

use App\Models\Items\Item;
use App\Models\Products\Price;
use Illuminate\Support\Facades\DB;

/**
 * 견적 단가 조회 서비스
 *
 * items + item_details + prices 테이블 기반 단가 조회
 * kd_price_tables 대체
 */
class EstimatePriceService
{
    private int $tenantId;

    /** @var array 단가 캐시 (세션 내 중복 조회 방지) */
    private array $cache = [];

    public function __construct(int $tenantId)
    {
        $this->tenantId = $tenantId;
    }

    // =========================================================================
    // BDmodels 단가 조회 (절곡품)
    // =========================================================================

    /**
     * BDmodels 단가 조회
     *
     * item_details 컬럼 매핑:
     *   product_category = 'bdmodels'
     *   part_type = seconditem (가이드레일, 케이스, 마구리, L-BAR, 하단마감재, 보강평철, 연기차단재)
     *   specification = spec (120*70, 500*380 등)
     * items.attributes:
     *   model_name = KSS01, KSS02 등
     *   finishing_type = SUS, EGI
     */
    public function getBDModelPrice(
        string $secondItem,
        ?string $modelName = null,
        ?string $finishingType = null,
        ?string $spec = null
    ): float {
        $cacheKey = "bdmodel:{$secondItem}:{$modelName}:{$finishingType}:{$spec}";

        if (isset($this->cache[$cacheKey])) {
            return $this->cache[$cacheKey];
        }

        $query = DB::table('items')
            ->join('item_details', 'item_details.item_id', '=', 'items.id')
            ->join('prices', 'prices.item_id', '=', 'items.id')
            ->where('items.tenant_id', $this->tenantId)
            ->where('items.is_active', true)
            ->whereNull('items.deleted_at')
            ->where('item_details.product_category', 'bdmodels')
            ->where('item_details.part_type', $secondItem);

        if ($modelName) {
            $query->where('items.attributes->model_name', $modelName);
        } else {
            $query->where(function ($q) {
                $q->whereNull('items.attributes->model_name')
                    ->orWhere('items.attributes->model_name', '');
            });
        }

        if ($finishingType) {
            $query->where('items.attributes->finishing_type', $finishingType);
        }

        if ($spec) {
            $query->where('item_details.specification', $spec);
        }

        // 현재 유효한 단가
        $today = now()->toDateString();
        $query->where('prices.effective_from', '<=', $today)
            ->where(function ($q) use ($today) {
                $q->whereNull('prices.effective_to')
                    ->orWhere('prices.effective_to', '>=', $today);
            })
            ->whereNull('prices.deleted_at');

        $price = (float) ($query->value('prices.sales_price') ?? 0);

        $this->cache[$cacheKey] = $price;

        return $price;
    }

    /**
     * 케이스 단가
     */
    public function getCasePrice(string $spec): float
    {
        return $this->getBDModelPrice('케이스', null, null, $spec);
    }

    /**
     * 가이드레일 단가
     */
    public function getGuideRailPrice(string $modelName, string $finishingType, string $spec): float
    {
        return $this->getBDModelPrice('가이드레일', $modelName, $finishingType, $spec);
    }

    /**
     * 하단마감재(하장바) 단가
     */
    public function getBottomBarPrice(string $modelName, string $finishingType): float
    {
        return $this->getBDModelPrice('하단마감재', $modelName, $finishingType);
    }

    /**
     * L-BAR 단가
     */
    public function getLBarPrice(string $modelName): float
    {
        return $this->getBDModelPrice('L-BAR', $modelName);
    }

    /**
     * 보강평철 단가
     */
    public function getFlatBarPrice(): float
    {
        return $this->getBDModelPrice('보강평철');
    }

    /**
     * 케이스 마구리 단가
     */
    public function getCaseCapPrice(string $spec): float
    {
        return $this->getBDModelPrice('마구리', null, null, $spec);
    }

    /**
     * 케이스용 연기차단재 단가
     */
    public function getCaseSmokeBlockPrice(): float
    {
        return $this->getBDModelPrice('케이스용 연기차단재');
    }

    /**
     * 가이드레일용 연기차단재 단가
     */
    public function getRailSmokeBlockPrice(): float
    {
        return $this->getBDModelPrice('가이드레일용 연기차단재');
    }

    // =========================================================================
    // 모터/제어기 단가
    // =========================================================================

    /**
     * 모터 단가
     *
     * chandj col2는 '150K(S)', '300K(S)', '300K' 등 다양한 형식
     * handler는 '150K', '300K' 등 단순 용량으로 호출
     * LIKE 매칭 + 380V 기본 전압 필터 적용
     */
    public function getMotorPrice(string $motorCapacity, string $voltage = '380'): float
    {
        $cacheKey = "motor:{$motorCapacity}:{$voltage}";

        if (isset($this->cache[$cacheKey])) {
            return $this->cache[$cacheKey];
        }

        $today = now()->toDateString();

        $price = (float) (DB::table('items')
            ->join('item_details', 'item_details.item_id', '=', 'items.id')
            ->join('prices', 'prices.item_id', '=', 'items.id')
            ->where('items.tenant_id', $this->tenantId)
            ->where('items.is_active', true)
            ->whereNull('items.deleted_at')
            ->where('item_details.product_category', 'motor')
            ->where('item_details.part_type', 'LIKE', "{$motorCapacity}%")
            ->where('items.attributes->voltage', $voltage)
            ->where('prices.effective_from', '<=', $today)
            ->where(function ($q) use ($today) {
                $q->whereNull('prices.effective_to')
                    ->orWhere('prices.effective_to', '>=', $today);
            })
            ->whereNull('prices.deleted_at')
            ->value('prices.sales_price') ?? 0);

        $this->cache[$cacheKey] = $price;

        return $price;
    }

    /**
     * 제어기 단가
     */
    public function getControllerPrice(string $controllerType): float
    {
        return $this->getEstimatePartPrice('controller', $controllerType);
    }

    // =========================================================================
    // 부자재 단가
    // =========================================================================

    /**
     * 샤프트 단가
     *
     * chandj col10은 '0.3', '3', '6' 등 혼재 포맷
     * 정수면 '6', 소수면 '0.3' 그대로 저장됨
     */
    public function getShaftPrice(string $size, float $length): float
    {
        // chandj 원본 포맷에 맞게 변환: 정수면 정수형, 소수면 소수형
        $lengthStr = ($length == (int) $length) ? (string) (int) $length : (string) $length;
        $cacheKey = "shaft:{$size}:{$lengthStr}";

        if (isset($this->cache[$cacheKey])) {
            return $this->cache[$cacheKey];
        }

        $price = $this->getEstimatePartPriceBySpec('shaft', $size, $lengthStr);
        $this->cache[$cacheKey] = $price;

        return $price;
    }

    /**
     * 파이프 단가
     */
    public function getPipePrice(string $thickness, int $length): float
    {
        return $this->getEstimatePartPriceBySpec('pipe', $thickness, (string) $length);
    }

    /**
     * 모터 받침용 앵글 단가 (bracket angle)
     *
     * 5130: calculateAngle(qty, itemList, '스크린용') → col2 검색
     * chandj col2 값: '스크린용', '철제300K', '철제400K', '철제800K'
     */
    public function getAnglePrice(string $searchOption): float
    {
        $cacheKey = "angle_bracket:{$searchOption}";

        if (isset($this->cache[$cacheKey])) {
            return $this->cache[$cacheKey];
        }

        $today = now()->toDateString();

        $price = (float) (DB::table('items')
            ->join('item_details', 'item_details.item_id', '=', 'items.id')
            ->join('prices', 'prices.item_id', '=', 'items.id')
            ->where('items.tenant_id', $this->tenantId)
            ->where('items.is_active', true)
            ->whereNull('items.deleted_at')
            ->where('item_details.product_category', 'angle_bracket')
            ->where('item_details.part_type', $searchOption)
            ->where('prices.effective_from', '<=', $today)
            ->where(function ($q) use ($today) {
                $q->whereNull('prices.effective_to')
                    ->orWhere('prices.effective_to', '>=', $today);
            })
            ->whereNull('prices.deleted_at')
            ->value('prices.sales_price') ?? 0);

        $this->cache[$cacheKey] = $price;

        return $price;
    }

    /**
     * 부자재용 앵글 단가 (main angle)
     *
     * 5130: calculateMainAngle(1, itemList, '앵글3T', '2.5') → col4+col10 검색
     */
    public function getMainAnglePrice(string $angleType, string $size): float
    {
        $cacheKey = "angle_main:{$angleType}:{$size}";

        if (isset($this->cache[$cacheKey])) {
            return $this->cache[$cacheKey];
        }

        $price = $this->getEstimatePartPriceBySpec('angle_main', $angleType, $size);
        $this->cache[$cacheKey] = $price;

        return $price;
    }

    /**
     * 원자재 단가
     */
    public function getRawMaterialPrice(string $materialName): float
    {
        return $this->getEstimatePartPrice('raw_material', $materialName);
    }

    // =========================================================================
    // 내부 헬퍼
    // =========================================================================

    /**
     * product_category + part_type 기반 단가 조회
     */
    private function getEstimatePartPrice(string $productCategory, string $partType): float
    {
        $cacheKey = "{$productCategory}:{$partType}";

        if (isset($this->cache[$cacheKey])) {
            return $this->cache[$cacheKey];
        }

        $today = now()->toDateString();

        $price = (float) (DB::table('items')
            ->join('item_details', 'item_details.item_id', '=', 'items.id')
            ->join('prices', 'prices.item_id', '=', 'items.id')
            ->where('items.tenant_id', $this->tenantId)
            ->where('items.is_active', true)
            ->whereNull('items.deleted_at')
            ->where('item_details.product_category', $productCategory)
            ->where('item_details.part_type', $partType)
            ->where('prices.effective_from', '<=', $today)
            ->where(function ($q) use ($today) {
                $q->whereNull('prices.effective_to')
                    ->orWhere('prices.effective_to', '>=', $today);
            })
            ->whereNull('prices.deleted_at')
            ->value('prices.sales_price') ?? 0);

        $this->cache[$cacheKey] = $price;

        return $price;
    }

    /**
     * product_category + spec1 + spec2 기반 단가 조회
     */
    private function getEstimatePartPriceBySpec(string $productCategory, string $spec1, string $spec2): float
    {
        $cacheKey = "{$productCategory}:{$spec1}:{$spec2}";

        if (isset($this->cache[$cacheKey])) {
            return $this->cache[$cacheKey];
        }

        $today = now()->toDateString();

        $price = (float) (DB::table('items')
            ->join('item_details', 'item_details.item_id', '=', 'items.id')
            ->join('prices', 'prices.item_id', '=', 'items.id')
            ->where('items.tenant_id', $this->tenantId)
            ->where('items.is_active', true)
            ->whereNull('items.deleted_at')
            ->where('item_details.product_category', $productCategory)
            ->where('item_details.part_type', $spec1)
            ->where('item_details.specification', $spec2)
            ->where('prices.effective_from', '<=', $today)
            ->where(function ($q) use ($today) {
                $q->whereNull('prices.effective_to')
                    ->orWhere('prices.effective_to', '>=', $today);
            })
            ->whereNull('prices.deleted_at')
            ->value('prices.sales_price') ?? 0);

        $this->cache[$cacheKey] = $price;

        return $price;
    }

    /**
     * 캐시 초기화
     */
    public function clearCache(): void
    {
        $this->cache = [];
    }
}