package gui

import clay "clay:."
import "base:runtime"
import "core:fmt"
import "core:math"
import "core:strings"
import rl "vendor:raylib"

// --- Font IDs (indices into raylib_fonts) ---
CLAY_FONT_BODY  :: u16(0)
CLAY_FONT_TITLE :: u16(1)
CLAY_FONT_MONO  :: u16(2)

// --- Font registry (shared between layout and renderer) ---
Raylib_Font :: struct {
	fontId: u16,
	font:   rl.Font,
}

raylib_fonts: [dynamic]Raylib_Font

// --- Clay Color Palette (modernized dark theme) ---
// Named with CLAY_ prefix to avoid collision with existing theme.odin

CLAY_BG_BASE       :: clay.Color{13, 13, 18, 255}
CLAY_BG_SIDEBAR    :: clay.Color{18, 18, 26, 255}
CLAY_BG_TOPBAR     :: clay.Color{22, 22, 32, 255}
CLAY_BG_CARD       :: clay.Color{28, 28, 40, 255}
CLAY_BG_CARD_ALT   :: clay.Color{24, 24, 36, 255}
CLAY_BG_STRIP      :: clay.Color{32, 32, 46, 255}
CLAY_BG_OVERLAY    :: clay.Color{0, 0, 0, 180}
CLAY_BG_INPUT      :: clay.Color{20, 20, 30, 255}

CLAY_BORDER_CARD    :: clay.Color{50, 50, 70, 255}
CLAY_BORDER_SUBTLE  :: clay.Color{40, 40, 58, 255}
CLAY_BORDER_DIVIDER :: clay.Color{36, 36, 52, 255}

CLAY_ACCENT        :: clay.Color{99, 102, 241, 255}
CLAY_ACCENT_HOVER  :: clay.Color{124, 127, 255, 255}
CLAY_ACCENT_MUTED   :: clay.Color{79, 70, 229, 200}
CLAY_ACCENT_SURFACE:: clay.Color{67, 56, 202, 40}
CLAY_ACCENT_GLOW   :: clay.Color{99, 102, 241, 60}

CLAY_TEXT_PRIMARY   :: clay.Color{240, 240, 245, 255}
CLAY_TEXT_SECONDARY :: clay.Color{170, 170, 190, 255}
CLAY_TEXT_TERTIARY :: clay.Color{110, 110, 135, 255}
CLAY_TEXT_DISABLED :: clay.Color{70, 70, 90, 255}
CLAY_TEXT_BRIGHT   := clay.Color{255, 255, 255, 255}

CLAY_SUCCESS      :: clay.Color{34, 197, 94, 255}
CLAY_SUCCESS_DIM  :: clay.Color{34, 197, 94, 100}
CLAY_WARNING      :: clay.Color{234, 179, 8, 255}
CLAY_WARNING_DIM  :: clay.Color{234, 179, 8, 100}
CLAY_ERROR        :: clay.Color{239, 68, 68, 255}
CLAY_ERROR_DIM    :: clay.Color{239, 68, 68, 100}

CLAY_BTN_DEFAULT       :: clay.Color{42, 42, 58, 255}
CLAY_BTN_DEFAULT_HOVER :: clay.Color{55, 55, 72, 255}
CLAY_BTN_SOFT          :: clay.Color{55, 50, 120, 255}
CLAY_BTN_SOFT_HOVER    :: clay.Color{70, 65, 140, 255}
CLAY_BTN_DANGER        :: clay.Color{185, 28, 28, 255}
CLAY_BTN_DANGER_HOVER  :: clay.Color{210, 40, 40, 255}
CLAY_BTN_DISABLED      :: clay.Color{30, 30, 42, 255}

CLAY_NAV_ACTIVE    :: clay.Color{99, 102, 241, 255}
CLAY_NAV_ACTIVE_BG :: clay.Color{67, 56, 202, 25}
CLAY_NAV_HOVER_BG  :: clay.Color{40, 40, 58, 255}

CLAY_INPUT_BORDER :: clay.Color{55, 55, 75, 255}
CLAY_INPUT_FOCUS  :: clay.Color{99, 102, 241, 255}

CLAY_PROGRESS_TRACK :: clay.Color{30, 30, 42, 255}
CLAY_PROGRESS_FILL  := clay.Color{99, 102, 241, 255}

