package tests

import "core:fmt"
import "core:strings"
import "core:testing"
import "../src/core"
import "../src/adapters"
import "../src/gui"
import "../src/ui"

// ─────────────────────────────────────────────────────────────
// Phase 6: Appearance Count + Streaming + Bubble Editing
// ─────────────────────────────────────────────────────────────

// ── Appearance Count Tests ──

@test
core_count_appearances_basic :: proc(t: ^testing.T) {
	script := core.Comic_Script{
		title = "Test Comic",
		synopsis = "A test comic",
		characters = []core.Character{
			{id = "hero", name = "Hero", role = .Protagonist},
			{id = "villain", name = "Villain", role = .Antagonist},
			{id = "sidekick", name = "Sidekick", role = .Supporting},
		},
		pages = []core.Page{
			{
				page_number = 1,
				panels = []core.Panel{
					{panel_id = "p1", characters_present = []string{"hero"}},
					{panel_id = "p2", characters_present = []string{"hero", "villain"}},
				},
			},
			{
				page_number = 2,
				panels = []core.Panel{
					{panel_id = "p3", characters_present = []string{"hero", "sidekick"}},
					{panel_id = "p4", characters_present = []string{"villain"}},
					{panel_id = "p5", characters_present = []string{"hero", "villain", "sidekick"}},
				},
			},
		},
	}

	core.count_character_appearances(&script)

	testing.expect(t, script.characters[0].appearance_count == 4, fmt.tprintf("hero should appear 4 times, got %d", script.characters[0].appearance_count))
	testing.expect(t, script.characters[1].appearance_count == 3, fmt.tprintf("villain should appear 3 times, got %d", script.characters[1].appearance_count))
	testing.expect(t, script.characters[2].appearance_count == 2, fmt.tprintf("sidekick should appear 2 times, got %d", script.characters[2].appearance_count))
}

@test
core_count_appearances_first_panel :: proc(t: ^testing.T) {
	script := core.Comic_Script{
		title = "Test",
		synopsis = "Test",
		characters = []core.Character{
			{id = "a", name = "A", role = .Protagonist},
			{id = "b", name = "B", role = .Supporting},
		},
		pages = []core.Page{
			{
				page_number = 1,
				panels = []core.Panel{
					{panel_id = "panel_001", characters_present = []string{"a"}},
					{panel_id = "panel_002", characters_present = []string{"a", "b"}},
				},
			},
		},
	}

	core.count_character_appearances(&script)

	testing.expect(t, script.characters[0].first_appearance_panel == "panel_001", fmt.tprintf("A first panel should be panel_001, got %q", script.characters[0].first_appearance_panel))
	testing.expect(t, script.characters[1].first_appearance_panel == "panel_002", fmt.tprintf("B first panel should be panel_002, got %q", script.characters[1].first_appearance_panel))
}

@test
core_count_appearances_zero :: proc(t: ^testing.T) {
	script := core.Comic_Script{
		title = "Test",
		synopsis = "Test",
		characters = []core.Character{
			{id = "unused", name = "Unused", role = .Extra},
		},
		pages = []core.Page{
			{
				page_number = 1,
				panels = []core.Panel{
					{panel_id = "p1", characters_present = []string{"other"}},
				},
			},
		},
	}

	core.count_character_appearances(&script)

	testing.expect(t, script.characters[0].appearance_count == 0, "unused character should have 0 appearances")
	testing.expect(t, len(script.characters[0].first_appearance_panel) == 0, "unused character should have no first panel")
}

@test
core_count_appearances_empty_script :: proc(t: ^testing.T) {
	script := core.Comic_Script{
		title = "Empty",
		synopsis = "Empty",
		characters = []core.Character{},
		pages = []core.Page{},
	}

	core.count_character_appearances(&script)

	testing.expect(t, len(script.characters) == 0, "should have no characters")
}

// ── Bubble Text Editing Tests ──

@test
core_update_bubble_text :: proc(t: ^testing.T) {
	bubble := core.Speech_Bubble{
		id = "bubble_1",
		panel_id = "panel_1",
		text = "Hello world",
		speaker_id = "char_1",
	}
	updated := core.update_bubble_text(bubble, "New text")
	testing.expect(t, updated.text == "New text", fmt.tprintf("text should be updated, got %q", updated.text))
	testing.expect(t, updated.id == "bubble_1", "id should be preserved")
	testing.expect(t, updated.panel_id == "panel_1", "panel_id should be preserved")
}

@test
gui_action_update_bubble_text :: proc(t: ^testing.T) {
	state := core.new_initial_state()
	defer core.dispose_state(&state)
	controller := ui.new_controller(state)
	defer ui.dispose_job_manager(&controller.jobs)

	// Add a character and panel with dialogue
	char := core.Character{id = "char_1", name = "Hero", role = .Protagonist}
	chars: [dynamic]core.Character
	append(&chars, char)
	controller.state.characters = chars[:]
	defer delete(chars)

	panel := core.Panel{
		panel_id = "panel_1",
		panel_number = 1,
		dialogue = []core.Dialogue{
			{speaker_id = "char_1", text = "Original text", emotion = .Neutral},
		},
	}

	// Generate bubbles for the panel
	bubbles := core.auto_place_panel_bubbles(panel, 800, 600)
	defer delete(bubbles)
	controller.state.speech_bubbles = make(map[string][]core.Speech_Bubble)
	controller.state.speech_bubbles["panel_1"] = bubbles

	// Update bubble text
	if len(bubbles) > 0 {
		bubble_id := bubbles[0].id
		msg := gui.action_update_bubble_text(&controller, bubble_id, "Updated dialogue")
		testing.expect(t, strings.contains(msg, "updated"), fmt.tprintf("should update bubble text, got %q", msg))
	}
}

// ── Bubble Position Tests ──

@test
core_bubble_position_update :: proc(t: ^testing.T) {
	bubble := core.Speech_Bubble{
		id = "b1",
		panel_id = "p1",
		text = "Test",
		position = core.Position{x = 0.1, y = 0.1},
	}
	updated := core.update_bubble_position(bubble, 0.5, 0.5)
	testing.expect(t, updated.position.x == 0.5, "x should be 0.5")
	testing.expect(t, updated.position.y == 0.5, "y should be 0.5")
}

@test
core_bubble_reset_position :: proc(t: ^testing.T) {
	bubble := core.Speech_Bubble{
		id = "b1",
		panel_id = "p1",
		text = "Test",
		position = core.Position{x = 0.9, y = 0.9},
	}
	reset := core.reset_bubble_position(bubble)
	testing.expect(t, reset.position.x == 0.0, "reset x should be 0")
	testing.expect(t, reset.position.y == 0.0, "reset y should be 0")
}

// ── Integration: Full Pipeline with Appearance Count ──

@test
core_normalize_and_count_appearances :: proc(t: ^testing.T) {
	script := core.Comic_Script{
		title = "Test",
		synopsis = "Test",
		characters = []core.Character{
			{id = "hero", name = "Hero", role = .Protagonist},
			{id = "villain", name = "Villain", role = .Antagonist},
		},
		pages = []core.Page{
			{
				panels = []core.Panel{
					{characters_present = []string{"hero"}},
					{characters_present = []string{"hero", "villain"}},
					{characters_present = []string{"villain"}},
				},
			},
		},
	}

	normalized := core.normalize_script(script)
	core.count_character_appearances(&normalized)

	testing.expect(t, normalized.characters[0].appearance_count == 2, "hero should appear twice")
	testing.expect(t, normalized.characters[1].appearance_count == 2, "villain should appear twice")
}
