package main

import (
	"gf-lt/models"
	"slices"
	"strings"

	"github.com/gdamore/tcell/v2"
	"github.com/rivo/tview"
)

// showModelSelectionPopup creates a modal popup to select a model
func showModelSelectionPopup() {
	// Helper function to get model list for a given API
	getModelListForAPI := func(api string) []string {
		if strings.Contains(api, "api.deepseek.com/") {
			return []string{"deepseek-chat", "deepseek-reasoner"}
		} else if strings.Contains(api, "openrouter.ai") {
			return ORFreeModels
		}
		// Assume local llama.cpp - fetch with load status
		models, err := fetchLCPModelsWithLoadStatus()
		if err != nil {
			logger.Error("failed to fetch models with load status", "error", err)
			return LocalModels
		}
		return models
	}
	// Get the current model list based on the API
	modelList := getModelListForAPI(cfg.CurrentAPI)
	// Check for empty options list
	if len(modelList) == 0 {
		logger.Warn("empty model list for", "api", cfg.CurrentAPI, "localModelsLen", len(LocalModels), "orModelsLen", len(ORFreeModels))
		var message string
		switch {
		case strings.Contains(cfg.CurrentAPI, "openrouter.ai"):
			message = "No OpenRouter models available. Check token and connection."
		case strings.Contains(cfg.CurrentAPI, "api.deepseek.com"):
			message = "DeepSeek models should be available. Please report bug."
		default:
			message = "No llama.cpp models loaded. Ensure llama.cpp server is running with models."
		}
		showToast("Empty list", message)
		return
	}
	// Create a list primitive
	modelListWidget := tview.NewList().ShowSecondaryText(false).
		SetSelectedBackgroundColor(tcell.ColorGray)
	modelListWidget.SetTitle("Select Model").SetBorder(true)
	// Find the current model index to set as selected
	currentModelIndex := -1
	for i, model := range modelList {
		if strings.TrimPrefix(model, models.LoadedMark) == chatBody.Model {
			currentModelIndex = i
		}
		modelListWidget.AddItem(model, "", 0, nil)
	}
	// Set the current selection if found
	if currentModelIndex != -1 {
		modelListWidget.SetCurrentItem(currentModelIndex)
	}
	modelListWidget.SetSelectedFunc(func(index int, mainText string, secondaryText string, shortcut rune) {
		modelName := strings.TrimPrefix(mainText, models.LoadedMark)
		chatBody.Model = modelName
		cfg.CurrentModel = chatBody.Model
		pages.RemovePage("modelSelectionPopup")
		app.SetFocus(textArea)
		updateCachedModelColor()
		updateStatusLine()
	})
	modelListWidget.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		if event.Key() == tcell.KeyEscape {
			pages.RemovePage("modelSelectionPopup")
			app.SetFocus(textArea)
			return nil
		}
		if event.Key() == tcell.KeyRune && event.Rune() == 'x' {
			pages.RemovePage("modelSelectionPopup")
			app.SetFocus(textArea)
			return nil
		}
		return event
	})
	modal := func(p tview.Primitive, width, height int) tview.Primitive {
		return tview.NewFlex().
			AddItem(nil, 0, 1, false).
			AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
				AddItem(nil, 0, 1, false).
				AddItem(p, height, 1, true).
				AddItem(nil, 0, 1, false), width, 1, true).
			AddItem(nil, 0, 1, false)
	}
	// Add modal page and make it visible
	pages.AddPage("modelSelectionPopup", modal(modelListWidget, 80, 20), true, true)
	app.SetFocus(modelListWidget)
}

