package input

import (
	"encoding/json"
	"log"
	"os"
	"path/filepath"

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

type Binding [][]ebiten.Key

const settingsFile = "assets/settings.json"

type InputManager struct {
	Actions map[string]Binding

	recordingAction string
	recordingKeys   []ebiten.Key
	isRecording     bool
}

var Manager *InputManager

func init() {
	Manager = NewInputManager()
	Manager.LoadSettings()
}

func NewInputManager() *InputManager {
	return &InputManager{
		Actions:       make(map[string]Binding),
		recordingKeys: make([]ebiten.Key, 0),
	}
}

func (im *InputManager) LoadDefaultSettings() {
	im.Actions = map[string]Binding{
		"Run":        {{ebiten.KeyControl}},
		"ClimbMode":  {{ebiten.KeyShift}},
		"MoveLeft":   {{ebiten.KeyA}, {ebiten.KeyLeft}},
		"MoveRight":  {{ebiten.KeyD}, {ebiten.KeyRight}},
		"MoveUp":     {{ebiten.KeyW}, {ebiten.KeyUp}},
		"MoveDown":   {{ebiten.KeyS}, {ebiten.KeyDown}},
		"Jump":       {{ebiten.KeySpace}},
		"ClimbLeft":  {{ebiten.KeyA}, {ebiten.KeyLeft}},
		"ClimbRight": {{ebiten.KeyD}, {ebiten.KeyRight}},
		"ClimbUp":    {{ebiten.KeyW}},
		"ClimbDown":  {{ebiten.KeyS}},
		"ClimbIn":    {{ebiten.KeyUp}},
		"ClimbOut":   {{ebiten.KeyDown}},
	}
}

func (im *InputManager) LoadSettings() {
	im.LoadDefaultSettings() // Load defaults first

	data, err := os.ReadFile(settingsFile)
	if err != nil {
		if os.IsNotExist(err) {
			im.SaveSettings() // Create the file if it doesn't exist
		} else {
			log.Println("Error reading settings.json:", err)
		}
		return
	}

	var loadedActions map[string]Binding
	if err := json.Unmarshal(data, &loadedActions); err != nil {
		log.Println("Error unmarshaling settings.json:", err)
		return
	}

	// Overwrite defaults with loaded ones
	for k, v := range loadedActions {
		im.Actions[k] = v
	}
}

func (im *InputManager) SaveSettings() {
	// Ensure directory exists
	if err := os.MkdirAll(filepath.Dir(settingsFile), 0755); err != nil {
		log.Println("Failed to create settings directory:", err)
		return
	}

	data, err := json.MarshalIndent(im.Actions, "", "  ")
	if err != nil {
		log.Println("Error marshaling settings:", err)
		return
	}

	if err := os.WriteFile(settingsFile, data, 0644); err != nil {
		log.Println("Error writing settings.json:", err)
	}
}

func (im *InputManager) IsActionPressed(action string) bool {
	bindings, ok := im.Actions[action]
	if !ok {
		return false
	}

	for _, combination := range bindings {
		allPressed := true
		for _, key := range combination {
			if !ebiten.IsKeyPressed(key) {
				allPressed = false
				break
			}
		}
		// Om alla tangenter i kombinationen är nedtryckta så triggas handlingen
		if len(combination) > 0 && allPressed {
			return true
		}
	}
	return false
}

func (im *InputManager) IsActionJustPressed(action string) bool {
	bindings, ok := im.Actions[action]
	if !ok {
		return false
	}

	for _, combination := range bindings {
		allPressed := true
		justPressedCount := 0
		for _, key := range combination {
			if !ebiten.IsKeyPressed(key) {
				allPressed = false
				break
			}
			if inpututil.IsKeyJustPressed(key) {
				justPressedCount++
			}
		}
		if len(combination) > 0 && allPressed && justPressedCount > 0 {
			return true
		}
	}
	return false
}

func (im *InputManager) StartRecording(action string) {
	im.recordingAction = action
	im.recordingKeys = []ebiten.Key{}
	im.isRecording = true
}

// UpdateRecording called every frame while in settings to record inputs.
// Returns true when recording finished.
func (im *InputManager) UpdateRecording() bool {
	if !im.isRecording {
		return false
	}

	// Avbryt med ESC
	if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
		im.StopRecording()
		return true
	}

	// Spara med Enter
	if inpututil.IsKeyJustPressed(ebiten.KeyEnter) {
		if len(im.recordingKeys) > 0 {
			im.Actions[im.recordingAction] = Binding{im.recordingKeys}
			im.SaveSettings()
		}
		im.isRecording = false
		return true
	}

	pressedKeys := make([]ebiten.Key, 0)
	for k := ebiten.KeyA; k <= ebiten.KeyMax; k++ {
		if ebiten.IsKeyPressed(k) {
			// Ignorera Escape och Enter från att bindas
			if k == ebiten.KeyEscape || k == ebiten.KeyEnter {
				continue
			}
			pressedKeys = append(pressedKeys, k)
		}
	}

	// Limit to max 2 keys
	if len(pressedKeys) > 2 {
		pressedKeys = pressedKeys[:2]
	}

	// Uppdatera de lagrade tangenterna att visa i UI
	if len(pressedKeys) > 0 {
		im.recordingKeys = pressedKeys
	}

	return false
}

func (im *InputManager) StopRecording() {
	im.isRecording = false
}

func (im *InputManager) IsRecording() bool {
	return im.isRecording
}

func (im *InputManager) GetRecordingAction() string {
	return im.recordingAction
}

func (im *InputManager) GetRecordingKeys() []ebiten.Key {
	return im.recordingKeys
}
