package tui

import (
	"context"
	"fmt"
	"strings"

	"github.com/AvengeMedia/DankMaterialShell/core/internal/deps"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/distros"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/utils"
	tea "github.com/charmbracelet/bubbletea"
)

func (m Model) viewDetectingDeps() string {
	var b strings.Builder

	b.WriteString(m.renderBanner())
	b.WriteString("\n")

	title := m.styles.Title.Render("Detecting Dependencies")
	b.WriteString(title)
	b.WriteString("\n\n")

	spinner := m.spinner.View()
	status := m.styles.Normal.Render("Scanning system for existing packages and configurations...")
	fmt.Fprintf(&b, "%s %s", spinner, status)

	return b.String()
}

func partitionOptionalLast(dependencies []deps.Dependency) []deps.Dependency {
	ordered := make([]deps.Dependency, 0, len(dependencies))
	for _, dep := range dependencies {
		if dep.Required {
			ordered = append(ordered, dep)
		}
	}
	for _, dep := range dependencies {
		if !dep.Required {
			ordered = append(ordered, dep)
		}
	}
	return ordered
}

func (m Model) viewDependencyReview() string {
	var b strings.Builder

	b.WriteString(m.renderBanner())
	b.WriteString("\n")

	title := m.styles.Title.Render("Dependency Review")
	b.WriteString(title)
	b.WriteString("\n\n")

	if len(m.dependencies) > 0 {
		optionalHeaderShown := false
		for i, dep := range m.dependencies {
			if !dep.Required && !optionalHeaderShown {
				b.WriteString("\n")
				b.WriteString(m.styles.Subtle.Render("Optional (space to enable)"))
				b.WriteString("\n")
				optionalHeaderShown = true
			}

			var status string
			var reinstallMarker string
			var variantMarker string

			isDMS := dep.Name == "dms (DankMaterialShell)"

			if dep.CanToggle && dep.Variant == deps.VariantGit {
				variantMarker = "[git] "
			}

			if m.disabledItems[dep.Name] {
				reinstallMarker = "✗ "
				status = m.styles.Subtle.Render("Will skip")
			} else if m.reinstallItems[dep.Name] {
				reinstallMarker = "🔄 "
				status = m.styles.Warning.Render("Will upgrade")
			} else if isDMS {
				reinstallMarker = "⚡ "
				switch dep.Status {
				case deps.StatusInstalled:
					status = m.styles.Success.Render("✓ Required (installed)")
				case deps.StatusMissing:
					status = m.styles.Warning.Render("○ Required (will install)")
				case deps.StatusNeedsUpdate:
					status = m.styles.Warning.Render("△ Required (needs update)")
				case deps.StatusNeedsReinstall:
					status = m.styles.Error.Render("! Required (needs reinstall)")
				}
			} else {
				switch dep.Status {
				case deps.StatusInstalled:
					status = m.styles.Subtle.Render("✓ Already installed")
				case deps.StatusMissing:
					status = m.styles.Warning.Render("○ Will install")
				case deps.StatusNeedsUpdate:
					status = m.styles.Warning.Render("△ Will install")
				case deps.StatusNeedsReinstall:
					status = m.styles.Error.Render("! Will install")
				}
			}

			note := ""
			switch dep.Name {
			case "dms-greeter":
				note = m.styles.Subtle.Render(" (selection replaces your current display manager)")
			case "danksearch":
				note = m.styles.Subtle.Render(" (file search; enables dsearch.service)")
			case "dankcalendar":
				note = m.styles.Subtle.Render(" (autostart managed in dankcalendar settings)")
			}

			var line string
			if i == m.selectedDep {
				line = fmt.Sprintf("▶ %s%s%-25s %s", reinstallMarker, variantMarker, dep.Name, status)
				if dep.Version != "" {
					line += fmt.Sprintf(" (%s)", dep.Version)
				}
				line = m.styles.SelectedOption.Render(line) + note
			} else {
				line = fmt.Sprintf("  %s%s%-25s %s", reinstallMarker, variantMarker, dep.Name, status)
				if dep.Version != "" {
					line += fmt.Sprintf(" (%s)", dep.Version)
				}
				line = m.styles.Normal.Render(line) + note
			}

			b.WriteString(line)
			b.WriteString("\n")
		}
	}

	b.WriteString("\n")
	help := m.styles.Subtle.Render("↑/↓: Navigate, Space: Toggle, G: Toggle stable/git, Enter: Continue")
	b.WriteString(help)

	return b.String()
}

func (m Model) updateDetectingDepsState(msg tea.Msg) (tea.Model, tea.Cmd) {
	if depsMsg, ok := msg.(depsDetectedMsg); ok {
		m.isLoading = false
		if depsMsg.err != nil {
			m.err = depsMsg.err
			m.state = StateError
		} else {
			m.dependencies = partitionOptionalLast(depsMsg.deps)
			// Optional components are opt-in, skipped by default
			for _, dep := range m.dependencies {
				if dep.Required {
					continue
				}
				m.disabledItems[dep.Name] = true
			}
			m.state = StateDependencyReview
		}
		return m, m.listenForLogs()
	}
	return m, m.listenForLogs()
}

