package portal

import (
	"image/color"

	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/vector"

	"github.com/atridad/LilGuy/internal/config"
)

type PortalSide int

const (
	SideLeft PortalSide = iota
	SideRight
	SideTop
	SideBottom
)

func (s PortalSide) String() string {
	switch s {
	case SideLeft:
		return "Left"
	case SideRight:
		return "Right"
	case SideTop:
		return "Top"
	case SideBottom:
		return "Bottom"
	default:
		return "Unknown"
	}
}

type Portal struct {
	ID     string
	X      float64
	Y      float64
	Width  float64
	Height float64
	Side   PortalSide

	DestinationMap    string
	DestinationPortal string

	Color         color.NRGBA
	GlowColor     color.NRGBA
	Enabled       bool
	Visible       bool
	GlowIntensity float64

	SpawnOffsetX float64
	SpawnOffsetY float64
}

type TransitionEvent struct {
	Portal            *Portal
	HeroX             float64
	HeroY             float64
	DestinationMap    string
	DestinationPortal string
}

func NewPortal(id string, side PortalSide, x, y, width, height float64) *Portal {
	return &Portal{
		ID:            id,
		X:             x,
		Y:             y,
		Width:         width,
		Height:        height,
		Side:          side,
		Color:         color.NRGBA{R: 100, G: 100, B: 255, A: 180},
		GlowColor:     color.NRGBA{R: 150, G: 150, B: 255, A: 100},
		Enabled:       true,
		Visible:       true,
		GlowIntensity: 0,
	}
}

// Contains checks if a point is within the portal bounds
func (p *Portal) Contains(x, y float64) bool {
	return x >= p.X && x <= p.X+p.Width && y >= p.Y && y <= p.Y+p.Height
}

// Overlaps checks if a rectangular area overlaps with the portal
func (p *Portal) Overlaps(x, y, width, height float64) bool {
	return x+width > p.X && x < p.X+p.Width &&
		y+height > p.Y && y < p.Y+p.Height
}

func (p *Portal) CanTransition() bool {
	return p.Enabled && p.DestinationMap != ""
}

func (p *Portal) Update(dt float64) {
	if !p.Enabled {
		return
	}

	if dt > 0.1 {
		dt = 0.1
	}

	p.GlowIntensity += dt * 2.0
	if p.GlowIntensity > 6.28 { // 2*PI
		p.GlowIntensity -= 6.28
	}
}

func (p *Portal) Draw(screen *ebiten.Image) {
	if !p.Visible {
		return
	}

	drawX := float32(int(p.X + 0.5))
	drawY := float32(int(p.Y + 0.5))
	drawWidth := float32(int(p.Width + 0.5))
	drawHeight := float32(int(p.Height + 0.5))

	vector.FillRect(
		screen,
		drawX,
		drawY,
		drawWidth,
		drawHeight,
		p.Color,
		false,
	)

	if p.Enabled {
		glowPulse := 0.5 + 0.5*float64(p.GlowIntensity)/6.28
		glowAlpha := uint8(float64(p.GlowColor.A) * glowPulse)
		glowColor := color.NRGBA{
			R: p.GlowColor.R,
			G: p.GlowColor.G,
			B: p.GlowColor.B,
			A: glowAlpha,
		}

		borderWidth := float32(4)
		vector.StrokeRect(
			screen,
			drawX-borderWidth/2,
			drawY-borderWidth/2,
			drawWidth+borderWidth,
			drawHeight+borderWidth,
			borderWidth,
			glowColor,
			false,
		)
	}
}

type Manager struct {
	Portals            []*Portal
	OnTransition       func(event TransitionEvent)
	transitionCooldown float64
}

func NewManager() *Manager {
	return &Manager{
		Portals:            make([]*Portal, 0),
		transitionCooldown: 0,
	}
}

func (m *Manager) AddPortal(portal *Portal) {
	m.Portals = append(m.Portals, portal)
}

func (m *Manager) GetPortalByID(id string) *Portal {
	for _, p := range m.Portals {
		if p.ID == id {
			return p
		}
	}
	return nil
}

func (m *Manager) RemovePortal(id string) {
	for i, p := range m.Portals {
		if p.ID == id {
			m.Portals = append(m.Portals[:i], m.Portals[i+1:]...)
			return
		}
	}
}

func (m *Manager) Clear() {
	m.Portals = make([]*Portal, 0)
}

func (m *Manager) Update(dt float64) {
	// clamp delta time to prevent physics issues
	if dt > 0.1 {
		dt = 0.1
	}

	for _, p := range m.Portals {
		p.Update(dt)
	}

	if m.transitionCooldown > 0 {
		m.transitionCooldown -= dt
		if m.transitionCooldown < 0 {
			m.transitionCooldown = 0
		}
	}
}

func (m *Manager) CheckCollision(x, y, width, height float64) *Portal {
	if m.transitionCooldown > 0 {
		return nil
	}

	for _, p := range m.Portals {
		if !p.CanTransition() {
			continue
		}

		if p.Overlaps(x, y, width, height) {
			return p
		}
	}
	return nil
}

func (m *Manager) TriggerTransition(portal *Portal, heroX, heroY float64) {
	if portal == nil || !portal.CanTransition() {
		return
	}

	if m.OnTransition != nil {
		event := TransitionEvent{
			Portal:            portal,
			HeroX:             heroX,
			HeroY:             heroY,
			DestinationMap:    portal.DestinationMap,
			DestinationPortal: portal.DestinationPortal,
		}
		m.OnTransition(event)
	}

	m.transitionCooldown = config.PortalTransitionCooldown
}

func (m *Manager) Draw(screen *ebiten.Image) {
	for _, p := range m.Portals {
		p.Draw(screen)
	}
}

func CreateSidePortal(id string, side PortalSide, screenWidth, screenHeight float64) *Portal {
	var x, y, width, height float64

	switch side {
	case SideLeft:
		x = 0
		y = 0
		width = config.PortalThickness
		height = screenHeight
	case SideRight:
		x = screenWidth - config.PortalThickness
		y = 0
		width = config.PortalThickness
		height = screenHeight
	case SideTop:
		x = 0
		y = 0
		width = screenWidth
		height = config.PortalThickness
	case SideBottom:
		x = 0
		y = screenHeight - config.PortalThickness
		width = screenWidth
		height = config.PortalThickness
	}

	return NewPortal(id, side, x, y, width, height)
}

func CreateDoorPortal(id string, side PortalSide, x, y float64) *Portal {
	const doorWidth = 80.0
	const doorHeight = 120.0

	return NewPortal(id, side, x, y, doorWidth, doorHeight)
}
