#!/usr/bin/env python3
"""Tests for tower_visual_mapper.py — verifies map construction and formatting."""

import json
import sys
import tempfile
from pathlib import Path
from unittest.mock import patch

sys.path.insert(0, str(Path(__file__).parent.parent / "scripts"))

from tower_visual_mapper import (
    TowerRoom, TowerNPC, TowerFloor, TowerMap,
    scan_gallery_index, scan_memory_architecture, scan_wizard_configs,
    build_tower_map, to_json, to_ascii, _gallery_image_to_room,
    _parse_json_response
)


# === Unit Tests ===

def test_gallery_image_to_room_known():
    room = _gallery_image_to_room("01-wizard-tower-bitcoin.jpg", "The Tower", "The Origin")
    assert room is not None
    assert room.name == "The Tower — Exterior"
    assert room.floor == 0
    assert "bitcoin" in room.description.lower() or "sovereign" in room.description.lower()
    print("  PASS: test_gallery_image_to_room_known")


def test_gallery_image_to_room_unknown():
    room = _gallery_image_to_room("random-image.jpg", "Something", "The Origin")
    assert room is None
    print("  PASS: test_gallery_image_to_room_unknown")


def test_gallery_image_to_room_philosophy():
    room = _gallery_image_to_room("06-the-paperclip-moment.jpg", "A paperclip", "The Philosophy")
    assert room is not None
    assert room.category == "philosophy"
    print("  PASS: test_gallery_image_to_room_philosophy")


def test_parse_json_response_clean():
    text = '{"floors": 5, "rooms": [{"name": "Test"}]}'
    result = _parse_json_response(text)
    assert result["floors"] == 5
    assert result["rooms"][0]["name"] == "Test"
    print("  PASS: test_parse_json_response_clean")


def test_parse_json_response_fenced():
    text = '```json\n{"floors": 3}\n```'
    result = _parse_json_response(text)
    assert result["floors"] == 3
    print("  PASS: test_parse_json_response_fenced")


def test_parse_json_response_garbage():
    result = _parse_json_response("no json here at all")
    assert result == {}
    print("  PASS: test_parse_json_response_garbage")


def test_tower_map_structure():
    tower = TowerMap()
    tower.rooms = [
        TowerRoom(name="Room A", floor=0, category="test"),
        TowerRoom(name="Room B", floor=0, category="test"),
        TowerRoom(name="Room C", floor=1, category="other"),
    ]
    tower.npcs = [
        TowerNPC(name="NPC1", role="guard", location="Room A"),
    ]

    output = json.loads(to_json(tower))
    assert output["name"] == "The Tower"
    assert output["stats"]["total_rooms"] == 3
    assert output["stats"]["total_npcs"] == 1
    print("  PASS: test_tower_map_structure")


def test_to_json():
    tower = TowerMap()
    tower.rooms = [TowerRoom(name="Test Room", floor=1)]
    output = json.loads(to_json(tower))
    assert output["rooms"][0]["name"] == "Test Room"
    assert output["rooms"][0]["floor"] == 1
    print("  PASS: test_to_json")


def test_to_ascii():
    tower = TowerMap()
    tower.floors = [TowerFloor(number=0, name="Ground", rooms=["Test Room"])]
    tower.rooms = [TowerRoom(name="Test Room", floor=0, description="A test")]
    tower.npcs = []
    tower.connections = []

    output = to_ascii(tower)
    assert "THE TOWER" in output
    assert "Test Room" in output
    assert "FLOOR 0" in output
    print("  PASS: test_to_ascii")


def test_to_ascii_with_npcs():
    tower = TowerMap()
    tower.floors = [TowerFloor(number=0, name="Ground", rooms=["The Forge"])]
    tower.rooms = [TowerRoom(name="The Forge", floor=0, occupants=["Bezalel"])]
    tower.npcs = [TowerNPC(name="Bezalel", role="Builder", location="The Forge")]

    output = to_ascii(tower)
    assert "Bezalel" in output
    print("  PASS: test_to_ascii_with_npcs")


def test_scan_gallery_index(tmp_path):
    # Create mock gallery
    gallery = tmp_path / "grok-imagine-gallery"
    gallery.mkdir()
    index = gallery / "INDEX.md"
    index.write_text("""# Gallery
### The Origin
| 01 | wizard-tower-bitcoin.jpg | The Tower, sovereign |
| 02 | soul-inscription.jpg | SOUL.md glowing |
### The Philosophy
| 05 | value-drift-battle.jpg | Blue vs red ships |
""")
    rooms = scan_gallery_index(tmp_path)
    assert len(rooms) >= 2
    names = [r.name for r in rooms]
    assert any("Tower" in n for n in names)
    assert any("Inscription" in n for n in names)
    print("  PASS: test_scan_gallery_index")


def test_scan_wizard_configs(tmp_path):
    wizards = tmp_path / "wizards"
    for name in ["timmy", "bezalel", "ezra"]:
        wdir = wizards / name
        wdir.mkdir(parents=True)
        (wdir / "config.yaml").write_text("model: test\n")

    npcs = scan_wizard_configs(tmp_path)
    assert len(npcs) >= 3
    names = [n.name for n in npcs]
    assert any("Timmy" in n for n in names)
    assert any("Bezalel" in n for n in names)
    print("  PASS: test_scan_wizard_configs")


def test_build_tower_map_empty(tmp_path):
    tower = build_tower_map(tmp_path, include_vision=False)
    assert tower.name == "The Tower"
    # Should still have palace rooms from MEMORY_ARCHITECTURE (won't exist in tmp, but that's fine)
    assert isinstance(tower.rooms, list)
    print("  PASS: test_build_tower_map_empty")


def test_room_deduplication():
    tower = TowerMap()
    tower.rooms = [
        TowerRoom(name="Dup Room", floor=0),
        TowerRoom(name="Dup Room", floor=1),  # same name, different floor
        TowerRoom(name="Unique Room", floor=0),
    ]
    # Deduplicate in build_tower_map — simulate
    seen = {}
    deduped = []
    for room in tower.rooms:
        if room.name not in seen:
            seen[room.name] = True
            deduped.append(room)
    assert len(deduped) == 2
    print("  PASS: test_room_deduplication")


def run_all():
    print("=== tower_visual_mapper tests ===")
    tests = [
        test_gallery_image_to_room_known,
        test_gallery_image_to_room_unknown,
        test_gallery_image_to_room_philosophy,
        test_parse_json_response_clean,
        test_parse_json_response_fenced,
        test_parse_json_response_garbage,
        test_tower_map_structure,
        test_to_json,
        test_to_ascii,
        test_to_ascii_with_npcs,
        test_scan_gallery_index,
        test_scan_wizard_configs,
        test_build_tower_map_empty,
        test_room_deduplication,
    ]
    passed = 0
    failed = 0
    for test in tests:
        try:
            if "tmp_path" in test.__code__.co_varnames:
                with tempfile.TemporaryDirectory() as td:
                    test(Path(td))
            else:
                test()
            passed += 1
        except Exception as e:
            print(f"  FAIL: {test.__name__} — {e}")
            failed += 1

    print(f"\n{'ALL PASSED' if failed == 0 else f'{failed} FAILED'}: {passed}/{len(tests)}")
    return failed == 0


if __name__ == "__main__":
    sys.exit(0 if run_all() else 1)