// showAPILinkSelectionPopup creates a modal popup to select an API link
func showAPILinkSelectionPopup() {
	// Prepare API links dropdown - ensure current API is in the list, avoid duplicates
	apiLinks := make([]string, 0, len(cfg.ApiLinks)+1)
	// Add current API first if it's not already in ApiLinks
	foundCurrentAPI := false
	for _, api := range cfg.ApiLinks {
		if api == cfg.CurrentAPI {
			foundCurrentAPI = true
		}
		apiLinks = append(apiLinks, api)
	}
	// If current API is not in the list, add it at the beginning
	if !foundCurrentAPI {
		apiLinks = make([]string, 0, len(cfg.ApiLinks)+1)
		apiLinks = append(apiLinks, cfg.CurrentAPI)
		apiLinks = append(apiLinks, cfg.ApiLinks...)
	}
	// Check for empty options list
	if len(apiLinks) == 0 {
		logger.Warn("no API links available for selection")
		message := "No API links available. Please configure API links in your config file."
		showToast("Empty list", message)
		return
	}
	// Create a list primitive
	apiListWidget := tview.NewList().ShowSecondaryText(false).
		SetSelectedBackgroundColor(tcell.ColorGray)
	apiListWidget.SetTitle("Select API Link").SetBorder(true)
	// Find the current API index to set as selected
	currentAPIIndex := -1
	for i, api := range apiLinks {
		if api == cfg.CurrentAPI {
			currentAPIIndex = i
		}
		apiListWidget.AddItem(api, "", 0, nil)
	}
	// Set the current selection if found
	if currentAPIIndex != -1 {
		apiListWidget.SetCurrentItem(currentAPIIndex)
	}
	apiListWidget.SetSelectedFunc(func(index int, mainText string, secondaryText string, shortcut rune) {
		// Update the API in config
		cfg.CurrentAPI = mainText
		// tools.UpdateToolCapabilities()
		// Update model list based on new API
		// Helper function to get model list for a given API (same as in props_table.go)
		getModelListForAPI := func(api string) []string {
			if strings.Contains(api, "api.deepseek.com/") {
				return []string{"deepseek-chat", "deepseek-reasoner"}
			} else if strings.Contains(api, "openrouter.ai") {
				return ORFreeModels
			}
			// Assume local llama.cpp
			refreshLocalModelsIfEmpty()
			localModelsMu.RLock()
			defer localModelsMu.RUnlock()
			return LocalModels
		}
		newModelList := getModelListForAPI(cfg.CurrentAPI)
		// Ensure chatBody.Model is in the new list; if not, set to first available model
		if len(newModelList) > 0 && !slices.Contains(newModelList, chatBody.Model) {
			chatBody.Model = strings.TrimPrefix(newModelList[0], models.LoadedMark)
			cfg.CurrentModel = chatBody.Model
			UpdateToolCapabilities()
		}
		pages.RemovePage("apiLinkSelectionPopup")
		app.SetFocus(textArea)
		choseChunkParser()
		updateCachedModelColor()
		updateStatusLine()
	})
	apiListWidget.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		if event.Key() == tcell.KeyEscape {
			pages.RemovePage("apiLinkSelectionPopup")
			app.SetFocus(textArea)
			return nil
		}
		if event.Key() == tcell.KeyRune && event.Rune() == 'x' {
			pages.RemovePage("apiLinkSelectionPopup")
			app.SetFocus(textArea)
			return nil
		}
		return event
	})
	modal := func(p tview.Primitive, width, height int) tview.Primitive {
		return tview.NewFlex().
			AddItem(nil, 0, 1, false).
			AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
				AddItem(nil, 0, 1, false).
				AddItem(p, height, 1, true).
				AddItem(nil, 0, 1, false), width, 1, true).
			AddItem(nil, 0, 1, false)
	}
	// Add modal page and make it visible
	pages.AddPage("apiLinkSelectionPopup", modal(apiListWidget, 80, 20), true, true)
	app.SetFocus(apiListWidget)
}

