package profiler

import (
	"fmt"
	"os/exec"
	"sort"

	"github.com/charmbracelet/huh"
	"github.com/muyue/muyue/internal/config"
	"github.com/muyue/muyue/internal/platform"
	"github.com/muyue/muyue/internal/scanner"
)

type editorCandidate struct {
	key    string
	binary string
	label  string
}

var allEditors = []editorCandidate{
	{"VS Code", "code", "VS Code"},
	{"Cursor", "cursor", "Cursor"},
	{"Zed", "zed", "Zed"},
	{"Neovim", "nvim", "Neovim"},
	{"Vim", "vim", "Vim"},
	{"Helix", "hx", "Helix"},
	{"Emacs", "emacs", "Emacs"},
	{"JetBrains", "jetbrains", "JetBrains (IntelliJ/GoLand/etc.)"},
	{"Sublime Text", "subl", "Sublime Text"},
}

type aiCandidate struct {
	key   string
	label string
}

var allAIProviders = []aiCandidate{
	{"minimax", "MiniMax M2.7"},
	{"zai", "Z.AI GLM"},
	{"anthropic", "Anthropic Claude"},
	{"openai", "OpenAI GPT"},
	{"ollama", "Ollama (local)"},
}

func RunFirstTimeSetup() (*config.MuyueConfig, error) {
	cfg := config.Default()
	info := platform.Detect()
	result := scanner.ScanSystem()

	fmt.Println("Welcome to muyue! Let's set up your environment.")

	var name, pseudo, email string
	var languages []string
	var editor string
	var aiProvider string

	nameField := huh.NewInput().
		Title("What's your name?").
		Placeholder("Augustin").
		Value(&name)

	pseudoField := huh.NewInput().
		Title("Your pseudo?").
		Placeholder("muyue").
		Value(&pseudo)

	emailField := huh.NewInput().
		Title("Your email (for git config)?").
		Placeholder("you@example.com").
		Value(&email)

	langOptions := buildLanguageOptions(result)
	langSelect := huh.NewMultiSelect[string]().
		Title("Which languages do you work with?").
		Options(langOptions...).
		Value(&languages)

	editorOptions := buildEditorOptions(info)
	editorSelect := huh.NewSelect[string]().
		Title("Preferred editor?").
		Options(editorOptions...).
		Value(&editor)

	aiOptions := buildAIOptions(info)
	aiSelect := huh.NewSelect[string]().
		Title("Which AI provider for orchestration?").
		Options(aiOptions...).
		Value(&aiProvider)

	form := huh.NewForm(
		huh.NewGroup(nameField, pseudoField, emailField),
		huh.NewGroup(langSelect),
		huh.NewGroup(editorSelect),
		huh.NewGroup(aiSelect),
	)

	if err := form.Run(); err != nil {
		return nil, fmt.Errorf("profile form: %w", err)
	}

	cfg.Profile.Name = name
	cfg.Profile.Pseudo = pseudo
	cfg.Profile.Email = email
	cfg.Profile.Languages = languages
	cfg.Profile.Preferences.Editor = editor
	cfg.Profile.Preferences.DefaultAI = aiProvider
	cfg.Profile.Preferences.Shell = info.Shell

	for i := range cfg.AI.Providers {
		cfg.AI.Providers[i].Active = cfg.AI.Providers[i].Name == aiProvider
	}

	return cfg, nil
}

