package providers

import (
	"fmt"
	"strings"

	"github.com/AvengeMedia/danklinux/internal/keybinds"
	"github.com/AvengeMedia/danklinux/internal/sway"
)

type SwayProvider struct {
	configPath string
}

func NewSwayProvider(configPath string) *SwayProvider {
	if configPath == "" {
		configPath = "$HOME/.config/sway"
	}
	return &SwayProvider{
		configPath: configPath,
	}
}

func (s *SwayProvider) Name() string {
	return "sway"
}

func (s *SwayProvider) GetCheatSheet() (*keybinds.CheatSheet, error) {
	section, err := sway.ParseKeys(s.configPath)
	if err != nil {
		return nil, fmt.Errorf("failed to parse sway config: %w", err)
	}

	categorizedBinds := make(map[string][]keybinds.Keybind)
	s.convertSection(section, "", categorizedBinds)

	return &keybinds.CheatSheet{
		Title:    "Sway Keybinds",
		Provider: s.Name(),
		Binds:    categorizedBinds,
	}, nil
}

func (s *SwayProvider) convertSection(section *sway.Section, subcategory string, categorizedBinds map[string][]keybinds.Keybind) {
	currentSubcat := subcategory
	if section.Name != "" {
		currentSubcat = section.Name
	}

	for _, kb := range section.Keybinds {
		category := s.categorizeByCommand(kb.Command)
		bind := s.convertKeybind(&kb, currentSubcat)
		categorizedBinds[category] = append(categorizedBinds[category], bind)
	}

	for _, child := range section.Children {
		s.convertSection(&child, currentSubcat, categorizedBinds)
	}
}

func (s *SwayProvider) categorizeByCommand(command string) string {
	command = strings.ToLower(command)

	switch {
	case strings.Contains(command, "scratchpad"):
		return "Scratchpad"
	case strings.Contains(command, "workspace") && strings.Contains(command, "output"):
		return "Monitor"
	case strings.Contains(command, "workspace"):
		return "Workspace"
	case strings.Contains(command, "output"):
		return "Monitor"
	case strings.Contains(command, "layout"):
		return "Layout"
	case command == "kill" ||
		command == "fullscreen" || strings.Contains(command, "fullscreen") ||
		command == "floating toggle" || strings.Contains(command, "floating") ||
		strings.Contains(command, "focus") ||
		strings.Contains(command, "move") ||
		strings.Contains(command, "resize") ||
		strings.Contains(command, "split"):
		return "Window"
	case strings.HasPrefix(command, "exec"):
		return "Execute"
	case command == "exit" || command == "reload":
		return "System"
	default:
		return "Other"
	}
}

func (s *SwayProvider) convertKeybind(kb *sway.KeyBinding, subcategory string) keybinds.Keybind {
	key := s.formatKey(kb)
	desc := kb.Comment

	if desc == "" {
		desc = kb.Command
	}

	return keybinds.Keybind{
		Key:         key,
		Description: desc,
		Subcategory: subcategory,
	}
}

func (s *SwayProvider) formatKey(kb *sway.KeyBinding) string {
	parts := make([]string, 0, len(kb.Mods)+1)
	parts = append(parts, kb.Mods...)
	parts = append(parts, kb.Key)
	return strings.Join(parts, "+")
}