// showUserRoleSelectionPopup creates a modal popup to select a user role
func showUserRoleSelectionPopup() {
	// Get the list of available roles
	roles := listRolesWithUser()
	// Check for empty options list
	if len(roles) == 0 {
		logger.Warn("no roles available for selection")
		message := "No roles available for selection."
		showToast("Empty list", message)
		return
	}
	// Create a list primitive
	roleListWidget := tview.NewList().ShowSecondaryText(false).
		SetSelectedBackgroundColor(tcell.ColorGray)
	roleListWidget.SetTitle("Select User Role").SetBorder(true)
	// Find the current role index to set as selected
	currentRole := cfg.UserRole
	if cfg.WriteNextMsgAs != "" {
		currentRole = cfg.WriteNextMsgAs
	}
	currentRoleIndex := -1
	for i, role := range roles {
		if strings.EqualFold(role, currentRole) {
			currentRoleIndex = i
		}
		roleListWidget.AddItem(role, "", 0, nil)
	}
	// Set the current selection if found
	if currentRoleIndex != -1 {
		roleListWidget.SetCurrentItem(currentRoleIndex)
	}
	roleListWidget.SetSelectedFunc(func(index int, mainText string, secondaryText string, shortcut rune) {
		// Update the user role in config
		cfg.WriteNextMsgAs = mainText
		// role got switch, update textview with character specific context for user
		filtered := filterMessagesForCharacter(chatBody.Messages, mainText)
		textView.SetText(chatToText(filtered, cfg.ShowSys))
		// Remove the popup page
		pages.RemovePage("userRoleSelectionPopup")
		app.SetFocus(textArea)
		// Update the status line to reflect the change
		updateStatusLine()
		colorText()
	})
	roleListWidget.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		if event.Key() == tcell.KeyEscape {
			pages.RemovePage("userRoleSelectionPopup")
			app.SetFocus(textArea)
			return nil
		}
		if event.Key() == tcell.KeyRune && event.Rune() == 'x' {
			pages.RemovePage("userRoleSelectionPopup")
			app.SetFocus(textArea)
			return nil
		}
		return event
	})
	modal := func(p tview.Primitive, width, height int) tview.Primitive {
		return tview.NewFlex().
			AddItem(nil, 0, 1, false).
			AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
				AddItem(nil, 0, 1, false).
				AddItem(p, height, 1, true).
				AddItem(nil, 0, 1, false), width, 1, true).
			AddItem(nil, 0, 1, false)
	}
	// Add modal page and make it visible
	pages.AddPage("userRoleSelectionPopup", modal(roleListWidget, 80, 20), true, true)
	app.SetFocus(roleListWidget)
}

// showBotRoleSelectionPopup creates a modal popup to select a bot role
func showBotRoleSelectionPopup() {
	// Get the list of available roles
	roles := listChatRoles()
	if len(roles) == 0 {
		logger.Warn("empty roles in chat")
	}
	if !strInSlice(cfg.AssistantRole, roles) {
		roles = append(roles, cfg.AssistantRole)
	}
	// Check for empty options list
	if len(roles) == 0 {
		logger.Warn("no roles available for selection")
		message := "No roles available for selection."
		showToast("Empty list", message)
		return
	}
	// Create a list primitive
	roleListWidget := tview.NewList().ShowSecondaryText(false).
		SetSelectedBackgroundColor(tcell.ColorGray)
	roleListWidget.SetTitle("Select Bot Role").SetBorder(true)
	// Find the current role index to set as selected
	currentRole := cfg.AssistantRole
	if cfg.WriteNextMsgAsCompletionAgent != "" {
		currentRole = cfg.WriteNextMsgAsCompletionAgent
	}
	currentRoleIndex := -1
	for i, role := range roles {
		if strings.EqualFold(role, currentRole) {
			currentRoleIndex = i
		}
		roleListWidget.AddItem(role, "", 0, nil)
	}
	// Set the current selection if found
	if currentRoleIndex != -1 {
		roleListWidget.SetCurrentItem(currentRoleIndex)
	}
	roleListWidget.SetSelectedFunc(func(index int, mainText string, secondaryText string, shortcut rune) {
		// Update the bot role in config
		cfg.WriteNextMsgAsCompletionAgent = mainText
		// Remove the popup page
		pages.RemovePage("botRoleSelectionPopup")
		app.SetFocus(textArea)
		// Update the status line to reflect the change
		updateStatusLine()
	})
	roleListWidget.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		if event.Key() == tcell.KeyEscape {
			pages.RemovePage("botRoleSelectionPopup")
			app.SetFocus(textArea)
			return nil
		}
		if event.Key() == tcell.KeyRune && event.Rune() == 'x' {
			pages.RemovePage("botRoleSelectionPopup")
			app.SetFocus(textArea)
			return nil
		}
		return event
	})
	modal := func(p tview.Primitive, width, height int) tview.Primitive {
		return tview.NewFlex().
			AddItem(nil, 0, 1, false).
			AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
				AddItem(nil, 0, 1, false).
				AddItem(p, height, 1, true).
				AddItem(nil, 0, 1, false), width, 1, true).
			AddItem(nil, 0, 1, false)
	}
	// Add modal page and make it visible
	pages.AddPage("botRoleSelectionPopup", modal(roleListWidget, 80, 20), true, true)
	app.SetFocus(roleListWidget)
}