func buildEditorOptions(info platform.SystemInfo) []huh.Option[string] {
	type scored struct {
		option huh.Option[string]
		score  int
	}

	var candidates []scored
	for _, e := range allEditors {
		installed := isInstalled(e.binary)
		score := 0
		if installed {
			score = 10
		}

		switch info.OS {
		case platform.Linux:
			if e.binary == "code" || e.binary == "nvim" || e.binary == "hx" || e.binary == "vim" {
				score += 2
			}
		case platform.MacOS:
			if e.binary == "code" || e.binary == "cursor" || e.binary == "zed" {
				score += 2
			}
		case platform.Windows:
			if e.binary == "code" || e.binary == "cursor" {
				score += 2
			}
		}

		label := e.label
		if installed {
			label = e.label + " (installed)"
		}

		candidates = append(candidates, scored{
			option: huh.NewOption[string](label, e.key),
			score:  score,
		})
	}

	sort.SliceStable(candidates, func(i, j int) bool {
		return candidates[i].score > candidates[j].score
	})

	options := make([]huh.Option[string], len(candidates))
	for i, c := range candidates {
		options[i] = c.option
	}
	return options
}

func buildLanguageOptions(result *scanner.ScanResult) []huh.Option[string] {
	type scored struct {
		option huh.Option[string]
		score  int
	}

	langs := []struct {
		key      string
		label    string
		binaries []string
	}{
		{"go", "Go", []string{"go"}},
		{"typescript", "TypeScript/JavaScript", []string{"node", "npm", "pnpm"}},
		{"python", "Python", []string{"python3", "pip3", "uv"}},
		{"rust", "Rust", []string{"rustc", "cargo"}},
		{"java", "Java", []string{"java", "javac"}},
		{"c", "C/C++", []string{"gcc", "g++", "clang"}},
		{"ruby", "Ruby", []string{"ruby"}},
		{"php", "PHP", []string{"php"}},
		{"swift", "Swift", []string{"swift"}},
		{"kotlin", "Kotlin", []string{"kotlin"}},
		{"zig", "Zig", []string{"zig"}},
		{"dart", "Dart/Flutter", []string{"dart", "flutter"}},
	}

	var candidates []scored
	for _, l := range langs {
		score := 0
		for _, bin := range l.binaries {
			if isInstalled(bin) {
				score = 5
				break
			}
		}
		if result != nil {
			for _, r := range result.Runtimes {
				if r.Installed && r.Name == l.key {
					score += 5
					break
				}
			}
		}
		candidates = append(candidates, scored{
			option: huh.NewOption[string](l.label, l.key),
			score:  score,
		})
	}

	sort.SliceStable(candidates, func(i, j int) bool {
		return candidates[i].score > candidates[j].score
	})

	options := make([]huh.Option[string], len(candidates))
	for i, c := range candidates {
		options[i] = c.option
	}
	return options
}

func buildAIOptions(info platform.SystemInfo) []huh.Option[string] {
	type scored struct {
		option huh.Option[string]
		score  int
	}

	var candidates []scored
	for _, ai := range allAIProviders {
		score := 0

		if ai.key == "ollama" {
			if isInstalled("ollama") {
				score = 15
			} else {
				score = -5
			}
		}

		switch info.OS {
		case platform.Linux:
			if ai.key == "ollama" || ai.key == "anthropic" {
				score += 1
			}
		case platform.MacOS:
			if ai.key == "anthropic" || ai.key == "openai" {
				score += 1
			}
		}

		candidates = append(candidates, scored{
			option: huh.NewOption[string](ai.label, ai.key),
			score:  score,
		})
	}

	sort.SliceStable(candidates, func(i, j int) bool {
		return candidates[i].score > candidates[j].score
	})

	options := make([]huh.Option[string], len(candidates))
	for i, c := range candidates {
		options[i] = c.option
	}
	return options
}

func isInstalled(binary string) bool {
	_, err := exec.LookPath(binary)
	return err == nil
}

func AskAPIKey(providerName string) (string, error) {
	var apiKey string

	field := huh.NewInput().
		Title(fmt.Sprintf("Enter your %s API key:", providerName)).
		Description("The key will be stored locally in ~/.config/muyue/config.yaml").
		EchoMode(huh.EchoModePassword).
		Value(&apiKey)

	form := huh.NewForm(huh.NewGroup(field))
	if err := form.Run(); err != nil {
		return "", err
	}

	return apiKey, nil
}
