package lsp

import (
	"os"
	"path/filepath"
	"time"

	"gopkg.in/yaml.v3"
)

type RegistryEntry struct {
	Name         string   `yaml:"name" json:"name"`
	Language     string   `yaml:"language" json:"language"`
	Description  string   `yaml:"description" json:"description"`
	Command      string   `yaml:"command" json:"command"`
	InstallCmd   string   `yaml:"install_cmd" json:"install_cmd"`
	InstallType  string   `yaml:"install_type" json:"install_type"`
	Category     string   `yaml:"category" json:"category"`
	FilePatterns []string `yaml:"file_patterns,omitempty" json:"file_patterns,omitempty"`
	ConfigFiles  []string `yaml:"config_files,omitempty" json:"config_files,omitempty"`
	Tags         []string `yaml:"tags,omitempty" json:"tags,omitempty"`
	HomePage     string   `yaml:"homepage,omitempty" json:"homepage,omitempty"`

	NeovimSetup   string `yaml:"neovim_setup,omitempty" json:"neovim_setup,omitempty"`
	HelixLanguage  string `yaml:"helix_language,omitempty" json:"helix_language,omitempty"`
}

type LSPRegistry struct {
	SchemaVersion string          `yaml:"schema_version"`
	UpdatedAt     time.Time       `yaml:"updated_at"`
	Servers       []RegistryEntry `yaml:"servers"`
}

