package webui

import "kjol/wasmruntime/vdom"

// Port of web/kit/Buttons.tsx.

const (
	ButtonNeutral      = "neutral"
	ButtonWhite        = "white"
	ButtonLightNeutral = "light-neutral"
	ButtonBlue         = "blue"
	ButtonDarkBlue     = "dark-blue"
	ButtonGreen        = "green"
	ButtonDarkGreen    = "dark-green"
	ButtonRed          = "red"
	ButtonDarkRed      = "dark-red"
	ButtonYellow       = "yellow"
	ButtonOrange       = "orange"
	ButtonPrimary      = "primary"
	ButtonSecondary    = "secondary"
	ButtonGhost        = "ghost"
)

const btnBase = "inline-flex items-center justify-center gap-2 cursor-pointer text-sm font-normal rounded-default transition disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-current focus-visible:outline-offset-2"

var btnColors = map[string]string{
	"neutral":       "shadow-xs bg-neutral-700 text-white hover:bg-neutral-800",
	"white":         "shadow-xs bg-surface text-ink border border-line-strong hover:bg-surface-muted",
	"light-neutral": "shadow-xs bg-surface-muted text-ink border border-line-strong hover:bg-surface-raised",
	"blue":          "shadow-xs bg-sky-700 text-white hover:bg-sky-800",
	"dark-blue":     "shadow-xs bg-sky-900 text-white hover:bg-sky-950",
	"green":         "shadow-xs bg-green-700 text-white hover:bg-green-800",
	"dark-green":    "shadow-xs bg-green-900 text-white hover:bg-green-950",
	"red":           "shadow-xs bg-red-700 text-white hover:bg-red-800",
	"dark-red":      "shadow-xs bg-red-900 text-white hover:bg-red-950",
	"yellow":        "shadow-xs bg-yellow-700 text-white hover:bg-yellow-800",
	"orange":        "shadow-xs bg-orange-600 text-white hover:bg-orange-700",
	"primary":       "shadow-xs bg-primary text-white hover:bg-primary-hover",
	"secondary":     "shadow-none bg-surface-raised text-ink-soft border border-line-strong hover:bg-surface-strong",
	"ghost":         "shadow-none bg-transparent text-ink-soft border-none hover:bg-surface-raised",
}

var btnOutlineColors = map[string]string{
	"neutral":       "text-ink-soft",
	"white":         "text-ink-faint",
	"light-neutral": "text-ink-faint",
	"blue":          "text-sky-700 dark:text-sky-400",
	"dark-blue":     "text-sky-900",
	"green":         "text-green-700 dark:text-green-400",
	"dark-green":    "text-green-900",
	"red":           "text-red-700",
	"dark-red":      "text-red-900",
	"yellow":        "text-yellow-700",
	"orange":        "text-orange-600",
	"primary":       "text-accent",
}

const btnOutlineBase = "bg-transparent shadow-[inset_0_0_0_1px_currentColor] hover:shadow-[inset_0_0_0_2px_currentColor]"

// ButtonProps configures Button. Icon is an icon name (see webui.Icon); Text is
// the label. If neither Text nor children are given the button is icon-only.
type ButtonProps struct {
	Color    string
	Outline  bool
	Small    bool
	Icon     string
	Text     string
	Type     string
	Disabled bool
	Title    string
	Class    string
	OnClick  func()
}

func buttonClass(p ButtonProps) string {
	c := btnBase
	if p.Outline {
		oc := btnOutlineColors[p.Color]
		if oc == "" {
			oc = btnOutlineColors["neutral"]
		}
		c = cx(c, btnOutlineBase, oc)
	} else {
		cc := btnColors[p.Color]
		if cc == "" {
			cc = btnColors["neutral"]
		}
		c = cx(c, cc)
	}
	hasText := p.Text != ""
	switch {
	case p.Small && p.Icon != "":
		c = cx(c, "py-1 px-3")
	case p.Small:
		c = cx(c, "py-1 px-4")
	case p.Icon != "" && !hasText:
		c = cx(c, "py-2 px-3")
	case p.Icon != "":
		c = cx(c, "py-2 px-5")
	default:
		c = cx(c, "py-2 px-8")
	}
	return cx(c, p.Class)
}

