package choose_fonts

import (
	"fmt"
	"math"
	"sync"

	"kitty/tools/tui/loop"
	"kitty/tools/utils"
)

var _ = fmt.Print

type faces_settings struct {
	font_family, bold_font, italic_font, bold_italic_font string
}

type faces_preview_key struct {
	settings      faces_settings
	width, height int
}

type faces struct {
	handler *handler

	family              string
	settings            faces_settings
	preview_cache       map[faces_preview_key]map[string]RenderedSampleTransmit
	preview_cache_mutex sync.Mutex
}

const highlight_key_style = "fg=magenta bold"

func (self *faces) draw_screen() (err error) {
	lp := self.handler.lp
	lp.SetCursorVisible(false)
	sz, _ := lp.ScreenSize()
	styled := lp.SprintStyled
	lp.QueueWriteString(self.handler.format_title(self.family, 0))
	lines := []string{
		fmt.Sprintf("Press %s to select this font, %s to go back to the font list or any of the %s keys below to fine-tune the appearance of the individual font styles.", styled("fg=green", "Enter"), styled("fg=red", "Esc"), styled(highlight_key_style, "highlighted")), "",
	}
	_, y, str := self.handler.render_lines.InRectangle(lines, 0, 2, int(sz.WidthCells), int(sz.HeightCells), &self.handler.mouse_state, self.on_click)

	lp.QueueWriteString(str)

	num_lines_per_font := ((int(sz.HeightCells) - y - 1) / 4) - 2
	num_lines := max(1, num_lines_per_font)
	key := faces_preview_key{settings: self.settings, width: int(sz.WidthCells * sz.CellWidth), height: int(sz.CellHeight) * num_lines}
	self.preview_cache_mutex.Lock()
	defer self.preview_cache_mutex.Unlock()
	previews, found := self.preview_cache[key]
	if !found {
		self.preview_cache[key] = make(map[string]RenderedSampleTransmit)
		go func() {
			var r map[string]RenderedSampleTransmit
			s := key.settings
			self.handler.set_worker_error(kitty_font_backend.query("render_family_samples", map[string]any{
				"text_style": self.handler.text_style, "font_family": s.font_family,
				"bold_font": s.bold_font, "italic_font": s.italic_font, "bold_italic_font": s.bold_italic_font,
				"width": key.width, "height": key.height, "output_dir": self.handler.temp_dir,
			}, &r))
			self.preview_cache_mutex.Lock()
			defer self.preview_cache_mutex.Unlock()
			self.preview_cache[key] = r
			self.handler.lp.WakeupMainThread()
		}()
		return
	}
	if len(previews) < 4 {
		return
	}

	slot := 0
	d := func(setting, title string) {
		r := previews[setting]
		num_lines := int(math.Ceil(float64(r.Canvas_height) / float64(sz.CellHeight)))
		if int(sz.HeightCells)-y < num_lines+1 {
			return
		}
		lp.MoveCursorTo(1, y+1)
		_, y, str = self.handler.render_lines.InRectangle([]string{title + ": " + previews[setting].Psname}, 0, y, int(sz.WidthCells), int(sz.HeightCells), &self.handler.mouse_state, self.on_click)
		lp.QueueWriteString(str)
		if y+num_lines < int(sz.HeightCells) {
			lp.MoveCursorTo(1, y+1)
			self.handler.graphics_manager.display_image(slot, r.Path, r.Canvas_width, r.Canvas_height)
			slot++
			y += num_lines + 1
		}
	}
	d(`font_family`, styled(highlight_key_style, "R")+`egular`)
	d(`bold_font`, styled(highlight_key_style, "B")+`old`)
	d(`italic_font`, styled(highlight_key_style, "I")+`talic`)
	d(`bold_italic_font`, "B"+styled(highlight_key_style, "o")+`ld-Italic`)

	return
}

func (self *faces) initialize(h *handler) (err error) {
	self.handler = h
	self.preview_cache = make(map[faces_preview_key]map[string]RenderedSampleTransmit)
	return
}

func (self *faces) on_wakeup() error {
	return self.handler.draw_screen()
}

func (self *faces) on_click(id string) (err error) {
	return
}

func (self *faces) on_key_event(event *loop.KeyEvent) (err error) {
	if event.MatchesPressOrRepeat("esc") {
		event.Handled = true
		self.handler.current_pane = &self.handler.listing
		return self.handler.draw_screen()
	}
	if event.MatchesPressOrRepeat("enter") {
		event.Handled = true
		return self.handler.final_pane.on_enter(self.family, self.settings)
	}
	return
}

func (self *faces) on_text(text string, from_key_event bool, in_bracketed_paste bool) (err error) {
	if from_key_event {
		which := ""
		switch text {
		case "r", "R":
			which = "font_family"
		case "b", "B":
			which = "bold_font"
		case "i", "I":
			which = "italic_font"
		case "o", "O":
			which = "bold_italic_font"
		}
		if which != "" {
			return self.handler.face_pane.on_enter(self.family, which, self.settings)
		}
	}
	return
}

func (self *faces) on_enter(family string) error {
	if family != "" {
		self.family = family
		r := self.handler.listing.resolved_faces_from_kitty_conf
		d := func(conf ResolvedFace, setting *string, defval string) {
			s := utils.IfElse(conf.Setting == "auto", "auto", conf.Spec)
			*setting = utils.IfElse(family == conf.Family, s, defval)
		}
		d(r.Font_family, &self.settings.font_family, fmt.Sprintf(`family="%s"`, family))
		d(r.Bold_font, &self.settings.bold_font, "auto")
		d(r.Italic_font, &self.settings.italic_font, "auto")
		d(r.Bold_italic_font, &self.settings.bold_italic_font, "auto")
	}
	self.handler.current_pane = self
	return self.handler.draw_screen()
}
