package launcher

import (
	"fmt"
	"log"
	"net/url"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/driver/desktop"
	"fyne.io/fyne/v2/widget"
)

// SystrayManager manages the system tray functionality
type SystrayManager struct {
	launcher *Launcher
	window   fyne.Window
	app      fyne.App
	desk     desktop.App

	// Menu items that need dynamic updates
	startStopItem      *fyne.MenuItem
	hasUpdateAvailable bool
	latestVersion      string
	icon               *fyne.StaticResource
}

// NewSystrayManager creates a new systray manager
func NewSystrayManager(launcher *Launcher, window fyne.Window, desktop desktop.App, app fyne.App, icon *fyne.StaticResource) *SystrayManager {
	sm := &SystrayManager{
		launcher: launcher,
		window:   window,
		app:      app,
		desk:     desktop,
		icon:     icon,
	}
	sm.setupMenu(desktop)
	return sm
}

// setupMenu sets up the system tray menu
func (sm *SystrayManager) setupMenu(desk desktop.App) {
	sm.desk = desk

	// Create the start/stop toggle item
	sm.startStopItem = fyne.NewMenuItem("Start LocalAI", func() {
		sm.toggleLocalAI()
	})

	desk.SetSystemTrayIcon(sm.icon)

	// Initialize the menu state using recreateMenu
	sm.recreateMenu()
}

// toggleLocalAI starts or stops LocalAI based on current state
func (sm *SystrayManager) toggleLocalAI() {
	if sm.launcher.IsRunning() {
		go func() {
			if err := sm.launcher.StopLocalAI(); err != nil {
				log.Printf("Failed to stop LocalAI: %v", err)
				sm.showErrorDialog("Failed to Stop LocalAI", err.Error())
			}
		}()
	} else {
		go func() {
			if err := sm.launcher.StartLocalAI(); err != nil {
				log.Printf("Failed to start LocalAI: %v", err)
				sm.showStartupErrorDialog(err)
			}
		}()
	}
}

// openWebUI opens the LocalAI WebUI in the default browser
func (sm *SystrayManager) openWebUI() {
	if !sm.launcher.IsRunning() {
		return // LocalAI is not running
	}

	webURL := sm.launcher.GetWebUIURL()
	if parsedURL, err := url.Parse(webURL); err == nil {
		sm.app.OpenURL(parsedURL)
	}
}

// openDocumentation opens the LocalAI documentation
func (sm *SystrayManager) openDocumentation() {
	if parsedURL, err := url.Parse("https://localai.io"); err == nil {
		sm.app.OpenURL(parsedURL)
	}
}

// updateStartStopItem updates the start/stop menu item based on current state
func (sm *SystrayManager) updateStartStopItem() {
	// Since Fyne menu items can't change text dynamically, we recreate the menu
	sm.recreateMenu()
}

