<?php

namespace Tests\Unit\Production;

use App\Services\Production\PrefixResolver;
use PHPUnit\Framework\TestCase;

class PrefixResolverTest extends TestCase
{
    private PrefixResolver $resolver;

    protected function setUp(): void
    {
        parent::setUp();
        $this->resolver = new PrefixResolver;
    }

    // ─────────────────────────────────────────────────
    // 가이드레일 벽면형(Wall) Prefix
    // ─────────────────────────────────────────────────

    /**
     * @dataProvider wallFinishProvider
     */
    public function test_wall_finish_prefix(string $productCode, string $expected): void
    {
        $this->assertEquals(
            $expected,
            $this->resolver->resolveGuideRailPrefix('finish', 'wall', $productCode)
        );
    }

    public static function wallFinishProvider(): array
    {
        return [
            'KSS01 → RS' => ['KSS01', 'RS'],
            'KQTS01 → RS' => ['KQTS01', 'RS'],
            'KSE01 → RE' => ['KSE01', 'RE'],
            'KWE01 → RE' => ['KWE01', 'RE'],
            'KTE01 → RS' => ['KTE01', 'RS'],
        ];
    }

    public function test_wall_body_prefix(): void
    {
        $this->assertEquals('RM', $this->resolver->resolveGuideRailPrefix('body', 'wall', 'KSS01'));
        $this->assertEquals('RM', $this->resolver->resolveGuideRailPrefix('body', 'wall', 'KSE01'));
        $this->assertEquals('RM', $this->resolver->resolveGuideRailPrefix('body', 'wall', 'KWE01'));
    }

    public function test_wall_body_steel_override(): void
    {
        $this->assertEquals('RT', $this->resolver->resolveGuideRailPrefix('body', 'wall', 'KTE01'));
    }

    public function test_wall_fixed_prefixes(): void
    {
        foreach (['KSS01', 'KSE01', 'KWE01', 'KTE01', 'KQTS01'] as $code) {
            $this->assertEquals('RC', $this->resolver->resolveGuideRailPrefix('c_type', 'wall', $code));
            $this->assertEquals('RD', $this->resolver->resolveGuideRailPrefix('d_type', 'wall', $code));
            $this->assertEquals('YY', $this->resolver->resolveGuideRailPrefix('extra_finish', 'wall', $code));
            $this->assertEquals('XX', $this->resolver->resolveGuideRailPrefix('base', 'wall', $code));
        }
    }

    // ─────────────────────────────────────────────────
    // 가이드레일 측면형(Side) Prefix
    // ─────────────────────────────────────────────────

    /**
     * @dataProvider sideFinishProvider
     */
    public function test_side_finish_prefix(string $productCode, string $expected): void
    {
        $this->assertEquals(
            $expected,
            $this->resolver->resolveGuideRailPrefix('finish', 'side', $productCode)
        );
    }

    public static function sideFinishProvider(): array
    {
        return [
            'KSS01 → SS' => ['KSS01', 'SS'],
            'KQTS01 → SS' => ['KQTS01', 'SS'],
            'KSE01 → SE' => ['KSE01', 'SE'],
            'KWE01 → SE' => ['KWE01', 'SE'],
            'KTE01 → SS' => ['KTE01', 'SS'],
        ];
    }

    public function test_side_body_prefix(): void
    {
        $this->assertEquals('SM', $this->resolver->resolveGuideRailPrefix('body', 'side', 'KSS01'));
        $this->assertEquals('SM', $this->resolver->resolveGuideRailPrefix('body', 'side', 'KSE01'));
    }

    public function test_side_body_steel_override(): void
    {
        $this->assertEquals('ST', $this->resolver->resolveGuideRailPrefix('body', 'side', 'KTE01'));
    }

    public function test_side_fixed_prefixes(): void
    {
        foreach (['KSS01', 'KSE01', 'KWE01', 'KTE01', 'KQTS01'] as $code) {
            $this->assertEquals('SC', $this->resolver->resolveGuideRailPrefix('c_type', 'side', $code));
            $this->assertEquals('SD', $this->resolver->resolveGuideRailPrefix('d_type', 'side', $code));
            $this->assertEquals('YY', $this->resolver->resolveGuideRailPrefix('extra_finish', 'side', $code));
            $this->assertEquals('XX', $this->resolver->resolveGuideRailPrefix('base', 'side', $code));
        }
    }

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

    public function test_bottom_bar_main_prefix(): void
    {
        // EGI 제품
        $this->assertEquals('BE', $this->resolver->resolveBottomBarPrefix('main', 'KSE01', 'EGI마감'));
        $this->assertEquals('BE', $this->resolver->resolveBottomBarPrefix('main', 'KWE01', 'EGI마감'));

        // SUS 제품
        $this->assertEquals('BS', $this->resolver->resolveBottomBarPrefix('main', 'KSS01', 'SUS마감'));
        $this->assertEquals('BS', $this->resolver->resolveBottomBarPrefix('main', 'KQTS01', 'SUS마감'));

        // 철재
        $this->assertEquals('TS', $this->resolver->resolveBottomBarPrefix('main', 'KTE01', 'EGI마감'));
    }

    public function test_bottom_bar_fixed_prefixes(): void
    {
        foreach (['KSS01', 'KSE01', 'KWE01', 'KTE01'] as $code) {
            $this->assertEquals('LA', $this->resolver->resolveBottomBarPrefix('lbar', $code, 'EGI마감'));
            $this->assertEquals('HH', $this->resolver->resolveBottomBarPrefix('reinforce', $code, 'EGI마감'));
            $this->assertEquals('YY', $this->resolver->resolveBottomBarPrefix('extra', $code, 'SUS마감'));
        }
    }

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

