"""
Unit Tests for Vertical Column-Major Inventory Packer (Doc 63 SSoT)
===================================================================
Kiểm thử thuật toán sắp xếp túi đồ và rương đồ theo chiều dọc:
- Gom toàn bộ đồ nhỏ 1x1 sang các cột ngoài cùng bên phải (Cột 11 -> 10...).
- Dồn các trang bị lớn (2x4, 2x3, 2x2) theo các cột dọc bên trái (Cột 0 -> 1...).
- Chứng minh loại bỏ triệt để hiện tượng phân mảnh không gian (Fragmentation),
  bảo toàn khối chữ nhật trống có chiều cao 4-5 ô cho trang bị kích thước lớn.
"""

import pytest
from src.assistant_tool.inventory_sorter import (
    VerticalInventoryPacker,
    InventoryItemSlot,
    ItemDimension,
)


def test_vertical_inventory_packing_layout():
    """Kiểm tra việc sắp xếp: đồ lớn dồn sang trái, đồ 1x1 dồn sang cột ngoài cùng bên phải."""
    packer = VerticalInventoryPacker(cols=12, rows=5)

    # Giả lập túi đồ có:
    # - 1 Quarterstaff 2x4 (đang nằm lộn xộn ở col 5, row 0)
    # - 1 Body Armour 2x3 (đang nằm ở col 8, row 1)
    # - 3 Currency Orbs 1x1 (nằm rải rác ở col 0, col 1, col 2)
    items = [
        InventoryItemSlot(item_id="staff_1", name="Crescent Quarterstaff", col=5, row=0, width=2, height=4),
        InventoryItemSlot(item_id="armour_1", name="Expert Vaal Cuirass", col=8, row=1, width=2, height=3),
        InventoryItemSlot(item_id="orb_1", name="Divine Orb", col=0, row=0, width=1, height=1),
        InventoryItemSlot(item_id="orb_2", name="Chaos Orb", col=1, row=2, width=1, height=1),
        InventoryItemSlot(item_id="orb_3", name="Exalted Orb", col=2, row=4, width=1, height=1),
    ]

    actions = packer.plan_vertical_sort(items)
    assert len(actions) > 0

    # Lập bản đồ tọa độ đích sau khi thực thi actions
    final_positions = {}
    for it in items:
        final_positions[it.item_id] = (it.col, it.row)
    for act in actions:
        final_positions[act.item_id] = (act.to_col, act.to_row)

    # 1. Đồ lớn (Quarterstaff 2x4) phải được dồn về cột bên trái (Cột 0)
    staff_col, staff_row = final_positions["staff_1"]
    assert staff_col == 0
    assert staff_row == 0

    # 2. Đồ lớn tiếp theo (Body Armour 2x3) dồn vào cột tiếp theo (Cột 2)
    armour_col, armour_row = final_positions["armour_1"]
    assert armour_col == 2
    assert armour_row == 0

    # 3. Tất cả đồ 1x1 (Currency Orbs) phải được dồn vào cột ngoài cùng bên phải (Cột 11)
    for orb_id in ["orb_1", "orb_2", "orb_3"]:
        orb_col, orb_row = final_positions[orb_id]
        assert orb_col == 11
        assert 0 <= orb_row < 5


def test_vertical_packing_prevents_space_fragmentation():
    """Chứng minh thuật toán giữ được khối trống 2x4 liên tục cho vũ khí tiếp theo."""
    packer = VerticalInventoryPacker(cols=12, rows=5)

    # Nếu có 8 đồ 1x1 xếp lộn xộn ở mỗi hàng 1 món, sẽ làm hỏng toàn bộ chiều cao 4 ô
    items = [
        InventoryItemSlot(item_id=f"orb_{i}", name="Chaos Orb", col=i, row=2, width=1, height=1)
        for i in range(8)
    ]

    # Trước khi sort: Tại hàng 2 có 8 item nằm ngang -> Không còn cột nào từ 0-7 có chiều cao trống >= 3!
    grid_before = [[False for _ in range(12)] for _ in range(5)]
    for it in items:
        grid_before[it.row][it.col] = True

    blocks_before = packer.calculate_free_blocks(grid_before)
    # Các khối 2x4 ở các cột 0..7 đều bị chặn bởi các item ở row 2
    valid_2x4_before = [b for b in blocks_before if b[2] == 2 and b[3] == 4 and b[0] < 7]
    assert len(valid_2x4_before) == 0

    # Sau khi sort theo chiều dọc:
    actions = packer.plan_vertical_sort(items)
    final_positions = {it.item_id: (it.col, it.row) for it in items}
    for act in actions:
        final_positions[act.item_id] = (act.to_col, act.to_row)

    grid_after = [[False for _ in range(12)] for _ in range(5)]
    for item_id, (c, r) in final_positions.items():
        grid_after[r][c] = True

    # Kiểm tra các khối trống sau khi sort
    blocks_after = packer.calculate_free_blocks(grid_after)
    valid_2x4_after = [b for b in blocks_after if b[2] == 2 and b[3] == 4 and b[0] < 7]

    # Bây giờ các cột 0..9 đều hoàn toàn trống cả 5 hàng -> rất nhiều khối 2x4 khả dụng!
    assert len(valid_2x4_after) > 0