// recreateMenu recreates the entire menu with updated state
func (sm *SystrayManager) recreateMenu() {
	if sm.desk == nil {
		return
	}

	// Determine the action based on LocalAI installation and running state
	var actionItem *fyne.MenuItem
	if !sm.launcher.GetReleaseManager().IsLocalAIInstalled() {
		// LocalAI not installed - show install option
		actionItem = fyne.NewMenuItem("📥 Install Latest Version", func() {
			sm.launcher.showDownloadLocalAIDialog()
		})
	} else if sm.launcher.IsRunning() {
		// LocalAI is running - show stop option
		actionItem = fyne.NewMenuItem("🛑 Stop LocalAI", func() {
			sm.toggleLocalAI()
		})
	} else {
		// LocalAI is installed but not running - show start option
		actionItem = fyne.NewMenuItem("▶️ Start LocalAI", func() {
			sm.toggleLocalAI()
		})
	}

	menuItems := []*fyne.MenuItem{}

	// Add status at the top (clickable for details)
	status := sm.launcher.GetLastStatus()
	statusText := sm.truncateText(status, 30)
	statusItem := fyne.NewMenuItem("📊 Status: "+statusText, func() {
		sm.showStatusDetails(status, "")
	})
	menuItems = append(menuItems, statusItem)

	// Only show version if LocalAI is installed
	if sm.launcher.GetReleaseManager().IsLocalAIInstalled() {
		version := sm.launcher.GetCurrentVersion()
		versionText := sm.truncateText(version, 25)
		versionItem := fyne.NewMenuItem("🔧 Version: "+versionText, func() {
			sm.showStatusDetails(status, version)
		})
		menuItems = append(menuItems, versionItem)
	}

	menuItems = append(menuItems, fyne.NewMenuItemSeparator())

	// Add update notification if available
	if sm.hasUpdateAvailable {
		updateItem := fyne.NewMenuItem("🔔 New version available ("+sm.latestVersion+")", func() {
			sm.downloadUpdate()
		})
		menuItems = append(menuItems, updateItem)
		menuItems = append(menuItems, fyne.NewMenuItemSeparator())
	}

	// Core actions
	menuItems = append(menuItems,
		actionItem,
	)

	// Only show WebUI option if LocalAI is installed
	if sm.launcher.GetReleaseManager().IsLocalAIInstalled() && sm.launcher.IsRunning() {
		menuItems = append(menuItems,
			fyne.NewMenuItem("Open WebUI", func() {
				sm.openWebUI()
			}),
		)
	}

	menuItems = append(menuItems,
		fyne.NewMenuItemSeparator(),
		fyne.NewMenuItem("Check for Updates", func() {
			sm.checkForUpdates()
		}),
		fyne.NewMenuItemSeparator(),
		fyne.NewMenuItem("Settings", func() {
			sm.showSettings()
		}),
		fyne.NewMenuItem("Show Welcome Window", func() {
			sm.showWelcomeWindow()
		}),
		fyne.NewMenuItem("Open Data Folder", func() {
			sm.openDataFolder()
		}),
		fyne.NewMenuItemSeparator(),
		fyne.NewMenuItem("Documentation", func() {
			sm.openDocumentation()
		}),
		fyne.NewMenuItemSeparator(),
		fyne.NewMenuItem("Quit", func() {
			// Perform cleanup before quitting
			if err := sm.launcher.Shutdown(); err != nil {
				log.Printf("Error during shutdown: %v", err)
			}
			sm.app.Quit()
		}),
	)

	menu := fyne.NewMenu("LocalAI", menuItems...)
	sm.desk.SetSystemTrayMenu(menu)
}

// UpdateRunningState updates the systray based on running state
func (sm *SystrayManager) UpdateRunningState(isRunning bool) {
	sm.updateStartStopItem()
}

// UpdateStatus updates the systray menu to reflect status changes
func (sm *SystrayManager) UpdateStatus(status string) {
	sm.recreateMenu()
}

// checkForUpdates checks for available updates
func (sm *SystrayManager) checkForUpdates() {
	go func() {
		log.Printf("Checking for updates...")
		available, version, err := sm.launcher.CheckForUpdates()
		if err != nil {
			log.Printf("Failed to check for updates: %v", err)
			return
		}

		log.Printf("Update check result: available=%v, version=%s", available, version)
		if available {
			sm.hasUpdateAvailable = true
			sm.latestVersion = version
			sm.recreateMenu()
		}
	}()
}

// downloadUpdate downloads the latest update
func (sm *SystrayManager) downloadUpdate() {
	if !sm.hasUpdateAvailable {
		return
	}

	// Show progress window
	sm.showDownloadProgress(sm.latestVersion)
}

// showSettings shows the settings window
func (sm *SystrayManager) showSettings() {
	sm.window.Show()
	sm.window.RequestFocus()
}

// showWelcomeWindow shows the welcome window
func (sm *SystrayManager) showWelcomeWindow() {
	if sm.launcher.GetUI() != nil {
		sm.launcher.GetUI().ShowWelcomeWindow()
	}
}

// openDataFolder opens the data folder in file manager
func (sm *SystrayManager) openDataFolder() {
	dataPath := sm.launcher.GetDataPath()
	if parsedURL, err := url.Parse("file://" + dataPath); err == nil {
		sm.app.OpenURL(parsedURL)
	}
}

