package plugins

import (
	"path/filepath"
	"strings"

	tea "charm.land/bubbletea/v2"
	"charm.land/glamour/v2"
	"charm.land/lipgloss/v2"
	ilovetui "github.com/anotherhadi/ilovetui"
	"github.com/anotherhadi/spilltea/internal/icons"
	"github.com/anotherhadi/spilltea/internal/keys"
	"github.com/anotherhadi/spilltea/internal/util"
)

func (m Model) View() tea.View {
	if m.width == 0 || m.manager == nil {
		return tea.NewView(lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, ilovetui.S.Faint.Render(util.EmptyState(m.width, "(._.)~*.'", "no plugins loaded"))))
	}

	listH, detailH := ilovetui.SplitH(m.height, m.renderStatusBar(), 0.4)

	content := lipgloss.JoinVertical(lipgloss.Left,
		m.renderListPanel(m.width, listH),
		m.renderDetailPanel(detailH),
		m.renderStatusBar(),
	)
	return tea.NewView(content)
}

func (m *Model) renderListPanel(w, h int) string {
	panelStyle := ilovetui.S.PanelFocused
	if m.editing {
		panelStyle = ilovetui.S.Panel
	}
	var dots string
	if len(m.filtered) > 0 {
		dots = ilovetui.S.Faint.Render(m.pager.View())
	}
	inner := lipgloss.JoinVertical(lipgloss.Left,
		m.listViewport.View(),
		lipgloss.PlaceHorizontal(m.listViewport.Width(), lipgloss.Center, dots),
	)
	return ilovetui.RenderWithTitle(panelStyle, icons.I.Plugin+"Plugins", inner, w, h)
}

func (m *Model) renderDetailPanel(h int) string {
	panelStyle := ilovetui.S.Panel
	if m.editing {
		panelStyle = ilovetui.S.PanelFocused
	}
	info, ok := m.selected()
	if !ok {
		return ilovetui.RenderWithTitle(panelStyle, icons.I.Detail+"Detail", "", m.width, h)
	}

	statusSt := lipgloss.NewStyle().Foreground(ilovetui.S.Error)
	if info.Enabled {
		statusSt = lipgloss.NewStyle().Foreground(ilovetui.S.Success)
	}
	status := "disabled"
	if info.Enabled {
		status = "enabled"
	}

	pad := lipgloss.NewStyle().Padding(0, 1)

	header := pad.Render(
		ilovetui.S.Bold.Render(info.Name) + "  " + statusSt.Render(status) + "\n" +
			ilovetui.S.Faint.Render(filepath.Base(info.FilePath)),
	)

	parts := []string{header, ilovetui.ViewportView(&m.detailViewport)}

	if m.hasConfig() {
		var configLabel string
		if m.editing {
			escKey := keys.Keys.Global.Escape.Help().Key
			configLabel = pad.Render(ilovetui.S.Faint.Render("editing config (" + escKey + " to save):"))
		} else {
			editKey := keys.Keys.Plugins.EditConfig.Help().Key
			configLabel = pad.Render(ilovetui.S.Faint.Render("config (" + editKey + " to edit):"))
		}
		parts = append(parts, "", configLabel, pad.Render(m.textarea.View()))
	}

	inner := lipgloss.JoinVertical(lipgloss.Left, parts...)
	return ilovetui.RenderWithTitle(panelStyle, icons.I.Detail+"Detail", inner, m.width, h)
}

func renderPluginDescription(desc string, width int) string {
	desc = strings.TrimSpace(desc)
	lines := strings.Split(desc, "\n")
	for i, l := range lines {
		lines[i] = strings.TrimLeft(l, " \t")
	}
	desc = strings.Join(lines, "\n")

	r, err := glamour.NewTermRenderer(
		glamour.WithStyles(ilovetui.GlamourStyleConfig()),
		glamour.WithWordWrap(width),
	)
	if err != nil {
		return desc
	}
	out, err := r.Render(desc)
	if err != nil {
		return desc
	}
	return strings.Trim(out, "\n")
}

func (m *Model) renderStatusBar() string {
	pad := lipgloss.NewStyle().Padding(0, 1)
	filterKey := keys.Keys.Plugins.Filter.Help().Key
	if m.filtering {
		return pad.Render(ilovetui.S.Faint.Render(filterKey) + " " + m.filterInput.View())
	}
	if m.filter != "" {
		escKey := keys.Keys.Global.Escape.Help().Key
		accent := lipgloss.NewStyle().Foreground(ilovetui.S.Primary)
		filterLine := pad.Render(accent.Render(filterKey) + " " + ilovetui.S.Bold.Render(m.filter) + ilovetui.S.Faint.Render("  "+escKey+" to clear"))
		return lipgloss.JoinVertical(lipgloss.Left, filterLine, pad.Render(m.help.View(pluginsKeyMap{editing: m.editing, hasConfig: m.hasConfig(), width: m.width})))
	}
	return pad.Render(m.help.View(pluginsKeyMap{editing: m.editing, hasConfig: m.hasConfig(), width: m.width}))
}

func (m *Model) renderList() string {
	if len(m.filtered) == 0 {
		msg := util.EmptyState(m.listViewport.Width(), "(ง •̀_•́)ง", "no plugins", "", "spilltea --add-default-plugins")
		if m.filter != "" {
			msg = util.EmptyState(m.listViewport.Width(), "= _ =", "no results")
		}
		return lipgloss.Place(
			m.listViewport.Width(), m.listViewport.Height(),
			lipgloss.Center, lipgloss.Center,
			ilovetui.S.Faint.Render(msg),
		)
	}

	start, end := util.PageBounds(m.pager, len(m.filtered))

	var sb strings.Builder
	for i, p := range m.filtered[start:end] {
		globalIdx := start + i
		selected := globalIdx == m.cursor

		enabledSt := lipgloss.NewStyle().Foreground(ilovetui.S.Error)
		enabledStr := "off"
		if p.Enabled {
			enabledSt = lipgloss.NewStyle().Foreground(ilovetui.S.Success)
			enabledStr = "on "
		}

		w := m.listViewport.Width()
		const fixedW = 2 + 3 + 1
		nameW := w - fixedW
		if nameW < 0 {
			nameW = 0
		}

		var line string
		if selected {
			bg := lipgloss.NewStyle().Background(ilovetui.S.Selection)
			line = lipgloss.JoinHorizontal(lipgloss.Top,
				bg.Bold(true).Foreground(ilovetui.S.Primary).Width(2).Render(">"),
				enabledSt.Background(ilovetui.S.Selection).Width(3).Render(enabledStr),
				bg.Width(1).Render(""),
				bg.Bold(true).Width(nameW).Render(p.Name),
			)
		} else {
			line = lipgloss.JoinHorizontal(lipgloss.Top,
				"  ",
				enabledSt.Width(3).Render(enabledStr),
				" ",
				ilovetui.S.Bold.Render(p.Name),
			)
		}
		sb.WriteString(line + "\n")
	}
	return sb.String()
}
