package examples

import "core:fmt"
import "core:math"
import "core:os"
import sdl "vendor:sdl3"

import "../../draw"
import cyber "../cybersteel"

// Backdrop example.
//
// Exercises the bracket scheduler end-to-end. The demo is structured as three zones in one
// window so we can stress-test the cases that matter:
//
//   Zone 1 (top, base layer): animated colorful background + two side-by-side frosted panels
//                             with DIFFERENT sigmas and DIFFERENT tints. Tests sigma grouping
//                             and per-primitive tint.
//
//   Zone 2 (bottom-left, second layer): a small frosted panel in a NEW layer; its bracket sees
//                                       Zone 1's full content (base layer's bracket output is
//                                       carried forward via source_texture). Tests multi-layer
//                                       backdrop sampling.
//
//   Zone 3 (bottom-right, base layer): edge cases. A sigma=0 "mirror" panel (no blur), two
//                                      same-sigma panels stacked (tests sub-batch coalescing
//                                      via append_or_extend_sub_batch), and text drawn ON TOP
//                                      of a backdrop (tests Pass B post-bracket rendering).
//
// Animation: an orbiting gradient stripe plus a few orbiting circles in Zone 1. Motion is the
// only way to visually confirm the blur is Gaussian; a static panel can't tell you whether the
// kernel coefficients are right.
gaussian_blur :: proc() {
	if !sdl.Init({.VIDEO}) do os.exit(1)
	window := sdl.CreateWindow("Backdrop blur", 800, 600, {.HIGH_PIXEL_DENSITY})
	gpu := sdl.CreateGPUDevice(draw.PLATFORM_SHADER_FORMAT, true, nil)
	if !sdl.ClaimWindowForGPUDevice(gpu, window) do os.exit(1)
	if !draw.init(gpu, window) do os.exit(1)
	PLEX_SANS_REGULAR = draw.register_font(cyber.SANS_REGULAR_RAW)

	WINDOW_W :: f32(800)
	WINDOW_H :: f32(600)
	FONT_SIZE :: u16(14)

	t: f32 = 0

	for {
		defer free_all(context.temp_allocator)
		ev: sdl.Event
		for sdl.PollEvent(&ev) {
			if ev.type == .QUIT do return
		}
		t += 1

		base_layer := draw.begin({width = WINDOW_W, height = WINDOW_H})

		//----- Background fill ----------------------------------
		draw.rectangle(base_layer, {0, 0, WINDOW_W, WINDOW_H}, draw.Color{20, 20, 28, 255})

		//----- Zone 1: animated background for the top frosted panels ----------------------------------

		// A wide rotating gradient stripe sweeps left-to-right across Zone 1. The angle changes
		// over time so the gradient itself shifts visibly.
		stripe_angle := t * 0.4
		draw.rectangle(
			base_layer,
			{20, 20, WINDOW_W - 40, 240},
			draw.Linear_Gradient {
				start_color = {255, 80, 60, 255},
				end_color = {60, 120, 255, 255},
				angle = stripe_angle,
			},
		)

		// Five orbiting circles inside Zone 1's strip. The blur should smooth their hard edges
		// and the gradient behind them into a continuous wash.
		for i in 0 ..< 5 {
			phase := f32(i) * 1.2 + t * 0.04
			cx := 100 + f32(i) * 140 + math.cos(phase) * 30
			cy := 140 + math.sin(phase) * 50
			circle_color := draw.Color {
				u8(clamp(120 + math.cos(phase) * 100, 0, 255)),
				u8(clamp(180 + math.sin(phase * 1.3) * 60, 0, 255)),
				u8(clamp(220 - math.sin(phase) * 80, 0, 255)),
				255,
			}
			draw.circle(base_layer, {cx, cy}, 22, circle_color)
		}

		// Bright accent rectangles to give the blur some sharp edges to munch on.
		draw.rectangle(base_layer, {200, 60, 60, 12}, draw.Color{255, 255, 200, 255})
		draw.rectangle(base_layer, {500, 200, 80, 16}, draw.Color{200, 255, 200, 255})

		//----- Zone 1 frosted panels: different sigmas, different tints --------------------------------

		// Panel A: heavy blur, cool blue-grey tint. sigma=14 in logical px.
		// Both panels share rounded corners.
		panel_radii := draw.Rectangle_Radii{16, 16, 16, 16}

		draw.gaussian_blur(
			base_layer,
			{60, 80, 320, 140},
			gaussian_sigma = 30,
			tint = draw.Color{170, 200, 240, 200}, // cool blue, strong mix
			radii = panel_radii,
		)
		draw.text(
			base_layer,
			"sigma = 20, cool tint",
			{72, 90},
			PLEX_SANS_REGULAR,
			FONT_SIZE,
			color = draw.Color{30, 35, 50, 255},
		)

		// Panel B: lighter blur, warm amber tint. sigma=6.
		draw.gaussian_blur(
			base_layer,
			{420, 80, 320, 140},
			gaussian_sigma = 6,
			tint = draw.Color{255, 220, 160, 200}, // warm amber, strong mix
			radii = panel_radii,
		)
		draw.text(
			base_layer,
			"sigma = 6, warm tint",
			{432, 90},
			PLEX_SANS_REGULAR,
			FONT_SIZE,
			color = draw.Color{60, 40, 20, 255},
		)

		// Pass-B verification: a rectangle drawn AFTER the backdrops in the same layer
		// Per the bracket scheduling model, this should render ON TOP of both panels above.
		// If you see this stripe behind the panels instead of in front, something is wrong with
		// the Pass B post-bracket path.
		draw.rectangle(base_layer, {WINDOW_W * 0.5 - 4, 70, 8, 160}, draw.Color{255, 255, 255, 230})

		//----- Zone 2: second layer with its own backdrop --------------------------------
		// Zone 2's panel is in a NEW layer. Its bracket samples source_texture as it stands
		// after the base layer fully finished (including the base layer's bracket V-composite
		// output). So this panel sees Zone 1's frosted panels through its own blur.

		zone2 := draw.new_layer(base_layer, {0, 280, WINDOW_W * 0.55, WINDOW_H - 280})

		// Pass A content for zone2: a translucent darker overlay to make the panel pop.
		draw.rectangle(zone2, {20, 300, WINDOW_W * 0.55 - 40, WINDOW_H - 320}, draw.Color{0, 0, 0, 80})

		// Animated diagonal stripe in Zone 2 so the blur in this layer's panel has motion to
		// smooth, not just the static base-layer content.
		stripe_y := 320 + (math.sin(t * 0.05) * 0.5 + 0.5) * 200
		draw.rectangle(zone2, {30, stripe_y, WINDOW_W * 0.55 - 60, 18}, draw.Color{255, 100, 200, 200})

		// Zone 2's frosted panel.
		draw.gaussian_blur(
			zone2,
			{60, 360, WINDOW_W * 0.55 - 120, 160},
			gaussian_sigma = 10,
			tint = draw.WHITE, // pure blur (white tint with any alpha is a no-op)
			radii = draw.Rectangle_Radii{24, 24, 24, 24},
		)
		draw.text(
			zone2,
			"Layer 2 backdrop",
			{72, 372},
			PLEX_SANS_REGULAR,
			FONT_SIZE,
			color = draw.Color{30, 30, 30, 255},
		)
		draw.text(
			zone2,
			"sigma = 10",
			{72, 392},
			PLEX_SANS_REGULAR,
			FONT_SIZE,
			color = draw.Color{60, 60, 60, 255},
		)

		//----- Zone 3: edge cases (back in base layer would also work, but we use zone2 to keep --------
		// the demo's two-layer structure simple). Zone 3 lives in a third layer so it gets
		// a fresh source snapshot too.
		zone3 := draw.new_layer(zone2, {WINDOW_W * 0.55, 280, WINDOW_W * 0.45, WINDOW_H - 280})

		// Animated background patch for Zone 3 so its mirror panel has something to reflect.
		for i in 0 ..< 4 {
			phase := f32(i) * 1.5 + t * 0.06
			y := 310 + f32(i) * 60 + math.sin(phase) * 8
			draw.rectangle(
				zone3,
				{WINDOW_W * 0.55 + 20, y, WINDOW_W * 0.45 - 40, 14},
				draw.Color {
					u8(clamp(200 + math.cos(phase) * 50, 0, 255)),
					u8(clamp(150 + math.sin(phase) * 80, 0, 255)),
					u8(clamp(220 - math.cos(phase * 1.7) * 60, 0, 255)),
					255,
				},
			)
		}

		// Edge case 1: sigma = 0 "mirror" — sharp framebuffer sample, no blur. Should reproduce
		// the underlying pixels exactly through the SDF mask. Tinted slightly so it's visible.
		draw.gaussian_blur(
			zone3,
			{WINDOW_W * 0.55 + 30, 310, 150, 70},
			gaussian_sigma = 0,
			tint = draw.WHITE, // pure mirror (no blur, no tint)
			radii = draw.Rectangle_Radii{12, 12, 12, 12},
		)
		draw.text(
			zone3,
			"sigma=0 (mirror)",
			{WINDOW_W * 0.55 + 38, 318},
			PLEX_SANS_REGULAR,
			FONT_SIZE,
			color = draw.Color{20, 20, 20, 255},
		)

		// Edge case 2: two same-sigma panels submitted contiguously. The sub-batch coalescer
		// should merge these into a single instanced V-composite draw. Visually, both should
		// look identical (modulo position) — same blur radius, same tint.
		draw.gaussian_blur(
			zone3,
			{WINDOW_W * 0.55 + 30, 400, 150, 70},
			gaussian_sigma = 8,
			tint = draw.Color{160, 255, 160, 200}, // green tint, strong mix
			radii = draw.Rectangle_Radii{12, 12, 12, 12},
		)
		draw.gaussian_blur(
			zone3,
			{WINDOW_W * 0.55 + 200, 400, 150, 70},
			gaussian_sigma = 8,
			tint = draw.Color{160, 255, 160, 200}, // identical: tests sub-batch coalescing
			radii = draw.Rectangle_Radii{12, 12, 12, 12},
		)
		draw.text(
			zone3,
			"sigma=8 (coalesced pair)",
			{WINDOW_W * 0.55 + 38, 408},
			PLEX_SANS_REGULAR,
			FONT_SIZE,
			color = draw.Color{20, 40, 20, 255},
		)

		// Edge case 3: text drawn AFTER a backdrop in the same layer. Tests Pass B over a fresh
		// V-composite output. The text should appear sharply on top of the green panels above.
		draw.text(
			zone3,
			"Pass B text overlay",
			{WINDOW_W * 0.55 + 38, 480},
			PLEX_SANS_REGULAR,
			FONT_SIZE,
			color = draw.WHITE,
		)

		draw.end(gpu, window, draw.Color{15, 15, 22, 255})
	}
}

