package screens

import (
	"image/color"

	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/inpututil"
	"github.com/hajimehoshi/ebiten/v2/text/v2"
)

// Settings interface
type FPSCapSetting interface {
	String() string
	Cycle()
}

type settingsScreen int

const (
	settingsMain settingsScreen = iota
	settingsDebugOptions
)

type SettingsScreen struct {
	selectedIndex         int
	currentScreen         settingsScreen
	fpsMonitorValue       *bool
	fpsCapValue           FPSCapSetting
	portalVisibilityValue *bool
	raycastEnabledValue   *bool
	raycastDebugValue     *bool
}

func NewSettingsScreen() *SettingsScreen {
	return &SettingsScreen{
		selectedIndex: 0,
		currentScreen: settingsMain,
	}
}

func (s *SettingsScreen) SetFPSMonitor(enabled *bool) {
	s.fpsMonitorValue = enabled
}

func (s *SettingsScreen) SetFPSCap(cap FPSCapSetting) {
	s.fpsCapValue = cap
}

func (s *SettingsScreen) SetPortalVisibility(enabled *bool) {
	s.portalVisibilityValue = enabled
}

func (s *SettingsScreen) SetRaycastSettings(enabled *bool, debugMode *bool) {
	s.raycastEnabledValue = enabled
	s.raycastDebugValue = debugMode
}

func (s *SettingsScreen) Update() bool {
	if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
		if s.currentScreen == settingsDebugOptions {
			s.currentScreen = settingsMain
			s.selectedIndex = 0
			return false
		}
		return true
	}

	if s.currentScreen == settingsDebugOptions {
		return s.updateDebugOptions()
	}
	return s.updateMain()
}

func (s *SettingsScreen) updateMain() bool {
	settingsCount := 2
	if inpututil.IsKeyJustPressed(ebiten.KeyArrowUp) || inpututil.IsKeyJustPressed(ebiten.KeyW) {
		s.selectedIndex--
		if s.selectedIndex < 0 {
			s.selectedIndex = 0
		}
	}
	if inpututil.IsKeyJustPressed(ebiten.KeyArrowDown) || inpututil.IsKeyJustPressed(ebiten.KeyS) {
		s.selectedIndex++
		if s.selectedIndex >= settingsCount {
			s.selectedIndex = settingsCount - 1
		}
	}

	if inpututil.IsKeyJustPressed(ebiten.KeyEnter) || inpututil.IsKeyJustPressed(ebiten.KeySpace) {
		if s.selectedIndex == 0 && s.fpsCapValue != nil {
			s.fpsCapValue.Cycle()
		} else if s.selectedIndex == 1 {
			s.currentScreen = settingsDebugOptions
			s.selectedIndex = 0
		}
	}

	return false
}

func (s *SettingsScreen) updateDebugOptions() bool {
	debugOptionsCount := 5 // FPS Monitor, Portal Visibility, Raycast Enabled, Raycast Debug, Back
	if inpututil.IsKeyJustPressed(ebiten.KeyArrowUp) || inpututil.IsKeyJustPressed(ebiten.KeyW) {
		s.selectedIndex--
		if s.selectedIndex < 0 {
			s.selectedIndex = 0
		}
	}
	if inpututil.IsKeyJustPressed(ebiten.KeyArrowDown) || inpututil.IsKeyJustPressed(ebiten.KeyS) {
		s.selectedIndex++
		if s.selectedIndex >= debugOptionsCount {
			s.selectedIndex = debugOptionsCount - 1
		}
	}

	if inpututil.IsKeyJustPressed(ebiten.KeyEnter) || inpututil.IsKeyJustPressed(ebiten.KeySpace) {
		if s.selectedIndex == 0 && s.fpsMonitorValue != nil {
			*s.fpsMonitorValue = !*s.fpsMonitorValue
		} else if s.selectedIndex == 1 && s.portalVisibilityValue != nil {
			*s.portalVisibilityValue = !*s.portalVisibilityValue
		} else if s.selectedIndex == 2 && s.raycastEnabledValue != nil {
			*s.raycastEnabledValue = !*s.raycastEnabledValue
		} else if s.selectedIndex == 3 && s.raycastDebugValue != nil {
			*s.raycastDebugValue = !*s.raycastDebugValue
		} else if s.selectedIndex == 4 {
			s.currentScreen = settingsMain
			s.selectedIndex = 0
		}
	}

	return false
}

// Rendering

func (s *SettingsScreen) Draw(screen *ebiten.Image, screenWidth, screenHeight int, title string) {
	screen.Fill(color.RGBA{R: 20, G: 20, B: 30, A: 255})

	titleX := (screenWidth / 2) - (len(title) * 7 / 2)
	titleY := screenHeight/3 - 50
	s.drawText(screen, title, color.White, titleX, titleY)

	if s.currentScreen == settingsDebugOptions {
		s.drawDebugOptions(screen, screenWidth, screenHeight)
	} else {
		s.drawMain(screen, screenWidth, screenHeight)
	}
}

