package main

import (
	"fmt"
	"strings"

	tea "github.com/charmbracelet/bubbletea"
)

type editorTab int

const (
	tabCommands editorTab = iota
	tabFilesystem
	tabNetwork
	tabEnv
)

var editorTabNames = []string{"Commands", "Filesystem", "Network", "Environment"}

type EditorModel struct {
	subTab   editorTab
	cmdLists [2]EditableList
	fsLists  [4]EditableList
	netList  EditableList
	envLists [2]EditableList
	netBlock bool
	listIdx  int
	width    int
}

func NewEditorModel(p *Profile) EditorModel {
	m := EditorModel{subTab: tabCommands}
	if p != nil {
		m.cmdLists[0] = NewEditableList("Allow", p.Commands.Allow)
		m.cmdLists[1] = NewEditableList("Deny", p.Commands.Deny)
		m.fsLists[0] = NewEditableList("Allow", p.FS.Allow)
		m.fsLists[1] = NewEditableList("Read", p.FS.Read)
		m.fsLists[2] = NewEditableList("Write", p.FS.Write)
		m.fsLists[3] = NewEditableList("Deny", p.FS.Deny)
		m.netList = NewEditableList("Allow Domains", p.Network.AllowDomain)
		m.envLists[0] = NewEditableList("Set Vars (key=value)", keyValueStrings(p.Env.SetVars))
		m.envLists[1] = NewEditableList("Deny Vars", p.Env.DenyVars)
		m.netBlock = p.Network.Block
	}
	return m
}

func (m EditorModel) listCount() int {
	switch m.subTab {
	case tabCommands:
		return 2
	case tabFilesystem:
		return 4
	case tabNetwork:
		return 1
	case tabEnv:
		return 2
	}
	return 0
}

func (m EditorModel) currentList() EditableList {
	switch m.subTab {
	case tabCommands:
		return m.cmdLists[m.listIdx]
	case tabFilesystem:
		return m.fsLists[m.listIdx]
	case tabNetwork:
		return m.netList
	case tabEnv:
		return m.envLists[m.listIdx]
	}
	return EditableList{}
}

func (m EditorModel) withList(idx int, l EditableList) EditorModel {
	switch m.subTab {
	case tabCommands:
		m.cmdLists[idx] = l
	case tabFilesystem:
		m.fsLists[idx] = l
	case tabNetwork:
		m.netList = l
	case tabEnv:
		m.envLists[idx] = l
	}
	return m
}

func (m EditorModel) listTitles() []string {
	switch m.subTab {
	case tabCommands:
		return []string{"Allow", "Deny"}
	case tabFilesystem:
		return []string{"Allow", "Read", "Write", "Deny"}
	case tabNetwork:
		return []string{"Allow Domains"}
	case tabEnv:
		return []string{"Set Vars", "Deny Vars"}
	}
	return nil
}

func (m EditorModel) Update(msg tea.Msg) (EditorModel, tea.Cmd) {
	current := m.currentList()
	if current.IsEditing() {
		updated, cmd := current.Update(msg)
		m = m.withList(m.listIdx, updated)
		return m, cmd
	}

	switch msg := msg.(type) {
	case tea.KeyMsg:
		switch msg.String() {
		case "1":
			m.subTab = tabCommands
			m.listIdx = 0
			return m, nil
		case "2":
			m.subTab = tabFilesystem
			m.listIdx = 0
			return m, nil
		case "3":
			m.subTab = tabNetwork
			m.listIdx = 0
			return m, nil
		case "4":
			m.subTab = tabEnv
			m.listIdx = 0
			return m, nil
		case "left":
			if m.listIdx > 0 {
				m.listIdx--
			}
			return m, nil
		case "right":
			if m.listIdx < m.listCount()-1 {
				m.listIdx++
			}
			return m, nil
		case "b":
			if m.subTab == tabNetwork {
				m.netBlock = !m.netBlock
				return m, nil
			}
		default:
			updated, cmd := current.Update(msg)
			m = m.withList(m.listIdx, updated)
			return m, cmd
		}
	}
	return m, nil
}

func (m EditorModel) View() string {
	var b strings.Builder

	b.WriteString("  ")
	for i, name := range editorTabNames {
		num := fmt.Sprintf("%d", i+1)
		if editorTab(i) == m.subTab {
			b.WriteString(activeTabStyle.Render(num + " " + name))
		} else {
			b.WriteString(tabStyle.Render(num + " " + name))
		}
		b.WriteString(" ")
	}
	b.WriteString("\n\n")

	current := m.currentList()
	titles := m.listTitles()
	if len(titles) > 1 {
		list := current
		list.title = fmt.Sprintf("%s (%d/%d)", titles[m.listIdx], m.listIdx+1, m.listCount())
		b.WriteString(list.View())
	} else {
		b.WriteString(current.View())
	}

	if m.subTab == tabNetwork {
		blockStr := "no"
		if m.netBlock {
			blockStr = "yes"
		}
		b.WriteString("\n\n  Block: " + blockStr + "  (b to toggle)")
	}

	b.WriteString("\n\n" + helpStyle.Render("  1-4:sub-tab  <-/->:switch list  a:add  x:remove  enter:edit  s:save  Tab:dashboard"))

	return b.String()
}

func (m EditorModel) SyncToProfile(p *Profile) {
	p.Commands.Allow = m.cmdLists[0].Items()
	p.Commands.Deny = m.cmdLists[1].Items()
	p.FS.Allow = m.fsLists[0].Items()
	p.FS.Read = m.fsLists[1].Items()
	p.FS.Write = m.fsLists[2].Items()
	p.FS.Deny = m.fsLists[3].Items()
	p.Network.AllowDomain = m.netList.Items()
	p.Network.Block = m.netBlock
	p.Env.SetVars = parseKeyValueStrings(m.envLists[0].Items())
	p.Env.DenyVars = m.envLists[1].Items()
}

func keyValueStrings(m map[string]string) []string {
	var result []string
	for k, v := range m {
		result = append(result, k+"="+v)
	}
	return result
}

func parseKeyValueStrings(items []string) map[string]string {
	result := make(map[string]string)
	for _, item := range items {
		parts := strings.SplitN(item, "=", 2)
		if len(parts) == 2 {
			result[parts[0]] = parts[1]
		}
	}
	return result
}