// NotifyUpdateAvailable sets update notification in systray
func (sm *SystrayManager) NotifyUpdateAvailable(version string) {
	sm.hasUpdateAvailable = true
	sm.latestVersion = version
	sm.recreateMenu()
}

// truncateText truncates text to specified length and adds ellipsis if needed
func (sm *SystrayManager) truncateText(text string, maxLength int) string {
	if len(text) <= maxLength {
		return text
	}
	return text[:maxLength-3] + "..."
}

// showStatusDetails shows a detailed status window with full information
func (sm *SystrayManager) showStatusDetails(status, version string) {
	fyne.DoAndWait(func() {
		// Create status details window
		statusWindow := sm.app.NewWindow("LocalAI Status Details")
		statusWindow.Resize(fyne.NewSize(500, 400))
		statusWindow.CenterOnScreen()

		// Status information
		statusLabel := widget.NewLabel("Current Status:")
		statusValue := widget.NewLabel(status)
		statusValue.Wrapping = fyne.TextWrapWord

		// Version information (only show if version exists)
		var versionContainer fyne.CanvasObject
		if version != "" {
			versionLabel := widget.NewLabel("Installed Version:")
			versionValue := widget.NewLabel(version)
			versionValue.Wrapping = fyne.TextWrapWord
			versionContainer = container.NewVBox(versionLabel, versionValue)
		}

		// Running state
		runningLabel := widget.NewLabel("Running State:")
		runningValue := widget.NewLabel("")
		if sm.launcher.IsRunning() {
			runningValue.SetText("🟢 Running")
		} else {
			runningValue.SetText("🔴 Stopped")
		}

		// WebUI URL
		webuiLabel := widget.NewLabel("WebUI URL:")
		webuiValue := widget.NewLabel(sm.launcher.GetWebUIURL())
		webuiValue.Wrapping = fyne.TextWrapWord

		// Recent logs (last 20 lines)
		logsLabel := widget.NewLabel("Recent Logs:")
		logsText := widget.NewMultiLineEntry()
		logsText.SetText(sm.launcher.GetRecentLogs())
		logsText.Wrapping = fyne.TextWrapWord
		logsText.Disable() // Make it read-only

		// Buttons
		closeButton := widget.NewButton("Close", func() {
			statusWindow.Close()
		})

		refreshButton := widget.NewButton("Refresh", func() {
			// Refresh the status information
			statusValue.SetText(sm.launcher.GetLastStatus())

			// Note: Version refresh is not implemented for simplicity
			// The version will be updated when the status details window is reopened

			if sm.launcher.IsRunning() {
				runningValue.SetText("🟢 Running")
			} else {
				runningValue.SetText("🔴 Stopped")
			}
			logsText.SetText(sm.launcher.GetRecentLogs())
		})

		openWebUIButton := widget.NewButton("Open WebUI", func() {
			sm.openWebUI()
		})

		// Layout
		buttons := container.NewHBox(closeButton, refreshButton, openWebUIButton)

		// Build info container dynamically
		infoItems := []fyne.CanvasObject{
			statusLabel, statusValue,
			widget.NewSeparator(),
		}

		// Add version section if it exists
		if versionContainer != nil {
			infoItems = append(infoItems, versionContainer, widget.NewSeparator())
		}

		infoItems = append(infoItems,
			runningLabel, runningValue,
			widget.NewSeparator(),
			webuiLabel, webuiValue,
		)

		infoContainer := container.NewVBox(infoItems...)

		content := container.NewVBox(
			infoContainer,
			widget.NewSeparator(),
			logsLabel,
			logsText,
			widget.NewSeparator(),
			buttons,
		)

		statusWindow.SetContent(content)
		statusWindow.Show()
	})
}

// showErrorDialog shows a simple error dialog
func (sm *SystrayManager) showErrorDialog(title, message string) {
	fyne.DoAndWait(func() {
		dialog.ShowError(fmt.Errorf("%s", message), sm.window)
	})
}