func showShellFileCompletionPopup(filter string) {
	baseDir := cfg.FilePickerDir
	if baseDir == "" {
		baseDir = "."
	}
	complMatches := scanFiles(baseDir, filter)
	if len(complMatches) == 0 {
		return
	}
	if len(complMatches) == 1 {
		currentText := shellInput.GetText()
		atIdx := strings.LastIndex(currentText, "@")
		if atIdx >= 0 {
			before := currentText[:atIdx]
			shellInput.SetText(before + complMatches[0])
		}
		return
	}
	widget := tview.NewList().ShowSecondaryText(false).
		SetSelectedBackgroundColor(tcell.ColorGray)
	widget.SetTitle("file completion").SetBorder(true)
	for _, m := range complMatches {
		widget.AddItem(m, "", 0, nil)
	}
	widget.SetSelectedFunc(func(index int, mainText string, secondaryText string, shortcut rune) {
		currentText := shellInput.GetText()
		atIdx := strings.LastIndex(currentText, "@")
		if atIdx >= 0 {
			before := currentText[:atIdx]
			shellInput.SetText(before + mainText)
		}
		pages.RemovePage("shellFileCompletionPopup")
		app.SetFocus(shellInput)
	})
	widget.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		if event.Key() == tcell.KeyEscape {
			pages.RemovePage("shellFileCompletionPopup")
			app.SetFocus(shellInput)
			return nil
		}
		if event.Key() == tcell.KeyRune && event.Rune() == 'x' {
			pages.RemovePage("shellFileCompletionPopup")
			app.SetFocus(shellInput)
			return nil
		}
		return event
	})
	modal := func(p tview.Primitive, width, height int) tview.Primitive {
		return tview.NewFlex().
			AddItem(nil, 0, 1, false).
			AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
				AddItem(nil, 0, 1, false).
				AddItem(p, height, 1, true).
				AddItem(nil, 0, 1, false), width, 1, true).
			AddItem(nil, 0, 1, false)
	}
	pages.AddPage("shellFileCompletionPopup", modal(widget, 80, 20), true, true)
	app.SetFocus(widget)
}

func showTextAreaFileCompletionPopup(filter string) {
	baseDir := cfg.FilePickerDir
	if baseDir == "" {
		baseDir = "."
	}
	complMatches := scanFiles(baseDir, filter)
	if len(complMatches) == 0 {
		return
	}
	if len(complMatches) == 1 {
		currentText := textArea.GetText()
		atIdx := strings.LastIndex(currentText, "@")
		if atIdx >= 0 {
			before := currentText[:atIdx]
			textArea.SetText(before+complMatches[0], true)
		}
		return
	}
	widget := tview.NewList().ShowSecondaryText(false).
		SetSelectedBackgroundColor(tcell.ColorGray)
	widget.SetTitle("file completion").SetBorder(true)
	for _, m := range complMatches {
		widget.AddItem(m, "", 0, nil)
	}
	widget.SetSelectedFunc(func(index int, mainText string, secondaryText string, shortcut rune) {
		currentText := textArea.GetText()
		atIdx := strings.LastIndex(currentText, "@")
		if atIdx >= 0 {
			before := currentText[:atIdx]
			textArea.SetText(before+mainText, true)
		}
		pages.RemovePage("textAreaFileCompletionPopup")
		app.SetFocus(textArea)
	})
	widget.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		if event.Key() == tcell.KeyEscape {
			pages.RemovePage("textAreaFileCompletionPopup")
			app.SetFocus(textArea)
			return nil
		}
		if event.Key() == tcell.KeyRune && event.Rune() == 'x' {
			pages.RemovePage("textAreaFileCompletionPopup")
			app.SetFocus(textArea)
			return nil
		}
		return event
	})
	modal := func(p tview.Primitive, width, height int) tview.Primitive {
		return tview.NewFlex().
			AddItem(nil, 0, 1, false).
			AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
				AddItem(nil, 0, 1, false).
				AddItem(p, height, 1, true).
				AddItem(nil, 0, 1, false), width, 1, true).
			AddItem(nil, 0, 1, false)
	}
	pages.AddPage("textAreaFileCompletionPopup", modal(widget, 80, 20), true, true)
	app.SetFocus(widget)
}