// --- Spacing (4px grid) ---
CLAY_SPACE_4  :: u16(4)
CLAY_SPACE_8  :: u16(8)
CLAY_SPACE_12 :: u16(12)
CLAY_SPACE_16 :: u16(16)
CLAY_SPACE_20 :: u16(20)
CLAY_SPACE_24 :: u16(24)
CLAY_SPACE_32 :: u16(32)
CLAY_SPACE_40 :: u16(40)
CLAY_SPACE_48 :: u16(48)

// --- Font Sizes ---
CLAY_FONT_SIZE_SM :: u16(13)
CLAY_FONT_SIZE_MD :: u16(15)
CLAY_FONT_SIZE_LG :: u16(18)
CLAY_FONT_SIZE_XL :: u16(22)
CLAY_FONT_SIZE_2XL:: u16(28)

// --- Corner Radius (px for Clay) ---
CLAY_RADIUS_SM :: f32(4)
CLAY_RADIUS_MD :: f32(8)
CLAY_RADIUS_LG :: f32(12)
CLAY_RADIUS_XL :: f32(16)

// --- Fractional radius (for DrawRectangleRounded compat) ---
CLAY_RADIUS_FRAC_BTN  :: f32(0.32)
CLAY_RADIUS_FRAC_PILL :: f32(0.50)
CLAY_RADIUS_FRAC_CARD :: f32(0.14)

// --- Color conversion ---
clay_color_to_rl :: proc(color: clay.Color) -> rl.Color {
	return {u8(color[0]), u8(color[1]), u8(color[2]), u8(color[3])}
}

// --- Clay Error Handler ---
clay_error_handler :: proc "c" (errorData: clay.ErrorData) {
	context = runtime.default_context()
	fmt.eprintf("CLAY ERROR: %v\n", errorData)
}

// --- Clay State ---
Clay_State :: struct {
	arena_memory: [dynamic]u8,
	font_default: rl.Font,
	font_title:  rl.Font,
	font_mono:  rl.Font,
}

clay_state: Clay_State

// --- Init / Shutdown ---
clay_init :: proc(screen_w: i32, screen_h: i32) {
	min_memory_size := clay.MinMemorySize()
	clay_state.arena_memory = make([dynamic]u8, min_memory_size)
	arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(uint(min_memory_size), raw_data(clay_state.arena_memory))

	clay.Initialize(arena, {f32(screen_w), f32(screen_h)}, {handler = clay_error_handler})
	clay.SetMeasureTextFunction(clay_measure_text, nil)

	clay_state.font_default = rl.GetFontDefault()
	clay_state.font_title = rl.GetFontDefault()
	clay_state.font_mono = rl.GetFontDefault()

	raylib_fonts = make([dynamic]Raylib_Font, 0, 3)
	append(&raylib_fonts, Raylib_Font{fontId = CLAY_FONT_BODY, font = clay_state.font_default})
	append(&raylib_fonts, Raylib_Font{fontId = CLAY_FONT_TITLE, font = clay_state.font_title})
	append(&raylib_fonts, Raylib_Font{fontId = CLAY_FONT_MONO, font = clay_state.font_mono})
}

clay_shutdown :: proc() {
	delete(raylib_fonts)
	delete(clay_state.arena_memory)
}

clay_update_dimensions :: proc(screen_w: i32, screen_h: i32) {
	clay.SetLayoutDimensions({f32(screen_w), f32(screen_h)})
}

clay_update_input :: proc() {
	mouse_pos := rl.GetMousePosition()
	is_down := rl.IsMouseButtonDown(.LEFT)
	clay.SetPointerState({mouse_pos.x, mouse_pos.y}, is_down)

	scroll_delta := rl.GetMouseWheelMove()
	clay.UpdateScrollContainers(true, {f32(scroll_delta) * 40, 0}, rl.GetFrameTime())
}

// --- Text Measurement ---
clay_measure_text :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfig, userData: rawptr) -> clay.Dimensions {
	context = runtime.default_context()

	if config.fontId >= u16(len(raylib_fonts)) {
		return {width = f32(text.length) * f32(config.fontSize) * 0.6, height = f32(config.fontSize)}
	}

	line_width: f32 = 0
	font := raylib_fonts[config.fontId].font
	text_str := string(text.chars[:text.length])

	for i in 0 ..< len(text_str) {
		ch := text_str[i]
		glyph_index := rl.GetGlyphIndex(font, rune(ch))

		if glyph_index < 0 || glyph_index >= i32(font.glyphCount) {
			line_width += f32(config.fontSize) * 0.6
			continue
		}

		glyph := font.glyphs[glyph_index]
		if glyph.advanceX != 0 {
			line_width += f32(glyph.advanceX)
		} else if glyph_index < i32(font.glyphCount) {
			line_width += font.recs[glyph_index].width + f32(font.glyphs[glyph_index].offsetX)
		}
	}

	scaleFactor := f32(config.fontSize) / f32(font.baseSize)
	total_spacing := f32(len(text_str)) * f32(config.letterSpacing)

	return {width = line_width * scaleFactor + total_spacing, height = f32(config.fontSize)}
}