// showStartupErrorDialog shows a detailed error dialog with process logs
func (sm *SystrayManager) showStartupErrorDialog(err error) {
	fyne.DoAndWait(func() {
		// Get the recent process logs (more useful for debugging)
		logs := sm.launcher.GetRecentLogs()

		// Create error window
		errorWindow := sm.app.NewWindow("LocalAI Startup Failed")
		errorWindow.Resize(fyne.NewSize(600, 500))
		errorWindow.CenterOnScreen()

		// Error message
		errorLabel := widget.NewLabel(fmt.Sprintf("Failed to start LocalAI:\n%s", err.Error()))
		errorLabel.Wrapping = fyne.TextWrapWord

		// Logs display
		logsLabel := widget.NewLabel("Process Logs:")
		logsText := widget.NewMultiLineEntry()
		logsText.SetText(logs)
		logsText.Wrapping = fyne.TextWrapWord
		logsText.Disable() // Make it read-only

		// Buttons
		closeButton := widget.NewButton("Close", func() {
			errorWindow.Close()
		})

		retryButton := widget.NewButton("Retry", func() {
			errorWindow.Close()
			// Try to start again
			go func() {
				if retryErr := sm.launcher.StartLocalAI(); retryErr != nil {
					sm.showStartupErrorDialog(retryErr)
				}
			}()
		})

		openLogsButton := widget.NewButton("Open Logs Folder", func() {
			sm.openDataFolder()
		})

		// Layout
		buttons := container.NewHBox(closeButton, retryButton, openLogsButton)
		content := container.NewVBox(
			errorLabel,
			widget.NewSeparator(),
			logsLabel,
			logsText,
			widget.NewSeparator(),
			buttons,
		)

		errorWindow.SetContent(content)
		errorWindow.Show()
	})
}

// showDownloadProgress shows a progress window for downloading updates
func (sm *SystrayManager) showDownloadProgress(version string) {
	// Create a new window for download progress
	progressWindow := sm.app.NewWindow("Downloading LocalAI Update")
	progressWindow.Resize(fyne.NewSize(400, 250))
	progressWindow.CenterOnScreen()

	// Progress bar
	progressBar := widget.NewProgressBar()
	progressBar.SetValue(0)

	// Status label
	statusLabel := widget.NewLabel("Preparing download...")

	// Release notes button
	releaseNotesButton := widget.NewButton("View Release Notes", func() {
		releaseNotesURL, err := sm.launcher.githubReleaseNotesURL(version)
		if err != nil {
			log.Printf("Failed to parse URL: %v", err)
			return
		}

		sm.app.OpenURL(releaseNotesURL)
	})

	// Progress container
	progressContainer := container.NewVBox(
		widget.NewLabel(fmt.Sprintf("Downloading LocalAI version %s", version)),
		progressBar,
		statusLabel,
		widget.NewSeparator(),
		releaseNotesButton,
	)

	progressWindow.SetContent(progressContainer)
	progressWindow.Show()

	// Start download in background
	go func() {
		err := sm.launcher.DownloadUpdate(version, func(progress float64) {
			// Update progress bar
			fyne.Do(func() {
				progressBar.SetValue(progress)
				percentage := int(progress * 100)
				statusLabel.SetText(fmt.Sprintf("Downloading... %d%%", percentage))
			})
		})

		// Handle completion
		fyne.Do(func() {
			if err != nil {
				statusLabel.SetText(fmt.Sprintf("Download failed: %v", err))
				// Show error dialog
				dialog.ShowError(err, progressWindow)
			} else {
				statusLabel.SetText("Download completed successfully!")
				progressBar.SetValue(1.0)

				// Show restart dialog
				dialog.ShowConfirm("Update Downloaded",
					"LocalAI has been updated successfully. Please restart the launcher to use the new version.",
					func(restart bool) {
						if restart {
							sm.app.Quit()
						}
						progressWindow.Close()
					}, progressWindow)
			}
		})

		// Update systray menu
		if err == nil {
			sm.hasUpdateAvailable = false
			sm.latestVersion = ""
			sm.recreateMenu()
		}
	}()
}