func updateWidgetColors(theme *tview.Theme) {
	bgColor := theme.PrimitiveBackgroundColor
	fgColor := theme.PrimaryTextColor
	borderColor := theme.BorderColor
	titleColor := theme.TitleColor
	textView.SetBackgroundColor(bgColor)
	textView.SetTextColor(fgColor)
	textView.SetBorderColor(borderColor)
	textView.SetTitleColor(titleColor)
	textArea.SetBackgroundColor(bgColor)
	textArea.SetBorderColor(borderColor)
	textArea.SetTitleColor(titleColor)
	textArea.SetTextStyle(tcell.StyleDefault.Background(bgColor).Foreground(fgColor))
	textArea.SetPlaceholderStyle(tcell.StyleDefault.Background(bgColor).Foreground(fgColor))
	textArea.SetText(textArea.GetText(), true)
	editArea.SetBackgroundColor(bgColor)
	editArea.SetBorderColor(borderColor)
	editArea.SetTitleColor(titleColor)
	editArea.SetTextStyle(tcell.StyleDefault.Background(bgColor).Foreground(fgColor))
	editArea.SetPlaceholderStyle(tcell.StyleDefault.Background(bgColor).Foreground(fgColor))
	editArea.SetText(editArea.GetText(), true)
	statusLineWidget.SetBackgroundColor(bgColor)
	statusLineWidget.SetTextColor(fgColor)
	statusLineWidget.SetBorderColor(borderColor)
	statusLineWidget.SetTitleColor(titleColor)
	helpView.SetBackgroundColor(bgColor)
	helpView.SetTextColor(fgColor)
	helpView.SetBorderColor(borderColor)
	helpView.SetTitleColor(titleColor)
	searchField.SetBackgroundColor(bgColor)
	searchField.SetBorderColor(borderColor)
	searchField.SetTitleColor(titleColor)
}

// showColorschemeSelectionPopup creates a modal popup to select a colorscheme
func showColorschemeSelectionPopup() {
	// Get the list of available colorschemes
	schemeNames := make([]string, 0, len(colorschemes))
	for name := range colorschemes {
		schemeNames = append(schemeNames, name)
	}
	slices.Sort(schemeNames)
	// Check for empty options list
	if len(schemeNames) == 0 {
		logger.Warn("no colorschemes available for selection")
		message := "No colorschemes available."
		showToast("Empty list", message)
		return
	}
	// Create a list primitive
	schemeListWidget := tview.NewList().ShowSecondaryText(false).
		SetSelectedBackgroundColor(tcell.ColorGray)
	schemeListWidget.SetTitle("Select Colorscheme").SetBorder(true)
	currentScheme := "default"
	for name := range colorschemes {
		if tview.Styles == colorschemes[name] {
			currentScheme = name
			break
		}
	}
	currentSchemeIndex := -1
	for i, scheme := range schemeNames {
		if scheme == currentScheme {
			currentSchemeIndex = i
		}
		schemeListWidget.AddItem(scheme, "", 0, nil)
	}
	// Set the current selection if found
	if currentSchemeIndex != -1 {
		schemeListWidget.SetCurrentItem(currentSchemeIndex)
	}
	schemeListWidget.SetSelectedFunc(func(index int, mainText string, secondaryText string, shortcut rune) {
		// Update the colorscheme
		if theme, ok := colorschemes[mainText]; ok {
			tview.Styles = theme
			go func() {
				app.QueueUpdateDraw(func() {
					updateWidgetColors(&theme)
				})
			}()
		}
		// Remove the popup page
		pages.RemovePage("colorschemeSelectionPopup")
		app.SetFocus(textArea)
	})
	schemeListWidget.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		if event.Key() == tcell.KeyEscape {
			pages.RemovePage("colorschemeSelectionPopup")
			app.SetFocus(textArea)
			return nil
		}
		if event.Key() == tcell.KeyRune && event.Rune() == 'x' {
			pages.RemovePage("colorschemeSelectionPopup")
			app.SetFocus(textArea)
			return nil
		}
		return event
	})
	modal := func(p tview.Primitive, width, height int) tview.Primitive {
		return tview.NewFlex().
			AddItem(nil, 0, 1, false).
			AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
				AddItem(nil, 0, 1, false).
				AddItem(p, height, 1, true).
				AddItem(nil, 0, 1, false), width, 1, true).
			AddItem(nil, 0, 1, false)
	}
	// Add modal page and make it visible
	pages.AddPage("colorschemeSelectionPopup", modal(schemeListWidget, 40, len(schemeNames)+2), true, true)
	app.SetFocus(schemeListWidget)
}
