<?php

namespace App\Services\Production;

use Illuminate\Support\Facades\DB;

/**
 * 절곡 세부품목 LOT Prefix 결정 및 BD-XX-NN 코드 생성
 *
 * 제품코드 + 마감재질 + 가이드타입 → LOT prefix → BD-XX-NN 코드 → items.id
 */
class PrefixResolver
{
    // ─────────────────────────────────────────────────
    // 가이드레일 Prefix 맵
    // ─────────────────────────────────────────────────

    /** 벽면형(Wall) prefix: partType → prefix (finish는 productCode별 분기) */
    private const WALL_PREFIXES = [
        'finish' => ['KSS' => 'RS', 'KQTS' => 'RS', 'KSE' => 'RE', 'KWE' => 'RE', 'KTE' => 'RS'],
        'body' => 'RM',
        'c_type' => 'RC',
        'd_type' => 'RD',
        'extra_finish' => 'YY',
        'base' => 'XX',
    ];

    /** 측면형(Side) prefix */
    private const SIDE_PREFIXES = [
        'finish' => ['KSS' => 'SS', 'KQTS' => 'SS', 'KSE' => 'SE', 'KWE' => 'SE', 'KTE' => 'SS'],
        'body' => 'SM',
        'c_type' => 'SC',
        'd_type' => 'SD',
        'extra_finish' => 'YY',
        'base' => 'XX',
    ];

    /** 철재(KTE01) body 오버라이드 */
    private const STEEL_BODY_OVERRIDES = [
        'wall' => 'RT',
        'side' => 'ST',
    ];

    // ─────────────────────────────────────────────────
    // 하단마감재 Prefix 맵
    // ─────────────────────────────────────────────────

    /** 하단마감재 main prefix: finishMaterial 기반 */
    private const BOTTOM_BAR_MAIN = [
        'EGI' => 'BE',
        'SUS' => 'BS',
        'STEEL' => 'TS',
    ];

    // ─────────────────────────────────────────────────
    // 셔터박스 Prefix 맵
    // ─────────────────────────────────────────────────

    /** 표준 사이즈(500*380) 셔터박스 prefix */
    private const SHUTTER_STANDARD = [
        'front' => 'CF',
        'lintel' => 'CL',
        'inspection' => 'CP',
        'rear_corner' => 'CB',
        'top_cover' => 'XX',
        'fin_cover' => 'XX',
    ];

    // ─────────────────────────────────────────────────
    // 길이코드 매핑
    // ─────────────────────────────────────────────────

    private const LENGTH_TO_CODE = [
        1219 => '12',
        2438 => '24',
        3000 => '30',
        3500 => '35',
        4000 => '40',
        4150 => '41',
        4200 => '42',
        4300 => '43',
    ];

    /** 연기차단재 전용 길이코드 */
    private const SMOKE_LENGTH_TO_CODE = [
        'w50' => [3000 => '53', 4000 => '54'],
        'w80' => [3000 => '83', 4000 => '84'],
    ];

    /** 파트타입 한글명 */
    private const PART_TYPE_NAMES = [
        'finish' => '마감재',
        'body' => '본체',
        'c_type' => 'C형',
        'd_type' => 'D형',
        'extra_finish' => '별도마감',
        'base' => '하부BASE',
        'main' => '메인',
        'lbar' => 'L-Bar',
        'reinforce' => '보강평철',
        'extra' => '별도마감',
        'front' => '전면부',
        'lintel' => '린텔부',
        'inspection' => '점검구',
        'rear_corner' => '후면코너부',
        'top_cover' => '상부덮개',
        'fin_cover' => '마구리',
        'smoke' => '연기차단재',
    ];

    /** items.id 캐시: code → id */
    private array $itemIdCache = [];

    // ─────────────────────────────────────────────────
    // 가이드레일
    // ─────────────────────────────────────────────────

    /**
     * 가이드레일 세부품목의 prefix 결정
     *
     * @param  string  $partType  'finish', 'body', 'c_type', 'd_type', 'extra_finish', 'base'
     * @param  string  $guideType  'wall', 'side'
     * @param  string  $productCode  'KSS01', 'KSE01', 'KWE01', 'KTE01', 'KQTS01'
     * @return string prefix (빈 문자열이면 해당 파트 없음)
     */
    public function resolveGuideRailPrefix(string $partType, string $guideType, string $productCode): string
    {
        $prefixMap = $guideType === 'wall' ? self::WALL_PREFIXES : self::SIDE_PREFIXES;
        $codePrefix = $this->extractCodePrefix($productCode);
        $isSteel = $codePrefix === 'KTE';

        // body: 철재 오버라이드
        if ($partType === 'body' && $isSteel) {
            return self::STEEL_BODY_OVERRIDES[$guideType] ?? '';
        }

        // finish: productCode별 분기
        if ($partType === 'finish') {
            $finishMap = $prefixMap['finish'] ?? [];

            return $finishMap[$codePrefix] ?? '';
        }

        // extra_finish, base, c_type, d_type, body: 고정 prefix
        return $prefixMap[$partType] ?? '';
    }