// --- Rendering ---
clay_raylib_render :: proc(render_commands: ^clay.ClayArray(clay.RenderCommand)) {
	for i in 0 ..< render_commands.length {
		render_command := clay.RenderCommandArray_Get(render_commands, i)
		bounds := render_command.boundingBox

		switch render_command.commandType {
		case .None:
		case .Text:
			config := render_command.renderData.text
			text := string(config.stringContents.chars[:config.stringContents.length])
			cstr_text := strings.clone_to_cstring(text)
			if config.fontId < u16(len(raylib_fonts)) {
				font := raylib_fonts[config.fontId].font
				rl.DrawTextEx(
					font,
					cstr_text,
					{bounds.x, bounds.y},
					f32(config.fontSize),
					f32(config.letterSpacing),
					clay_color_to_rl(config.textColor),
				)
			}
		case .Image:
			config := render_command.renderData.image
			texture := (^rl.Texture2D)(config.imageData)
			rl.DrawTextureEx(texture^, {bounds.x, bounds.y}, 0, bounds.width / f32(texture.width), rl.WHITE)
		case .ScissorStart:
			rl.BeginScissorMode(
				i32(math.round(bounds.x)),
				i32(math.round(bounds.y)),
				i32(math.round(bounds.width)),
				i32(math.round(bounds.height)),
			)
		case .ScissorEnd:
			rl.EndScissorMode()
		case .Rectangle:
			config := render_command.renderData.rectangle
			if config.cornerRadius.topLeft > 0 {
				radius := (config.cornerRadius.topLeft * 2) / min(bounds.width, bounds.height)
				rl.DrawRectangleRounded(
					{bounds.x, bounds.y, bounds.width, bounds.height},
					radius, 8,
					clay_color_to_rl(config.backgroundColor),
				)
			} else {
				rl.DrawRectangle(
					i32(math.round(bounds.x)),
					i32(math.round(bounds.y)),
					i32(math.round(bounds.width)),
					i32(math.round(bounds.height)),
					clay_color_to_rl(config.backgroundColor),
				)
			}
		case .Border:
			config := render_command.renderData.border
			if config.width.left > 0 {
				rl.DrawRectangle(
					i32(math.round(bounds.x)),
					i32(math.round(bounds.y + config.cornerRadius.topLeft)),
					i32(config.width.left),
					i32(math.round(bounds.height - config.cornerRadius.topLeft - config.cornerRadius.bottomLeft)),
					clay_color_to_rl(config.color),
				)
			}
			if config.width.right > 0 {
				rl.DrawRectangle(
					i32(math.round(bounds.x + bounds.width - f32(config.width.right))),
					i32(math.round(bounds.y + config.cornerRadius.topRight)),
					i32(config.width.right),
					i32(math.round(bounds.height - config.cornerRadius.topRight - config.cornerRadius.bottomRight)),
					clay_color_to_rl(config.color),
				)
			}
			if config.width.top > 0 {
				rl.DrawRectangle(
					i32(math.round(bounds.x + config.cornerRadius.topLeft)),
					i32(math.round(bounds.y)),
					i32(math.round(bounds.width - config.cornerRadius.topLeft - config.cornerRadius.topRight)),
					i32(config.width.top),
					clay_color_to_rl(config.color),
				)
			}
			if config.width.bottom > 0 {
				rl.DrawRectangle(
					i32(math.round(bounds.x + config.cornerRadius.bottomLeft)),
					i32(math.round(bounds.y + bounds.height - f32(config.width.bottom))),
					i32(math.round(bounds.width - config.cornerRadius.bottomLeft - config.cornerRadius.bottomRight)),
					i32(config.width.bottom),
					clay_color_to_rl(config.color),
				)
			}
			if config.cornerRadius.topLeft > 0 {
				rl.DrawRing(
					{math.round(bounds.x + config.cornerRadius.topLeft), math.round(bounds.y + config.cornerRadius.topLeft)},
					math.round(config.cornerRadius.topLeft - f32(config.width.top)),
					config.cornerRadius.topLeft,
					180, 270, 10, clay_color_to_rl(config.color),
				)
			}
			if config.cornerRadius.topRight > 0 {
				rl.DrawRing(
					{math.round(bounds.x + bounds.width - config.cornerRadius.topRight), math.round(bounds.y + config.cornerRadius.topRight)},
					math.round(config.cornerRadius.topRight - f32(config.width.top)),
					config.cornerRadius.topRight,
					270, 360, 10, clay_color_to_rl(config.color),
				)
			}
			if config.cornerRadius.bottomLeft > 0 {
				rl.DrawRing(
					{math.round(bounds.x + config.cornerRadius.bottomLeft), math.round(bounds.y + bounds.height - config.cornerRadius.bottomLeft)},
					math.round(config.cornerRadius.bottomLeft - f32(config.width.top)),
					config.cornerRadius.bottomLeft,
					90, 180, 10, clay_color_to_rl(config.color),
				)
			}
			if config.cornerRadius.bottomRight > 0 {
				rl.DrawRing(
					{math.round(bounds.x + bounds.width - config.cornerRadius.bottomRight), math.round(bounds.y + bounds.height - config.cornerRadius.bottomRight)},
					math.round(config.cornerRadius.bottomRight - f32(config.width.bottom)),
					config.cornerRadius.bottomRight,
					0.1, 90, 10, clay_color_to_rl(config.color),
				)
			}
		case .OverlayColorStart:
			config := render_command.renderData.overlayColor
			rl.DrawRectangle(
				i32(math.round(bounds.x)),
				i32(math.round(bounds.y)),
				i32(math.round(bounds.width)),
				i32(math.round(bounds.height)),
				clay_color_to_rl(config.color),
			)
		case .OverlayColorEnd:
		case .Custom:
		}
	}
}