    public function test_shutter_box_standard_prefixes(): void
    {
        $this->assertEquals('CF', $this->resolver->resolveShutterBoxPrefix('front', true));
        $this->assertEquals('CL', $this->resolver->resolveShutterBoxPrefix('lintel', true));
        $this->assertEquals('CP', $this->resolver->resolveShutterBoxPrefix('inspection', true));
        $this->assertEquals('CB', $this->resolver->resolveShutterBoxPrefix('rear_corner', true));
        $this->assertEquals('XX', $this->resolver->resolveShutterBoxPrefix('top_cover', true));
        $this->assertEquals('XX', $this->resolver->resolveShutterBoxPrefix('fin_cover', true));
    }

    public function test_shutter_box_nonstandard_all_xx(): void
    {
        foreach (['front', 'lintel', 'inspection', 'rear_corner', 'top_cover', 'fin_cover'] as $part) {
            $this->assertEquals('XX', $this->resolver->resolveShutterBoxPrefix($part, false));
        }
    }

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

    public function test_smoke_barrier_always_gi(): void
    {
        $this->assertEquals('GI', $this->resolver->resolveSmokeBarrierPrefix());
    }

    // ─────────────────────────────────────────────────
    // lengthToCode 변환
    // ─────────────────────────────────────────────────

    /**
     * @dataProvider lengthCodeProvider
     */
    public function test_length_to_code(int $lengthMm, ?string $smokeCategory, ?string $expected): void
    {
        $this->assertSame($expected, PrefixResolver::lengthToCode($lengthMm, $smokeCategory));
    }

    public static function lengthCodeProvider(): array
    {
        return [
            '1219 → 12' => [1219, null, '12'],
            '2438 → 24' => [2438, null, '24'],
            '3000 → 30' => [3000, null, '30'],
            '3500 → 35' => [3500, null, '35'],
            '4000 → 40' => [4000, null, '40'],
            '4150 → 41' => [4150, null, '41'],
            '4200 → 42' => [4200, null, '42'],
            '4300 → 43' => [4300, null, '43'],
            'smoke w50 3000 → 53' => [3000, 'w50', '53'],
            'smoke w50 4000 → 54' => [4000, 'w50', '54'],
            'smoke w80 3000 → 83' => [3000, 'w80', '83'],
            'smoke w80 4000 → 84' => [4000, 'w80', '84'],
            'unknown length → null' => [9999, null, null],
        ];
    }

    // ─────────────────────────────────────────────────
    // buildItemCode
    // ─────────────────────────────────────────────────

    public function test_build_item_code(): void
    {
        $this->assertEquals('BD-RS-43', $this->resolver->buildItemCode('RS', 4300));
        $this->assertEquals('BD-RM-30', $this->resolver->buildItemCode('RM', 3000));
        $this->assertEquals('BD-GI-53', $this->resolver->buildItemCode('GI', 3000, 'w50'));
        $this->assertEquals('BD-GI-84', $this->resolver->buildItemCode('GI', 4000, 'w80'));
    }

    public function test_build_item_code_invalid_length_returns_null(): void
    {
        $this->assertNull($this->resolver->buildItemCode('RS', 9999));
    }

    // ─────────────────────────────────────────────────
    // partTypeName
    // ─────────────────────────────────────────────────

    public function test_part_type_name(): void
    {
        $this->assertEquals('마감재', PrefixResolver::partTypeName('finish'));
        $this->assertEquals('본체', PrefixResolver::partTypeName('body'));
        $this->assertEquals('C형', PrefixResolver::partTypeName('c_type'));
        $this->assertEquals('D형', PrefixResolver::partTypeName('d_type'));
        $this->assertEquals('별도마감', PrefixResolver::partTypeName('extra_finish'));
        $this->assertEquals('하부BASE', PrefixResolver::partTypeName('base'));
        $this->assertEquals('L-Bar', PrefixResolver::partTypeName('lbar'));
        $this->assertEquals('보강평철', PrefixResolver::partTypeName('reinforce'));
        $this->assertEquals('전면부', PrefixResolver::partTypeName('front'));
        $this->assertEquals('unknown_type', PrefixResolver::partTypeName('unknown_type'));
    }

    // ─────────────────────────────────────────────────
    // 전체 조합 커버리지 (productCode × guideType × partType)
    // ─────────────────────────────────────────────────

    public function test_all_product_code_guide_type_combinations_produce_non_empty_prefix(): void
    {
        $productCodes = ['KSS01', 'KSE01', 'KWE01', 'KTE01', 'KQTS01'];
        $guideTypes = ['wall', 'side'];
        $partTypes = ['finish', 'body', 'c_type', 'd_type', 'base'];

        foreach ($productCodes as $code) {
            foreach ($guideTypes as $guide) {
                foreach ($partTypes as $part) {
                    $prefix = $this->resolver->resolveGuideRailPrefix($part, $guide, $code);
                    $this->assertNotEmpty(
                        $prefix,
                        "Empty prefix for {$code}/{$guide}/{$part}"
                    );
                    $this->assertMatchesRegularExpression(
                        '/^[A-Z]{2}$/',
                        $prefix,
                        "Invalid prefix '{$prefix}' for {$code}/{$guide}/{$part}"
                    );
                }
            }
        }
    }
}
