package render

import (
	"image/color"

	"tetris/engine/system"

	rl "github.com/gen2brain/raylib-go/raylib"
)

type Config struct {
	Title string

	// Window
	WindowWidth  int32
	WindowHeight int32
	WindowFlags  uint32

	// Render target resolution
	RenderHeight int32
	RenderWidth  int32

	ScaleFlags ScaleFlags
}

// target is the off-screen render target where all drawing operations are performed.
// It has a fixed resolution and is later scaled to the window size.
var target rl.RenderTexture2D

var scaleFlags ScaleFlags

// Init initializes the rendering system.
//
// It creates an off-screen render texture with the fixed resolution defined by config.RenderWidth/Height.
// This texture is where all tiles and game graphics are drawn before being scaled and presented.
func Init(config Config) {
	// hyprland has a bug where the height of the window is 37 pixels taller than requested.
	// so we just subtract it here.
	if system.IsHyprland() {
		config.WindowHeight = config.WindowHeight - 37
	}

	scaleFlags = config.ScaleFlags

	if config.WindowFlags > 0 {
		rl.SetConfigFlags(config.WindowFlags)
	}

	// Setup window
	rl.InitWindow(config.WindowWidth, config.WindowHeight, config.Title)

	// Initialize render texture.
	target = rl.LoadRenderTexture(config.RenderWidth, config.RenderHeight)
	rl.SetTextureFilter(target.Texture, rl.TextureFilterNearest)
}

// Exit shuts down the rendering system.
//
// It unloads the render texture and frees any associated GPU resources.
// This should be called before the application exits.
func Exit() {
	rl.UnloadRenderTexture(target)
	rl.CloseWindow()
}

// Begin prepares the rendering system for a new frame.
//
// It binds the off-screen texture target and clears it to a black background.
// All tile drawing operations (e.g., DrawTile) should occur after Begin() and
// before End().
func Begin(col color.RGBA) {
	// Bind texture so that all draw calls after are applied to target texture
	rl.BeginTextureMode(target)
	// Clear the texture
	rl.ClearBackground(col)
}

// End finalizes the current frame and displays it on the screen.
//
// It ends the off-screen drawing session and stretches the texture target
// to fill the window. This function must be called after all drawing is done.
func End() {
	// End drawing to the texture target.
	rl.EndTextureMode()

	// Begin drawing to screen buffer.
	rl.BeginDrawing()

	// Define source rectangle (flip vertically to match coordinate systems).
	src := rl.Rectangle{
		X:      0,
		Y:      0,
		Width:  float32(target.Texture.Width),
		Height: -float32(target.Texture.Height),
	}

	// Calculate the destination rectangle (window).
	dest := scale(target.Texture.Width, target.Texture.Height,
		int32(rl.GetRenderWidth()), int32(rl.GetRenderHeight()),
		scaleFlags)

	// Blit the off-screen texture to the screen's back buffer.
	rl.DrawTexturePro(target.Texture, src, dest, rl.Vector2Zero(), 0.0, rl.White)

	// Swap buffers
	rl.EndDrawing()
}