    // ─────────────────────────────────────────────────
    // 하단마감재
    // ─────────────────────────────────────────────────

    /**
     * 하단마감재 세부품목의 prefix 결정
     *
     * @param  string  $partType  'main', 'lbar', 'reinforce', 'extra'
     * @param  string  $productCode  'KSS01', 'KSE01', etc.
     * @param  string  $finishMaterial  'EGI마감', 'SUS마감'
     * @return string prefix
     */
    public function resolveBottomBarPrefix(string $partType, string $productCode, string $finishMaterial): string
    {
        if ($partType === 'lbar') {
            return 'LA';
        }
        if ($partType === 'reinforce') {
            return 'HH';
        }
        if ($partType === 'extra') {
            return 'YY';
        }

        // main: 재질 기반
        $codePrefix = $this->extractCodePrefix($productCode);
        $isSteel = $codePrefix === 'KTE';

        if ($isSteel) {
            return 'TS';
        }

        $isSUS = in_array($codePrefix, ['KSS', 'KQTS']);

        return $isSUS ? 'BS' : 'BE';
    }

    // ─────────────────────────────────────────────────
    // 셔터박스
    // ─────────────────────────────────────────────────

    /**
     * 셔터박스 세부품목의 prefix 결정
     *
     * CF/CL/CP/CB 품목은 모든 길이에 등록되어 있으므로 boxSize 무관하게 적용.
     * top_cover, fin_cover는 전용 품목 없이 XX(하부BASE/상부/마구리) 공용.
     *
     * @param  string  $partType  'front', 'lintel', 'inspection', 'rear_corner', 'top_cover', 'fin_cover'
     * @return string prefix
     */
    public function resolveShutterBoxPrefix(string $partType): string
    {
        return self::SHUTTER_STANDARD[$partType] ?? 'XX';
    }

    // ─────────────────────────────────────────────────
    // 연기차단재
    // ─────────────────────────────────────────────────

    /**
     * 연기차단재 세부품목의 prefix 결정 (항상 GI)
     */
    public function resolveSmokeBarrierPrefix(): string
    {
        return 'GI';
    }

    // ─────────────────────────────────────────────────
    // 코드 생성 및 조회
    // ─────────────────────────────────────────────────

    /**
     * prefix + 길이(mm) → BD-XX-NN 코드 생성
     *
     * @param  string  $prefix  LOT prefix (RS, RM, etc.)
     * @param  int  $lengthMm  길이 (mm)
     * @param  string|null  $smokeCategory  연기차단재 카테고리 ('w50', 'w80')
     * @return string|null BD 코드 (길이코드 변환 실패 시 null)
     */
    public function buildItemCode(string $prefix, int $lengthMm, ?string $smokeCategory = null): ?string
    {
        $lengthCode = self::lengthToCode($lengthMm, $smokeCategory);
        if ($lengthCode === null) {
            return null;
        }

        return "BD-{$prefix}-{$lengthCode}";
    }

    /**
     * BD-XX-NN 코드 → items.id 조회 (캐시)
     *
     * @return int|null items.id (미등록 시 null)
     */
    public function resolveItemId(string $itemCode, int $tenantId = 287): ?int
    {
        $cacheKey = "{$tenantId}:{$itemCode}";

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

        $id = DB::table('items')
            ->where('tenant_id', $tenantId)
            ->where('code', $itemCode)
            ->whereNull('deleted_at')
            ->value('id');

        $this->itemIdCache[$cacheKey] = $id;

        return $id;
    }

    /**
     * 길이(mm) → 길이코드 변환
     *
     * @param  int  $lengthMm  길이 (mm)
     * @param  string|null  $smokeCategory  연기차단재 카테고리 ('w50', 'w80')
     * @return string|null 길이코드 (변환 불가 시 null)
     */
    public static function lengthToCode(int $lengthMm, ?string $smokeCategory = null): ?string
    {
        // 연기차단재 전용 코드
        if ($smokeCategory && isset(self::SMOKE_LENGTH_TO_CODE[$smokeCategory][$lengthMm])) {
            return self::SMOKE_LENGTH_TO_CODE[$smokeCategory][$lengthMm];
        }

        return self::LENGTH_TO_CODE[$lengthMm] ?? null;
    }

    /**
     * 파트타입 한글명 반환
     */
    public static function partTypeName(string $partType): string
    {
        return self::PART_TYPE_NAMES[$partType] ?? $partType;
    }

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

    // ─────────────────────────────────────────────────
    // private
    // ─────────────────────────────────────────────────

    /**
     * 'KSS01' → 'KSS', 'KQTS01' → 'KQTS' 등 제품코드 prefix 추출
     */
    private function extractCodePrefix(string $productCode): string
    {
        return preg_replace('/\d+$/', '', $productCode);
    }
}
