<?php

namespace Tests\Unit\Production;

use App\DTOs\Production\DynamicBomEntry;
use InvalidArgumentException;
use PHPUnit\Framework\TestCase;

class DynamicBomEntryTest extends TestCase
{
    private function validData(): array
    {
        return [
            'child_item_id' => 15812,
            'child_item_code' => 'BD-RS-43',
            'lot_prefix' => 'RS',
            'part_type' => '마감재',
            'category' => 'guideRail',
            'material_type' => 'SUS',
            'length_mm' => 4300,
            'qty' => 2,
        ];
    }

    // ─────────────────────────────────────────────────
    // fromArray + toArray 라운드트립
    // ─────────────────────────────────────────────────

    public function test_from_array_creates_dto(): void
    {
        $entry = DynamicBomEntry::fromArray($this->validData());

        $this->assertEquals(15812, $entry->child_item_id);
        $this->assertEquals('BD-RS-43', $entry->child_item_code);
        $this->assertEquals('RS', $entry->lot_prefix);
        $this->assertEquals('마감재', $entry->part_type);
        $this->assertEquals('guideRail', $entry->category);
        $this->assertEquals('SUS', $entry->material_type);
        $this->assertEquals(4300, $entry->length_mm);
        $this->assertEquals(2, $entry->qty);
    }

    public function test_to_array_round_trip(): void
    {
        $data = $this->validData();
        $entry = DynamicBomEntry::fromArray($data);
        $this->assertEquals($data, $entry->toArray());
    }

    public function test_to_array_list(): void
    {
        $entries = [
            DynamicBomEntry::fromArray($this->validData()),
            DynamicBomEntry::fromArray(array_merge($this->validData(), [
                'child_item_id' => 15813,
                'child_item_code' => 'BD-RM-43',
                'lot_prefix' => 'RM',
                'part_type' => '본체',
            ])),
        ];

        $list = DynamicBomEntry::toArrayList($entries);
        $this->assertCount(2, $list);
        $this->assertEquals('BD-RS-43', $list[0]['child_item_code']);
        $this->assertEquals('BD-RM-43', $list[1]['child_item_code']);
    }

    // ─────────────────────────────────────────────────
    // 유효한 카테고리
    // ─────────────────────────────────────────────────

    /**
     * @dataProvider validCategoryProvider
     */
    public function test_valid_categories(string $category): void
    {
        $data = array_merge($this->validData(), ['category' => $category]);
        $entry = DynamicBomEntry::fromArray($data);
        $this->assertEquals($category, $entry->category);
    }

    public static function validCategoryProvider(): array
    {
        return [
            'guideRail' => ['guideRail'],
            'bottomBar' => ['bottomBar'],
            'shutterBox' => ['shutterBox'],
            'smokeBarrier' => ['smokeBarrier'],
        ];
    }

    // ─────────────────────────────────────────────────
    // 필수 필드 누락 검증
    // ─────────────────────────────────────────────────

    /**
     * @dataProvider requiredFieldProvider
     */
    public function test_missing_required_field_throws(string $field): void
    {
        $data = $this->validData();
        unset($data[$field]);

        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage("'{$field}' is required");
        DynamicBomEntry::fromArray($data);
    }

    public static function requiredFieldProvider(): array
    {
        return [
            'child_item_id' => ['child_item_id'],
            'child_item_code' => ['child_item_code'],
            'lot_prefix' => ['lot_prefix'],
            'part_type' => ['part_type'],
            'category' => ['category'],
            'material_type' => ['material_type'],
            'length_mm' => ['length_mm'],
            'qty' => ['qty'],
        ];
    }

    // ─────────────────────────────────────────────────
    // 값 제약 검증
    // ─────────────────────────────────────────────────

    public function test_invalid_child_item_id_throws(): void
    {
        $data = array_merge($this->validData(), ['child_item_id' => 0]);

        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('child_item_id must be positive');
        DynamicBomEntry::fromArray($data);
    }

    public function test_invalid_category_throws(): void
    {
        $data = array_merge($this->validData(), ['category' => 'invalidCategory']);

        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('category must be one of');
        DynamicBomEntry::fromArray($data);
    }

    public function test_zero_qty_throws(): void
    {
        $data = array_merge($this->validData(), ['qty' => 0]);

        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('qty must be positive');
        DynamicBomEntry::fromArray($data);
    }

    public function test_negative_qty_throws(): void
    {
        $data = array_merge($this->validData(), ['qty' => -1]);

        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('qty must be positive');
        DynamicBomEntry::fromArray($data);
    }

    // ─────────────────────────────────────────────────
    // float qty 허용
    // ─────────────────────────────────────────────────

    public function test_float_qty_allowed(): void
    {
        $data = array_merge($this->validData(), ['qty' => 1.5]);
        $entry = DynamicBomEntry::fromArray($data);
        $this->assertEquals(1.5, $entry->qty);
    }
}
