package messages

import (
	"html"
	"strings"

	"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
	"github.com/diamondburned/cchat-gtk/internal/ui/service/session/server/traverse"
	"github.com/diamondburned/handy"
	"github.com/gotk3/gotk3/gtk"
	"github.com/gotk3/gotk3/pango"
)

// const BreadcrumbSlash = `<span rise="-1024" size="x-large">❭</span>`
const BreadcrumbSlash = " 〉"

const iconSize = gtk.ICON_SIZE_BUTTON

type Header struct {
	handy.HeaderBar

	ShowBackBtn *gtk.Revealer
	BackButton  *gtk.Button
	Breadcrumb  *gtk.Label
	MessageCtrl *MessageControl
	ShowMembers *gtk.ToggleButton

	breadcrumbs []string
	minicrumbs  bool
}

var backButtonCSS = primitives.PrepareClassCSS("back-button", `
	.back-button {
		margin-left: 14px;
	}
`)

var rightBreadcrumbCSS = primitives.PrepareClassCSS("right-breadcrumb", `
	.right-breadcrumb {
		margin-left: 14px;
	}
`)

func NewHeader() *Header {
	bk, _ := gtk.ButtonNewFromIconName("go-previous-symbolic", iconSize)
	bk.SetVAlign(gtk.ALIGN_CENTER)
	bk.Show()
	backButtonCSS(bk)

	rbk, _ := gtk.RevealerNew()
	rbk.Add(bk)
	rbk.SetRevealChild(false)
	rbk.SetTransitionType(gtk.REVEALER_TRANSITION_TYPE_SLIDE_LEFT)
	rbk.SetTransitionDuration(50)
	rbk.Show()

	bc, _ := gtk.LabelNew(BreadcrumbSlash)
	bc.SetUseMarkup(true)
	bc.SetXAlign(0.0)
	bc.SetEllipsize(pango.ELLIPSIZE_MIDDLE)
	bc.SetSingleLineMode(true)
	bc.SetHExpand(true)
	bc.SetMaxWidthChars(75)
	bc.Show()
	rightBreadcrumbCSS(bc)

	msgctrl := NewMessageControl()
	msgctrl.Disable()
	msgctrl.Show()

	memberIcon, _ := gtk.ImageNewFromIconName("system-users-symbolic", iconSize)
	memberIcon.Show()

	mb, _ := gtk.ToggleButtonNew()
	mb.SetVAlign(gtk.ALIGN_CENTER)
	mb.SetImage(memberIcon)
	mb.SetActive(false)
	mb.SetSensitive(false)

	header := handy.HeaderBarNew()
	header.SetShowCloseButton(true)
	header.PackStart(rbk)
	header.PackStart(bc)
	header.PackEnd(mb)
	header.PackEnd(msgctrl)
	header.Show()

	// Hack to hide the title.
	b, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
	header.SetCustomTitle(b)

	return &Header{
		HeaderBar:   *header,
		ShowBackBtn: rbk,
		BackButton:  bk,
		Breadcrumb:  bc,
		MessageCtrl: msgctrl,
		ShowMembers: mb,
	}
}

func (h *Header) Reset() {
	h.SetBreadcrumber(nil)
	h.MessageCtrl.Disable()
}

func (h *Header) OnBackPressed(fn func()) {
	h.BackButton.Connect("clicked", func(*gtk.Button) { fn() })
}

func (h *Header) OnShowMembersToggle(fn func(show bool)) {
	h.ShowMembers.Connect("toggled", func(showMembers *gtk.ToggleButton) {
		fn(showMembers.GetActive())
	})
}

func (h *Header) SetShowBackButton(show bool) {
	h.ShowBackBtn.SetRevealChild(show)
}

func (h *Header) SetCanShowMembers(canShow bool) {
	if canShow {
		h.ShowMembers.Show()
		h.ShowMembers.SetSensitive(true)
	} else {
		h.ShowMembers.Hide()
		h.ShowMembers.SetSensitive(false)
	}
}

// SetMiniBreadcrumb sets whether or not the breadcrumb should display the full
// label.
func (h *Header) SetMiniBreadcrumb(mini bool) {
	h.minicrumbs = mini
	h.updateBreadcrumb()
}

// updateBreadcrumb updates the breadcrumb label from the local state.
func (h *Header) updateBreadcrumb() {
	switch {
	case len(h.breadcrumbs) == 0:
		h.Breadcrumb.SetText("")

	case h.minicrumbs:
		h.Breadcrumb.SetMarkup(h.breadcrumbs[len(h.breadcrumbs)-1])

	default:
		h.Breadcrumb.SetMarkup(
			BreadcrumbSlash + " " + strings.Join(h.breadcrumbs, " "+BreadcrumbSlash+" "),
		)
	}
}

func (h *Header) SetBreadcrumber(b traverse.Breadcrumber) {
	if b == nil {
		h.breadcrumbs = nil
		h.updateBreadcrumb()
		return
	}

	h.breadcrumbs = traverse.TryBreadcrumb(b)
	if len(h.breadcrumbs) < 2 {
		return
	}

	// Skip the service name and username.
	h.breadcrumbs = h.breadcrumbs[2:]

	for i := range h.breadcrumbs {
		h.breadcrumbs[i] = html.EscapeString(h.breadcrumbs[i])
	}

	h.updateBreadcrumb()
}