func DefaultLSPRegistry() *LSPRegistry {
	return &LSPRegistry{
		SchemaVersion: "v1",
		UpdatedAt:     time.Now(),
		Servers: []RegistryEntry{
			{
				Name: "gopls", Language: "go", Description: "Go language server",
				Command: "gopls", InstallCmd: "go install golang.org/x/tools/gopls@latest",
				InstallType: "go", Category: "lsp", FilePatterns: []string{"*.go"},
				ConfigFiles: []string{"go.mod"}, Tags: []string{"go", "linting", "completion"},
				HomePage: "https://github.com/golang/tools",
				NeovimSetup: `lspconfig.gopls.setup{}`,
				HelixLanguage: "go",
			},
			{
				Name: "pyright", Language: "python", Description: "Python type checker and language server",
				Command: "pyright", InstallCmd: "npm install -g pyright",
				InstallType: "npm", Category: "lsp", FilePatterns: []string{"*.py", "*.pyi"},
				ConfigFiles: []string{"requirements.txt", "pyproject.toml", "setup.py", "Pipfile"},
				Tags: []string{"python", "type-checking"}, HomePage: "https://github.com/microsoft/pyright",
				NeovimSetup: `lspconfig.pyright.setup{}`,
				HelixLanguage: "python",
			},
			{
				Name: "typescript-language-server", Language: "typescript", Description: "TypeScript and JavaScript language server",
				Command: "typescript-language-server", InstallCmd: "npm install -g typescript-language-server typescript",
				InstallType: "npm", Category: "lsp", FilePatterns: []string{"*.ts", "*.tsx", "*.js", "*.jsx"},
				ConfigFiles: []string{"tsconfig.json", "package.json"},
				Tags: []string{"typescript", "javascript"}, HomePage: "https://github.com/typescript-language-server/typescript-language-server",
				NeovimSetup: `lspconfig.tsserver.setup{}`,
				HelixLanguage: "typescript",
			},
			{
				Name: "vscode-json-language-server", Language: "json", Description: "JSON language server",
				Command: "vscode-json-language-server", InstallCmd: "npm install -g vscode-langservers-extracted",
				InstallType: "npm", Category: "lsp", FilePatterns: []string{"*.json", "*.jsonc"},
				Tags: []string{"json"}, NeovimSetup: `lspconfig.jsonls.setup{}`,
				HelixLanguage: "json",
			},
			{
				Name: "vscode-html-language-server", Language: "html", Description: "HTML language server",
				Command: "vscode-html-language-server", InstallCmd: "npm install -g vscode-langservers-extracted",
				InstallType: "npm", Category: "lsp", FilePatterns: []string{"*.html", "*.htm"},
				Tags: []string{"html"}, NeovimSetup: `lspconfig.html.setup{}`,
				HelixLanguage: "html",
			},
			{
				Name: "vscode-css-language-server", Language: "css", Description: "CSS/SCSS/LESS language server",
				Command: "vscode-css-language-server", InstallCmd: "npm install -g vscode-langservers-extracted",
				InstallType: "npm", Category: "lsp", FilePatterns: []string{"*.css", "*.scss", "*.less"},
				Tags: []string{"css"}, NeovimSetup: `lspconfig.cssls.setup{}`,
				HelixLanguage: "css",
			},
			{
				Name: "yaml-language-server", Language: "yaml", Description: "YAML language server",
				Command: "yaml-language-server", InstallCmd: "npm install -g yaml-language-server",
				InstallType: "npm", Category: "lsp", FilePatterns: []string{"*.yml", "*.yaml"},
				Tags: []string{"yaml"}, NeovimSetup: `lspconfig.yamlls.setup{}`,
				HelixLanguage: "yaml",
			},
			{
				Name: "bash-language-server", Language: "bash", Description: "Bash language server",
				Command: "bash-language-server", InstallCmd: "npm install -g bash-language-server",
				InstallType: "npm", Category: "lsp", FilePatterns: []string{"*.sh", "*.bash"},
				Tags: []string{"bash", "shell"}, NeovimSetup: `lspconfig.bashls.setup{}`,
				HelixLanguage: "bash",
			},
			{
				Name: "rust-analyzer", Language: "rust", Description: "Rust language server",
				Command: "rust-analyzer", InstallCmd: "rustup component add rust-analyzer",
				InstallType: "rustup", Category: "lsp", FilePatterns: []string{"*.rs"},
				ConfigFiles: []string{"Cargo.toml"}, Tags: []string{"rust"},
				HomePage: "https://github.com/rust-lang/rust-analyzer",
				NeovimSetup: `lspconfig.rust_analyzer.setup{}`,
				HelixLanguage: "rust",
			},
			{
				Name: "clangd", Language: "c/c++", Description: "C/C++ language server",
				Command: "clangd", InstallCmd: "", InstallType: "system",
				Category: "lsp", FilePatterns: []string{"*.c", "*.cpp", "*.h", "*.hpp"},
				ConfigFiles: []string{"CMakeLists.txt", "Makefile"}, Tags: []string{"c", "cpp"},
				NeovimSetup: `lspconfig.clangd.setup{}`,
				HelixLanguage: "c",
			},
			{
				Name: "lua-language-server", Language: "lua", Description: "Lua language server",
				Command: "lua-language-server", InstallCmd: "npm install -g lua-language-server",
				InstallType: "npm", Category: "lsp", FilePatterns: []string{"*.lua"},
				Tags: []string{"lua"}, NeovimSetup: `lspconfig.lua_ls.setup{}`,
				HelixLanguage: "lua",
			},
			{
				Name: "dockerfile-language-server", Language: "dockerfile", Description: "Dockerfile language server",
				Command: "docker-langserver", InstallCmd: "npm install -g dockerfile-language-server-nodejs",
				InstallType: "npm", Category: "lsp", FilePatterns: []string{"Dockerfile", "Dockerfile.*"},
				Tags: []string{"docker"}, NeovimSetup: `lspconfig.dockerls.setup{}`,
				HelixLanguage: "dockerfile",
			},
			{
				Name: "tailwindcss-language-server", Language: "tailwind", Description: "Tailwind CSS language server",
				Command: "tailwindcss-language-server", InstallCmd: "npm install -g @tailwindcss/language-server",
				InstallType: "npm", Category: "lsp", FilePatterns: []string{"*.html", "*.tsx", "*.jsx"},
				ConfigFiles: []string{"tailwind.config.js", "tailwind.config.ts"},
				Tags: []string{"tailwind", "css"}, NeovimSetup: `lspconfig.tailwindcss.setup{}`,
			},
			{
				Name: "svelte-language-server", Language: "svelte", Description: "Svelte language server",
				Command: "svelteserver", InstallCmd: "npm install -g svelte-language-server",
				InstallType: "npm", Category: "lsp", FilePatterns: []string{"*.svelte"},
				Tags: []string{"svelte"}, NeovimSetup: `lspconfig.svelte.setup{}`,
				HelixLanguage: "svelte",
			},
			{
				Name: "vue-language-server", Language: "vue", Description: "Vue language server",
				Command: "vue-language-server", InstallCmd: "npm install -g @vue/language-server",
				InstallType: "npm", Category: "lsp", FilePatterns: []string{"*.vue"},
				Tags: []string{"vue"}, NeovimSetup: `lspconfig.vuels.setup{}`,
			},
			{
				Name: "golangci-lint-langserver", Language: "go-lint", Description: "Go linter language server",
				Command: "golangci-lint-langserver", InstallCmd: "go install github.com/nametake/golangci-lint-langserver@latest",
				InstallType: "go", Category: "lsp", FilePatterns: []string{"*.go"},
				Tags: []string{"go", "linting"},
			},
		},
	}
}

var lspRegistryPath string

func init() {
	home, _ := os.UserHomeDir()
	if home != "" {
		lspRegistryPath = filepath.Join(home, ".muyue", "lsp-registry.yaml")
	}
}

func SetLSPRegistryPath(p string) {
	lspRegistryPath = p
}