// Button renders a styled <button>. Extra children render after any Icon/Text.
func Button(p ButtonProps, children ...*vdom.VNode) *vdom.VNode {
	mods := []vdom.Mod{
		vdom.Attr("type", pick(p.Type, "button")),
		vdom.Attr("class", buttonClass(p)),
	}
	if p.Disabled {
		mods = append(mods, vdom.Attr("disabled", "disabled"))
	}
	if p.Title != "" {
		mods = append(mods, vdom.Attr("title", p.Title))
	}
	if p.OnClick != nil {
		mods = append(mods, vdom.On(vdom.EVENT_CLICK, p.OnClick))
	}
	if p.Icon != "" {
		mods = append(mods, Icon(p.Icon, iconSize(p.Small), ""))
	}
	if p.Text != "" {
		mods = append(mods, vdom.Text(p.Text))
	}
	mods = kids(mods, children)
	return vdom.Button(mods...)
}

func iconSize(small bool) int {
	if small {
		return 14
	}
	return 16
}

// ButtonLink is a text-styled link button (blue).
func ButtonLink(onClick func(), children ...*vdom.VNode) *vdom.VNode {
	mods := []vdom.Mod{
		vdom.Attr("type", "button"),
		vdom.Attr("class", "cursor-pointer bg-transparent border-none p-0 font-[inherit] text-sky-700 dark:text-sky-400 hover:underline"),
	}
	if onClick != nil {
		mods = append(mods, vdom.On(vdom.EVENT_CLICK, onClick))
	}
	return vdom.Button(kids(mods, children)...)
}

// ButtonLinkRed is the red variant of ButtonLink.
func ButtonLinkRed(onClick func(), children ...*vdom.VNode) *vdom.VNode {
	mods := []vdom.Mod{
		vdom.Attr("type", "button"),
		vdom.Attr("class", "cursor-pointer bg-transparent border-none p-0 font-[inherit] text-red-600 dark:text-red-400 hover:underline"),
	}
	if onClick != nil {
		mods = append(mods, vdom.On(vdom.EVENT_CLICK, onClick))
	}
	return vdom.Button(kids(mods, children)...)
}

// SegmentedButtonOption is one option in a SegmentedButtons group.
type SegmentedButtonOption struct {
	Value string
	Label string
	Icon  string
}

// SegmentedButtons renders a pill group of mutually-exclusive options; `value`
// is the selected option's value, `onChange` receives the clicked value.
func SegmentedButtons(options []SegmentedButtonOption, value string, onChange func(string), small bool, class string) *vdom.VNode {
	sizeCls := "py-1 px-3 text-sm"
	if small {
		sizeCls = "py-0.5 px-2 text-ss"
	}
	const baseCls = "inline-flex items-center justify-center gap-1.5 flex-1 cursor-pointer font-medium transition-colors whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed"
	const activeCls = "bg-surface text-text-heading shadow-sm"
	const inactiveCls = "text-ink-muted hover:text-ink-soft"

	mods := []vdom.Mod{vdom.Attr("class", cx("flex items-center gap-0.5 rounded-md bg-surface-raised p-0.5", class))}
	for _, opt := range options {
		state := inactiveCls
		if opt.Value == value {
			state = activeCls
		}
		v := opt.Value
		btnMods := []vdom.Mod{
			vdom.Attr("type", "button"),
			vdom.Attr("class", cx(baseCls, "rounded-default", sizeCls, state)),
			vdom.Attr("title", opt.Label),
			vdom.On(vdom.EVENT_CLICK, func() { onChange(v) }),
		}
		if opt.Icon != "" {
			btnMods = append(btnMods, Icon(opt.Icon, 12, ""))
		}
		btnMods = append(btnMods, vdom.Span(vdom.Text(opt.Label)))
		mods = append(mods, vdom.Button(btnMods...))
	}
	return vdom.Div(mods...)
}

// BackLink is an inline chevron-left anchor. onDark switches to on-dark colors.
func BackLink(href, text string, onDark bool) *vdom.VNode {
	color := "text-ink-soft hover:text-ink"
	if onDark {
		color = "text-text-on-dark-muted hover:text-text-on-dark"
	}
	return vdom.A(vdom.Attr("href", href),
		vdom.Attr("class", cx("inline-flex items-center gap-1 text-sm no-underline", color)),
		Icon("chevron-left", 16, ""),
		vdom.Text(text),
	)
}