// --- Layout helpers (procs because Clay helpers require runtime evaluation) ---

clay_card_layout :: proc() -> clay.LayoutConfig {
	return clay.LayoutConfig {
		layoutDirection = .TopToBottom,
		sizing = {
			width = clay.SizingGrow({}),
			height = clay.SizingFit({}),
		},
		padding = clay.PaddingAll(16),
		childGap = CLAY_SPACE_8,
	}
}

clay_row_layout :: proc() -> clay.LayoutConfig {
	return clay.LayoutConfig {
		layoutDirection = .LeftToRight,
		sizing = {
			width = clay.SizingGrow({}),
			height = clay.SizingFit({}),
		},
		childGap = CLAY_SPACE_8,
	}
}

clay_input_layout :: proc() -> clay.LayoutConfig {
	return clay.LayoutConfig {
		layoutDirection = .LeftToRight,
		sizing = {
			width = clay.SizingGrow({}),
			height = clay.SizingFixed(36),
		},
		padding = {top = 8, right = 12, bottom = 8, left = 12},
	}
}

clay_button_layout :: proc() -> clay.LayoutConfig {
	return clay.LayoutConfig {
		layoutDirection = .LeftToRight,
		sizing = {
			width = clay.SizingFit({}),
			height = clay.SizingFixed(36),
		},
		padding = {top = 8, right = 16, bottom = 8, left = 16},
		childAlignment = {x = .Center, y = .Center},
	}
}

// --- Style configs ---

clay_card_style :: proc() -> clay.ElementDeclaration {
	return {
		layout = clay_card_layout(),
		backgroundColor = CLAY_BG_CARD,
		cornerRadius = clay.CornerRadiusAll(CLAY_RADIUS_MD),
		border = {color = CLAY_BORDER_CARD, width = clay.BorderOutside(1)},
	}
}

// --- Text helpers ---

clay_body_text :: proc(text: string, color: clay.Color = CLAY_TEXT_PRIMARY, size: u16 = CLAY_FONT_SIZE_MD) {
	clay.Text(text, {fontId = CLAY_FONT_BODY, fontSize = size, textColor = color})
}

clay_title_text :: proc(text: string, color: clay.Color = CLAY_TEXT_BRIGHT, size: u16 = CLAY_FONT_SIZE_LG) {
	clay.Text(text, {fontId = CLAY_FONT_TITLE, fontSize = size, textColor = color})
}

clay_muted_text :: proc(text: string) {
	clay.Text(text, {fontId = CLAY_FONT_BODY, fontSize = CLAY_FONT_SIZE_SM, textColor = CLAY_TEXT_TERTIARY})
}