func LoadLSPRegistry() (*LSPRegistry, error) {
	if lspRegistryPath == "" {
		return DefaultLSPRegistry(), nil
	}

	data, err := os.ReadFile(lspRegistryPath)
	if err != nil {
		return DefaultLSPRegistry(), nil
	}

	var reg LSPRegistry
	if err := yaml.Unmarshal(data, &reg); err != nil {
		return nil, err
	}
	return &reg, nil
}

func SaveLSPRegistry(reg *LSPRegistry) error {
	if lspRegistryPath == "" {
		return nil
	}
	reg.UpdatedAt = time.Now()
	data, err := yaml.Marshal(reg)
	if err != nil {
		return err
	}
	os.MkdirAll(filepath.Dir(lspRegistryPath), 0755)
	return os.WriteFile(lspRegistryPath, data, 0644)
}

func InitLSPRegistry() error {
	if lspRegistryPath == "" {
		return nil
	}
	if _, err := os.Stat(lspRegistryPath); err == nil {
		return nil
	}
	return SaveLSPRegistry(DefaultLSPRegistry())
}

func DetectProjectLanguages(projectDir string) []string {
	if projectDir == "" {
		return nil
	}

	langDetectors := map[string][]string{
		"go":         {"go.mod", "go.sum"},
		"python":     {"requirements.txt", "pyproject.toml", "setup.py", "Pipfile", "uv.lock"},
		"typescript": {"tsconfig.json", "package.json"},
		"javascript": {"package.json"},
		"rust":       {"Cargo.toml"},
		"ruby":       {"Gemfile"},
		"java":       {"pom.xml", "build.gradle"},
		"c":          {"CMakeLists.txt", "Makefile"},
		"cpp":        {"CMakeLists.txt"},
		"php":        {"composer.json"},
		"lua":        {".luarc.json"},
		"docker":     {"Dockerfile"},
	}

	extDetectors := map[string]string{
		".go":   "go",
		".py":   "python",
		".rs":   "rust",
		".ts":   "typescript",
		".tsx":  "typescript",
		".js":   "javascript",
		".jsx":  "javascript",
		".rb":   "ruby",
		".java": "java",
		".c":    "c",
		".cpp":  "cpp",
		".h":    "c",
		".lua":  "lua",
		".vue":  "vue",
		".svelte": "svelte",
	}

	detected := map[string]bool{}
	for lang, files := range langDetectors {
		for _, f := range files {
			if _, err := os.Stat(filepath.Join(projectDir, f)); err == nil {
				detected[lang] = true
				break
			}
		}
	}

	entries, err := os.ReadDir(projectDir)
	if err == nil {
		for _, e := range entries {
			if e.IsDir() {
				continue
			}
			ext := filepath.Ext(e.Name())
			if lang, ok := extDetectors[ext]; ok {
				detected[lang] = true
			}
		}
	}

	var languages []string
	for lang := range detected {
		languages = append(languages, lang)
	}
	return languages
}

func GenerateNeovimConfig(servers []RegistryEntry) string {
	config := `-- Generated by Muyue LSP Manager
-- Add to your init.lua or require from lspconfig setup
local lspconfig = require('lspconfig')

`
	for _, s := range servers {
		if s.NeovimSetup != "" {
			config += s.NeovimSetup + "\n"
		}
	}
	return config
}

func GenerateHelixConfig(servers []RegistryEntry) string {
	config := `# Generated by Muyue LSP Manager
# Add to ~/.config/helix/languages.toml

`
	for _, s := range servers {
		if s.HelixLanguage != "" {
			config += "[[language]]\n"
			config += "name = \"" + s.HelixLanguage + "\"\n"
			config += "language-servers = [\"" + s.Name + "\"]\n\n"
		}
	}
	return config
}

func GenerateVSCodeRecommendations(servers []RegistryEntry) []string {
	extensionMap := map[string][]string{
		"gopls":                        {"golang.go"},
		"pyright":                      {"ms-python.python", "ms-python.vscode-pylance"},
		"typescript-language-server":   {"ms-vscode.vscode-typescript-next"},
		"rust-analyzer":                {"rust-lang.rust-analyzer"},
		"lua-language-server":          {"sumneko.lua"},
		"tailwindcss-language-server":  {"bradlc.vscode-tailwindcss"},
		"svelte-language-server":       {"svelte.svelte-vscode"},
		"vue-language-server":          {"vue.volar"},
		"yaml-language-server":         {"redhat.vscode-yaml"},
		"bash-language-server":         {"mads-hartmann.bash-ide-vscode"},
	}

	var extensions []string
	for _, s := range servers {
		if exts, ok := extensionMap[s.Name]; ok {
			extensions = append(extensions, exts...)
		}
	}
	return extensions
}
