Gitfed
bastien-mrq/gitfed / cmd / gitfed-install / keys.go
package main

import (
	"os"

	tea "github.com/charmbracelet/bubbletea"
)

func (m model) handleKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
	if m.step == stepDomain {
		return m.handleDomainKey(msg)
	}

	switch msg.String() {
	case "ctrl+c":
		m.cancel()
		m.quitting = true
		return m, tea.Quit
	}

	switch m.step {
	case stepWelcome:
		if msg.String() == "enter" {
			m.step = stepScan
			return m, tea.Batch(m.cmdScan(), listen(m.msgCh))
		}
		if msg.String() == "q" {
			m.quitting = true
			return m, tea.Quit
		}

	case stepScan:
		if m.scanDone && msg.String() == "enter" {
			m.step = stepDomain
			return m, tea.Batch(m.cmdDetectIP(), listen(m.msgCh))
		}

	case stepDNS:
		switch msg.String() {
		case "enter":
			if m.dns.Matches {
				m.step = stepK3s
				return m, tea.Batch(m.cmdInstallDeps(), listen(m.msgCh))
			}
		case "i":
			// proceed anyway — a certificate request that fails because
			// DNS genuinely isn't ready yet is recoverable (screen 6's
			// ingress apply just won't get a cert until it is), not a
			// reason to trap someone here if they know what they're doing.
			m.step = stepK3s
			return m, tea.Batch(m.cmdInstallDeps(), listen(m.msgCh))
		case "r":
			m.dnsChecking = true
			return m, tea.Batch(m.cmdCheckDNS(), listen(m.msgCh))
		}

	case stepK3s:
		if msg.String() == "enter" && m.k3sDone && m.certManagerDone && m.issuerDone && m.installErr == nil {
			m.step = stepBuild
			home, _ := os.UserHomeDir()
			m.workDir = home + "/.gitfed-install"
			return m, tea.Batch(m.cmdBuildImage(), listen(m.msgCh))
		}

	case stepBuild:
		if msg.String() == "enter" && m.buildDone && m.importDone && m.buildErr == nil {
			m.sourceDir = manifestPath(m.workDir, sourceDirName)
			m.deployStatus = initialDeployStatus()
			m.step = stepDeploy
			return m, tea.Batch(m.cmdDeploy(), listen(m.msgCh))
		}

	case stepDeploy:
		if msg.String() == "enter" && m.deployIdx == len(deployOrder) && m.deployErr == nil {
			m.step = stepPodStatus
			m.podPolling = true
			return m, tea.Batch(m.cmdPollPod(), listen(m.msgCh))
		}

	case stepPodStuck:
		switch msg.String() {
		case "r":
			m.step = stepBuild
			m.buildLines = nil
			m.buildDone, m.importDone, m.buildErr = false, false, nil
			return m, tea.Batch(m.cmdBuildImage(), listen(m.msgCh))
		case "q":
			m.quitting = true
			return m, tea.Quit
		}

	case stepVerify:
		if msg.String() == "enter" && m.verifyDone {
			m.step = stepAccount
			return m, listen(m.msgCh)
		}

	case stepAccount:
		switch msg.String() {
		case "enter":
			return m, launchAccountTUI()
		case "s":
			m.step = stepSuccess
			return m, listen(m.msgCh)
		}

	case stepSuccess:
		if msg.String() == "enter" || msg.String() == "q" {
			m.quitting = true
			return m, tea.Quit
		}
	}
	return m, nil
}

func (m model) handleDomainKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
	switch msg.String() {
	case "ctrl+c":
		m.cancel()
		m.quitting = true
		return m, tea.Quit
	case "tab", "shift+tab", "down", "up":
		m.focusIdx = 1 - m.focusIdx
		if m.focusIdx == 0 {
			m.domainInput.Focus()
			m.contactInput.Blur()
		} else {
			m.contactInput.Focus()
			m.domainInput.Blur()
		}
		return m, nil
	case "enter":
		if m.domainInput.Value() != "" && m.contactInput.Value() != "" {
			m.step = stepDNS
			m.dnsChecking = true
			return m, tea.Batch(m.cmdCheckDNS(), listen(m.msgCh))
		}
		return m, nil
	}

	var cmd tea.Cmd
	if m.focusIdx == 0 {
		m.domainInput, cmd = m.domainInput.Update(msg)
	} else {
		m.contactInput, cmd = m.contactInput.Update(msg)
	}
	return m, cmd
}

func initialDeployStatus() []deployFileStatus {
	labels := make([]deployFileStatus, len(deployOrder))
	for i, f := range deployOrder {
		labels[i] = deployFileStatus{Label: f}
	}
	return labels
}