package core

import "core:fmt"

DEFAULT_BUBBLE_STYLE := Speech_Bubble_Style{
	background_color = "#ffffff",
	border_color = "#000000",
	border_width = 2,
	border_radius = 16,
	font_family = "Comic Sans MS, cursive, sans-serif",
	font_size = 14,
	text_color = "#000000",
	padding = 12,
}

clampf :: proc(v, minv, maxv: f32) -> f32 {
	if v < minv { return minv }
	if v > maxv { return maxv }
	return v
}

calculate_bubble_size :: proc(text: string, style: Speech_Bubble_Style) -> Size {
	char_width := style.font_size * 0.6
	char_height := style.font_size * 1.4
	chars_per_line: f32 = 25
	lines := f32(len(text)) / chars_per_line
	if lines < 1 {
		lines = 1
	}

	width := f32(len(text))*char_width/lines + style.padding*2
	width = clampf(width, 100, 300)
	height := lines*char_height + style.padding*2 + 20

	return Size{width = width, height = height}
}

auto_place_bubble :: proc(bubble: Speech_Bubble, panel_w, panel_h: f32, speaker_pos: Position) -> Speech_Bubble {
	updated := bubble
	size := calculate_bubble_size(bubble.text, bubble.style)
	updated.size = size

	speaker := speaker_pos
	if speaker.x == 0 && speaker.y == 0 {
		speaker = Position{x = panel_w * 0.5, y = panel_h * 0.7}
	}

	switch bubble.type {
	case .Thought:
		updated.position = Position{
			x = clampf(speaker.x-size.width/2, 20, panel_w-size.width-20),
			y = clampf(speaker.y-size.height-40, 20, panel_h-size.height-10),
		}
		updated.tail_target = Position{x = speaker.x, y = speaker.y - 20}
		updated.tail_direction = "bottom"
	case .Shout:
		updated.size = Size{width = size.width * 1.1, height = size.height * 1.1}
		updated.position = Position{
			x = clampf(speaker.x-updated.size.width/2, 10, panel_w-updated.size.width-10),
			y = clampf(speaker.y-updated.size.height-30, 10, panel_h-updated.size.height-10),
		}
		updated.tail_target = Position{x = speaker.x, y = speaker.y - 10}
		updated.tail_direction = "bottom"
	case .Whisper:
		updated.position = Position{
			x = clampf(speaker.x-size.width/2, 20, panel_w-size.width-20),
			y = clampf(speaker.y-size.height-30, 20, panel_h-size.height-10),
		}
		updated.tail_target = Position{x = speaker.x, y = speaker.y - 20}
		updated.tail_direction = "bottom"
	case .Narration:
		updated.position = Position{x = panel_w * 0.1, y = 20}
		updated.size = Size{width = panel_w * 0.8, height = size.height}
		updated.tail_direction = "bottom"
	case .Sound_Effect:
		updated.position = Position{
			x = clampf(speaker.x+20, 10, panel_w-size.width-10),
			y = clampf(speaker.y-size.height-50, 10, panel_h-size.height-10),
		}
		updated.tail_target = Position{x = speaker.x + 30, y = speaker.y - 30}
		updated.tail_direction = "bottom-left"
	case .Normal:
		updated.position = Position{
			x = clampf(speaker.x-size.width/2, 20, panel_w-size.width-20),
			y = clampf(speaker.y-size.height-30, 20, panel_h-size.height-10),
		}
		updated.tail_target = Position{x = speaker.x, y = speaker.y - 20}
		updated.tail_direction = "bottom"
	}

	return updated
}

auto_place_panel_bubbles :: proc(panel: Panel, panel_w, panel_h: f32) -> []Speech_Bubble {
	if len(panel.dialogue) == 0 && len(panel.caption) == 0 {
		return nil
	}

	bubbles: [dynamic]Speech_Bubble

	for dialogue, idx in panel.dialogue {
		speaker_count := len(panel.characters_present)
		speaker_idx := 0
		for char_id, j in panel.characters_present {
			if char_id == dialogue.speaker_id {
				speaker_idx = j
				break
			}
		}

		speaker_x := panel_w * 0.5
		if speaker_count > 1 {
			speaker_x = (panel_w / f32(speaker_count + 1)) * f32(speaker_idx + 1)
		}
		speaker_y := panel_h * 0.75

		bubble := Speech_Bubble{
			id = fmt.aprintf("bubble_%s_%d", panel.panel_id, idx),
			panel_id = panel.panel_id,
			type = dialogue.bubble_type,
			text = dialogue.text,
			position = Position{},
			size = Size{width = 100, height = 50},
			tail_direction = "bottom",
			tail_target = Position{x = speaker_x, y = speaker_y},
			style = DEFAULT_BUBBLE_STYLE,
			speaker_id = dialogue.speaker_id,
		}

		placed := auto_place_bubble(bubble, panel_w, panel_h, Position{x = speaker_x, y = speaker_y})
		placed.position.y = clampf(placed.position.y-f32(idx*10), 10, panel_h-placed.size.height-10)
		placed.position.x = clampf(placed.position.x, 10, panel_w-placed.size.width-10)

		append(&bubbles, placed)
	}

	if len(panel.caption) > 0 {
		caption_bubble := Speech_Bubble{
			id = fmt.aprintf("caption_%s", panel.panel_id),
			panel_id = panel.panel_id,
			type = .Narration,
			text = panel.caption,
			position = Position{x = panel_w * 0.1, y = 20},
			size = Size{width = panel_w * 0.8, height = 40},
			tail_direction = "bottom",
			tail_target = Position{x = panel_w * 0.5, y = 60},
			style = Speech_Bubble_Style{
				background_color = "#f5f5f5",
				border_color = "#999999",
				border_width = DEFAULT_BUBBLE_STYLE.border_width,
				border_radius = DEFAULT_BUBBLE_STYLE.border_radius,
				font_family = DEFAULT_BUBBLE_STYLE.font_family,
				font_size = DEFAULT_BUBBLE_STYLE.font_size,
				text_color = DEFAULT_BUBBLE_STYLE.text_color,
				padding = DEFAULT_BUBBLE_STYLE.padding,
			},
			speaker_id = "",
		}
		append(&bubbles, caption_bubble)
	}

	return bubbles[:]
}

update_bubble_text :: proc(bubble: Speech_Bubble, new_text: string) -> Speech_Bubble {
	updated := bubble
	updated.text = new_text
	return updated
}

update_bubble_position :: proc(bubble: Speech_Bubble, x, y: f32) -> Speech_Bubble {
	updated := bubble
	updated.position = Position{x = x, y = y}
	return updated
}

reset_bubble_position :: proc(bubble: Speech_Bubble) -> Speech_Bubble {
	updated := bubble
	updated.position = Position{x = 0, y = 0}
	return updated
}
