// Port of web/kit/Sidebar.tsx.

package webui

import "kjol/vdom"

const sidebarNavRoot = "bg-surface rounded-default shadow-sm border border-line py-2"
const sidebarNavList = "list-none m-0 p-0"
const sidebarNavBtn = "w-full text-left py-2 pr-3 pl-4 text-sm cursor-pointer bg-transparent text-ink-soft border-0 hover:text-ink hover:bg-surface-muted"
const sidebarNavSubBtn = "w-full text-left py-1.5 pr-3 pl-8 text-xs cursor-pointer bg-transparent text-ink-muted border-0 hover:text-ink hover:bg-surface-muted"
const sidebarNavIcon = "mr-2"

const sidebarLayoutRoot = "grid grid-cols-1 gap-8 min-h-screen items-start lg:grid-cols-12"
const sidebarLayoutSidebar = "hidden lg:block lg:col-span-2 lg:self-start lg:h-full"
const sidebarLayoutSticky = "sticky top-20 max-h-[calc(100vh_-_7rem)] overflow-y-auto"
const sidebarLayoutStickyFull = "sticky top-0 h-screen overflow-y-auto"

// sidebarLayoutMain: lg:pr-8 mirrors the grid's gap-8 so the content has matching
// breathing room on the right instead of hugging the viewport edge.
const sidebarLayoutMain = "col-span-1 min-w-0 lg:col-span-10 lg:pr-8"

// SidebarNavItem is one entry in a SidebarNav. Icon is an optional leading node
// (e.g. webui.Icon(...)). Children are optional second-level items that jump to
// sub-sections within this item.
type SidebarNavItem struct {
	ID       string
	Label    string
	Icon     *vdom.VNode
	Children []SidebarNavItem
}

// SidebarNav renders a vertical nav of jump links. onItemClick receives the id
// of the clicked item (top-level or sub-item).
//
// NOTE: the TSX handler also does document.getElementById(id).scrollIntoView({
// behavior: "smooth" }) to smooth-scroll to the target section. That is
// browser-only (no document in the neutral runtime) and is dropped here; perform
// the scroll from within the app's onItemClick if needed.
func SidebarNav(items []SidebarNavItem, onItemClick func(string), class string) *vdom.VNode {
	handleClick := func(id string) {
		if onItemClick != nil {
			onItemClick(id)
		}
	}

	listMods := []vdom.Mod{vdom.Attr("class", sidebarNavList)}
	for _, item := range items {
		id := item.ID
		btnMods := []vdom.Mod{
			vdom.Attr("class", sidebarNavBtn),
			vdom.On(vdom.EVENT_CLICK, func() { handleClick(id) }),
		}
		if item.Icon != nil {
			btnMods = append(btnMods, vdom.Span(vdom.Attr("class", sidebarNavIcon), item.Icon))
		}
		btnMods = append(btnMods, vdom.Text(item.Label))

		liMods := []vdom.Mod{vdom.Button(btnMods...)}

		if len(item.Children) > 0 {
			subListMods := []vdom.Mod{vdom.Attr("class", sidebarNavList)}
			for _, sub := range item.Children {
				sid := sub.ID
				subBtnMods := []vdom.Mod{
					vdom.Attr("class", sidebarNavSubBtn),
					vdom.On(vdom.EVENT_CLICK, func() { handleClick(sid) }),
				}
				if sub.Icon != nil {
					subBtnMods = append(subBtnMods, vdom.Span(vdom.Attr("class", sidebarNavIcon), sub.Icon))
				}
				subBtnMods = append(subBtnMods, vdom.Text(sub.Label))
				subListMods = append(subListMods, vdom.Li(vdom.Button(subBtnMods...)))
			}
			liMods = append(liMods, vdom.Ul(subListMods...))
		}

		listMods = append(listMods, vdom.Li(liMods...))
	}

	return vdom.Nav(vdom.Attr("class", cx(sidebarNavRoot, class)),
		vdom.Ul(listMods...),
	)
}

// SidebarLayoutProps configures SidebarLayout. Sidebar is the aside content;
// children (variadic on SidebarLayout) are the main content.
type SidebarLayoutProps struct {
	Sidebar          *vdom.VNode
	Class            string
	FullHeight       bool
	Collapsible      bool
	OnToggleCollapse func()
}

// SidebarLayout is a two-column responsive grid: a sticky sidebar (aside) and a
// main content column. Children are the main content.
//
// NOTE: the TSX keeps an internal `collapsed` signal toggled by the collapse
// button, but nothing in its markup reads it — so collapsing has no visual
// effect there. This port renders the toggle button when Collapsible is set and
// wires OnToggleCollapse; the app owns any collapsed state/behavior.
func SidebarLayout(p SidebarLayoutProps, children ...*vdom.VNode) *vdom.VNode {
	sticky := sidebarLayoutSticky
	if p.FullHeight {
		sticky = sidebarLayoutStickyFull
	}

	asideMods := []vdom.Mod{
		vdom.Attr("class", sidebarLayoutSidebar),
		vdom.Div(kids([]vdom.Mod{vdom.Attr("class", sticky)}, []*vdom.VNode{p.Sidebar})...),
	}
	if p.Collapsible {
		btnMods := []vdom.Mod{
			vdom.Attr("type", "button"),
			vdom.Attr("aria-label", "Toggle sidebar"),
		}
		if p.OnToggleCollapse != nil {
			btnMods = append(btnMods, vdom.On(vdom.EVENT_CLICK, p.OnToggleCollapse))
		}
		asideMods = append(asideMods, vdom.Button(btnMods...))
	}

	main := vdom.Main(kids([]vdom.Mod{vdom.Attr("class", sidebarLayoutMain)}, children)...)

	return vdom.Div(vdom.Attr("class", cx(sidebarLayoutRoot, p.Class)),
		vdom.Aside(asideMods...),
		main,
	)
}