// Backdrop diagnostic example.
//
// Minimal isolation harness for debugging the blur. ONE panel, ONE sigma, NO animation. The
// fixed background gives the eye a stable reference: the blur should smooth a *known* set of
// hard edges, and any artifacts (crisp circles, ghost mirrors, no apparent change with sigma)
// stand out clearly.
//
// Controls:
//   UP / DOWN arrow  : adjust sigma by ±1
//   LEFT / RIGHT arrow : adjust sigma by ±5
//   SPACE            : reset to sigma=10
//   T                : toggle the test rectangle on top of the panel
//
// Sigma is printed to the title bar so you can correlate visual behavior with the numeric
// value as you adjust it.
gaussian_blur_debug :: proc() {
	if !sdl.Init({.VIDEO}) do os.exit(1)
	window := sdl.CreateWindow("Backdrop debug", 800, 600, {.HIGH_PIXEL_DENSITY})
	gpu := sdl.CreateGPUDevice(draw.PLATFORM_SHADER_FORMAT, true, nil)
	if !sdl.ClaimWindowForGPUDevice(gpu, window) do os.exit(1)
	if !draw.init(gpu, window) do os.exit(1)
	defer draw.destroy(gpu)
	PLEX_SANS_REGULAR = draw.register_font(cyber.SANS_REGULAR_RAW)

	WINDOW_W :: f32(800)
	WINDOW_H :: f32(600)
	FONT_SIZE :: u16(14)

	sigma: f32 = 10
	show_test_rect := true

	for {
		defer free_all(context.temp_allocator)
		ev: sdl.Event
		for sdl.PollEvent(&ev) {
			if ev.type == .QUIT do return
			if ev.type == .KEY_DOWN {
				#partial switch ev.key.scancode {
				case .UP: sigma += 1
				case .DOWN: sigma = max(sigma - 1, 0)
				case .RIGHT: sigma += 5
				case .LEFT: sigma = max(sigma - 5, 0)
				case .SPACE: sigma = 10
				case .T: show_test_rect = !show_test_rect
				}
			}
		}

		// Update title with current sigma so we can correlate visuals to numbers.
		title := fmt.ctprintf("Backdrop debug | sigma = %.1f", sigma)
		sdl.SetWindowTitle(window, title)

		base_layer := draw.begin({width = WINDOW_W, height = WINDOW_H})

		// Background: deliberately high-contrast static content. The eye can verify whether
		// hard edges (the black grid lines, the crisp circles, the fine vertical bars) get
		// smoothed by the panel. NOTHING animates here — every difference between frames is
		// caused by user input (sigma change), not by the demo itself.
		draw.rectangle(base_layer, {0, 0, WINDOW_W, WINDOW_H}, draw.Color{255, 255, 255, 255})

		// Black grid: 8x6 cells with thin lines. Each grid cell is 100x100 logical px.
		for x: f32 = 0; x <= WINDOW_W; x += 100 {
			draw.rectangle(base_layer, {x - 1, 0, 2, WINDOW_H}, draw.BLACK)
		}
		for y: f32 = 0; y <= WINDOW_H; y += 100 {
			draw.rectangle(base_layer, {0, y - 1, WINDOW_W, 2}, draw.BLACK)
		}

		// A row of small bright circles across the middle. Their crisp edges are the most
		// sensitive blur indicator.
		for i in 0 ..< 8 {
			cx := f32(i) * 100 + 50
			color := draw.Color{u8((i * 32) & 0xff), u8((i * 64) & 0xff), u8(255 - (i * 32) & 0xff), 255}
			draw.circle(base_layer, {cx, 350}, 25, color)
		}

		// Vertical fine-detail stripes on the left edge. At any meaningful sigma these should
		// merge into a flat color through the panel.
		for i in 0 ..< 20 {
			x := 30 + f32(i) * 6
			color := draw.RED if i % 2 == 0 else draw.BLUE
			draw.rectangle(base_layer, {x, 200, 4, 200}, color)
		}

		// THE PANEL UNDER TEST. Square, centered, large enough to cover multiple grid cells and
		// the circle row. Square shape makes any horizontal-vs-vertical asymmetry purely
		// renderer-driven (geometry can't introduce it).
		panel := draw.Rectangle{250, 150, 300, 300}
		draw.gaussian_blur(
			base_layer,
			panel,
			gaussian_sigma = sigma,
			tint = draw.WHITE,
			radii = draw.Rectangle_Radii{20, 20, 20, 20},
		)

		// Pass B test: a bright rectangle drawn AFTER the backdrop in the same layer. Should
		// always render on top of the panel. If the panel ever shows a "ghost" of this rect
		// inside its blur, the V-composite is sampling the wrong texture state.
		if show_test_rect {
			draw.rectangle(base_layer, {380, 280, 40, 40}, draw.Color{0, 200, 0, 255})
		}

		// Sigma label at the bottom in giant text so you can read it from across the room.
		draw.text(
			base_layer,
			fmt.tprintf("sigma = %.1f", sigma),
			{20, WINDOW_H - 40},
			PLEX_SANS_REGULAR,
			28,
			color = draw.BLACK,
		)
		draw.text(
			base_layer,
			"UP/DOWN ±1   LEFT/RIGHT ±5   SPACE reset   T toggle test rect",
			{20, WINDOW_H - 70},
			PLEX_SANS_REGULAR,
			FONT_SIZE,
			color = draw.Color{60, 60, 60, 255},
		)

		draw.end(gpu, window, draw.Color{255, 255, 255, 255})
	}
}