func (s *SettingsScreen) drawMain(screen *ebiten.Image, screenWidth, screenHeight int) {
	startY := screenHeight/2 - 20
	leftMargin := screenWidth/2 - 120

	// FPS cap setting
	fpsCapText := "FPS Cap: "
	if s.fpsCapValue != nil {
		fpsCapText += s.fpsCapValue.String()
	} else {
		fpsCapText += "60 FPS"
	}

	if s.selectedIndex == 0 {
		indicatorX := leftMargin - 20
		s.drawText(screen, ">", color.RGBA{R: 255, G: 200, B: 0, A: 255}, indicatorX, startY)
		s.drawText(screen, fpsCapText, color.RGBA{R: 255, G: 255, B: 100, A: 255}, leftMargin, startY)
	} else {
		s.drawText(screen, fpsCapText, color.RGBA{R: 180, G: 180, B: 200, A: 255}, leftMargin, startY)
	}

	// debug options submenu
	debugOptionsText := "Debug Options >"
	debugY := startY + 40
	if s.selectedIndex == 1 {
		indicatorX := leftMargin - 20
		s.drawText(screen, ">", color.RGBA{R: 255, G: 200, B: 0, A: 255}, indicatorX, debugY)
		s.drawText(screen, debugOptionsText, color.RGBA{R: 255, G: 255, B: 100, A: 255}, leftMargin, debugY)
	} else {
		s.drawText(screen, debugOptionsText, color.RGBA{R: 180, G: 180, B: 200, A: 255}, leftMargin, debugY)
	}

	// Instructions
	hintText := "Enter/Space to select, ESC to go back"
	hintX := (screenWidth / 2) - (len(hintText) * 7 / 2)
	hintY := screenHeight - 50
	s.drawText(screen, hintText, color.RGBA{R: 120, G: 120, B: 150, A: 255}, hintX, hintY)
}

func (s *SettingsScreen) drawDebugOptions(screen *ebiten.Image, screenWidth, screenHeight int) {
	startY := screenHeight/2 - 20
	leftMargin := screenWidth/2 - 120

	// FPS monitor toggle
	fpsMonitorText := "FPS Monitor: "
	if s.fpsMonitorValue != nil && *s.fpsMonitorValue {
		fpsMonitorText += "ON"
	} else {
		fpsMonitorText += "OFF"
	}

	if s.selectedIndex == 0 {
		indicatorX := leftMargin - 20
		s.drawText(screen, ">", color.RGBA{R: 255, G: 200, B: 0, A: 255}, indicatorX, startY)
		s.drawText(screen, fpsMonitorText, color.RGBA{R: 255, G: 255, B: 100, A: 255}, leftMargin, startY)
	} else {
		s.drawText(screen, fpsMonitorText, color.RGBA{R: 180, G: 180, B: 200, A: 255}, leftMargin, startY)
	}

	// Portal visibility toggle
	portalVisText := "Portal Visibility: "
	if s.portalVisibilityValue != nil && *s.portalVisibilityValue {
		portalVisText += "ON"
	} else {
		portalVisText += "OFF"
	}

	portalY := startY + 40
	if s.selectedIndex == 1 {
		indicatorX := leftMargin - 20
		s.drawText(screen, ">", color.RGBA{R: 255, G: 200, B: 0, A: 255}, indicatorX, portalY)
		s.drawText(screen, portalVisText, color.RGBA{R: 255, G: 255, B: 100, A: 255}, leftMargin, portalY)
	} else {
		s.drawText(screen, portalVisText, color.RGBA{R: 180, G: 180, B: 200, A: 255}, leftMargin, portalY)
	}

	// Raycast enabled toggle
	raycastText := "Lighting: "
	if s.raycastEnabledValue != nil && *s.raycastEnabledValue {
		raycastText += "ON"
	} else {
		raycastText += "OFF"
	}

	raycastY := startY + 80
	if s.selectedIndex == 2 {
		indicatorX := leftMargin - 20
		s.drawText(screen, ">", color.RGBA{R: 255, G: 200, B: 0, A: 255}, indicatorX, raycastY)
		s.drawText(screen, raycastText, color.RGBA{R: 255, G: 255, B: 100, A: 255}, leftMargin, raycastY)
	} else {
		s.drawText(screen, raycastText, color.RGBA{R: 180, G: 180, B: 200, A: 255}, leftMargin, raycastY)
	}

	// Raycast debug toggle
	raycastDebugText := "Debug Rays: "
	if s.raycastDebugValue != nil && *s.raycastDebugValue {
		raycastDebugText += "ON"
	} else {
		raycastDebugText += "OFF"
	}

	raycastDebugY := startY + 120
	if s.selectedIndex == 3 {
		indicatorX := leftMargin - 20
		s.drawText(screen, ">", color.RGBA{R: 255, G: 200, B: 0, A: 255}, indicatorX, raycastDebugY)
		s.drawText(screen, raycastDebugText, color.RGBA{R: 255, G: 255, B: 100, A: 255}, leftMargin, raycastDebugY)
	} else {
		s.drawText(screen, raycastDebugText, color.RGBA{R: 180, G: 180, B: 200, A: 255}, leftMargin, raycastDebugY)
	}

	// back option
	backText := "< Back"
	backY := startY + 160
	if s.selectedIndex == 4 {
		indicatorX := leftMargin - 20
		s.drawText(screen, ">", color.RGBA{R: 255, G: 200, B: 0, A: 255}, indicatorX, backY)
		s.drawText(screen, backText, color.RGBA{R: 255, G: 255, B: 100, A: 255}, leftMargin, backY)
	} else {
		s.drawText(screen, backText, color.RGBA{R: 180, G: 180, B: 200, A: 255}, leftMargin, backY)
	}

	// Instructions
	hintText := "Enter/Space to select, ESC to go back"
	hintX := (screenWidth / 2) - (len(hintText) * 7 / 2)
	hintY := screenHeight - 50
	s.drawText(screen, hintText, color.RGBA{R: 120, G: 120, B: 150, A: 255}, hintX, hintY)
}

func (s *SettingsScreen) drawText(screen *ebiten.Image, txt string, clr color.Color, x, y int) {
	op := &text.DrawOptions{}
	op.GeoM.Translate(float64(x), float64(y)-basicFaceAscent)
	op.ColorScale.ScaleWithColor(clr)
	text.Draw(screen, txt, basicFace, op)
}

func (s *SettingsScreen) Reset() {
	s.selectedIndex = 0
	s.currentScreen = settingsMain
}