func (m Model) updateDependencyReviewState(msg tea.Msg) (tea.Model, tea.Cmd) {
	if keyMsg, ok := msg.(tea.KeyMsg); ok {
		switch keyMsg.String() {
		case "up":
			if m.selectedDep > 0 {
				m.selectedDep--
			}
		case "down":
			if m.selectedDep < len(m.dependencies)-1 {
				m.selectedDep++
			}
		case " ":
			if len(m.dependencies) > 0 {
				depName := m.dependencies[m.selectedDep].Name
				isDMS := depName == "dms (DankMaterialShell)"

				if !isDMS {
					isInstalled := m.dependencies[m.selectedDep].Status == deps.StatusInstalled ||
						m.dependencies[m.selectedDep].Status == deps.StatusNeedsReinstall

					if isInstalled {
						m.reinstallItems[depName] = !m.reinstallItems[depName]
						m.disabledItems[depName] = false
					} else {
						m.disabledItems[depName] = !m.disabledItems[depName]
						m.reinstallItems[depName] = false
					}
				}
			}
		case "g", "G":
			if len(m.dependencies) > 0 && m.dependencies[m.selectedDep].CanToggle {
				if m.dependencies[m.selectedDep].Variant == deps.VariantStable {
					m.dependencies[m.selectedDep].Variant = deps.VariantGit
				} else {
					m.dependencies[m.selectedDep].Variant = deps.VariantStable
				}
			}
		case "enter":
			// Check if on Gentoo - show USE flags screen
			if m.osInfo != nil {
				if config, exists := distros.Registry[m.osInfo.Distribution.ID]; exists && config.Family == distros.FamilyGentoo {
					m.state = StateGentooUseFlags
					return m, nil
				}
			}
			return m.enterAuthPhase()
		case "esc":
			m.state = StateSelectWindowManager
			return m, nil
		}
	}
	return m, m.listenForLogs()
}

func (m Model) installPackages() tea.Cmd {
	return func() tea.Msg {
		if m.osInfo == nil {
			return packageInstallProgressMsg{
				progress:   0.0,
				step:       "Error: OS info not available",
				isComplete: true,
			}
		}

		installer, err := distros.NewPackageInstaller(m.osInfo.Distribution.ID, m.logChan)
		if err != nil {
			return packageInstallProgressMsg{
				progress:   0.0,
				step:       fmt.Sprintf("Error: %s", err.Error()),
				isComplete: true,
			}
		}

		// Convert TUI selection to deps enum
		wm := m.selectedWindowManager()

		installerProgressChan := make(chan distros.InstallProgressMsg, 100)

		go func() {
			defer close(installerProgressChan)
			err := installer.InstallPackages(context.Background(), m.dependencies, wm, m.sudoPassword, m.reinstallItems, m.disabledItems, m.skipGentooUseFlags, installerProgressChan)
			if err != nil {
				installerProgressChan <- distros.InstallProgressMsg{
					Progress:   0.0,
					Step:       fmt.Sprintf("Installation error: %s", err.Error()),
					IsComplete: true,
					Error:      err,
				}
			}
		}()

		// Convert installer messages to TUI messages
		go func() {
			for msg := range installerProgressChan {
				// Run optional greeter setup
				if msg.Phase == distros.PhaseComplete && msg.IsComplete && msg.Error == nil {
					if m.optionalDepSelected("dms-greeter") {
						m.packageProgressChan <- packageInstallProgressMsg{
							progress:  0.92,
							step:      "Configuring DMS greeter...",
							logOutput: "Starting automated greeter setup...",
						}
						greeterLogFunc := func(line string) {
							m.packageProgressChan <- packageInstallProgressMsg{
								progress:  0.94,
								step:      "Configuring DMS greeter...",
								logOutput: line,
							}
						}
						if err := utils.RunDmsGreeterInstall(m.sudoPassword, greeterLogFunc); err != nil {
							m.packageProgressChan <- packageInstallProgressMsg{
								progress:  0.96,
								step:      "Greeter setup warning",
								logOutput: fmt.Sprintf("⚠ Greeter auto-setup warning (non-fatal): %v", err),
							}
						}

						if m.useSystemdConfig() && m.optionalDepSelected("danksearch") {
							m.packageProgressChan <- packageInstallProgressMsg{
								progress:  0.97,
								step:      "Enabling danksearch service...",
								logOutput: "Setting up dsearch.service...",
							}
							dsearchLogFunc := func(line string) {
								m.packageProgressChan <- packageInstallProgressMsg{
									progress:  0.97,
									step:      "Enabling danksearch service...",
									logOutput: line,
								}
							}
							if err := distros.SetupDsearchService(context.Background(), dsearchLogFunc); err != nil {
								m.packageProgressChan <- packageInstallProgressMsg{
									progress:  0.98,
									step:      "danksearch service warning",
									logOutput: fmt.Sprintf("danksearch service setup warning (non-fatal): %v", err),
								}
							}
						}
					}
				}
				tuiMsg := packageInstallProgressMsg{
					progress:    msg.Progress,
					step:        msg.Step,
					isComplete:  msg.IsComplete,
					needsSudo:   msg.NeedsSudo,
					commandInfo: msg.CommandInfo,
					logOutput:   msg.LogOutput,
					error:       msg.Error,
				}
				if msg.IsComplete {
					m.logChan <- fmt.Sprintf("[DEBUG] Sending completion signal: step=%s, progress=%.2f", msg.Step, msg.Progress)
				}
				m.packageProgressChan <- tuiMsg
			}
			m.logChan <- "[DEBUG] Installer channel closed"
		}()

		return packageInstallProgressMsg{
			progress:   0.05,
			step:       "Starting installation...",
			isComplete: false,
		}
	}
}
