// package screen -- объект экрана
package screen

import (
	"fmt"

	"github.com/gdamore/tcell"

	"p78git.ddns.net/svi/libtui/alias"
	"p78git.ddns.net/svi/libtui/lib/line_cell/cell"
	"p78git.ddns.net/svi/libtui/lib/pos"

	// "p78git.ddns.net/svi/libtui/screen/win_debug"
	"p78git.ddns.net/svi/libtui/lib/size"
	"p78git.ddns.net/svi/libtui/types"
)

// Screen -- объект экрана
type Screen struct {
	app      types.IKernel
	scr      tcell.Screen // Библиотечный экран
	size     types.ISize  // Размер экрана
	posShift types.IPos   // Смещение начала координат
}

// NewScreen -- возвращаетновый экран
func NewScreen(app types.IKernel) (*Screen, error) {
	if app == nil {
		return nil, fmt.Errorf("NewScreen(): IApp==nil")
	}
	scr, err := tcell.NewScreen()
	if err != nil {
		return nil, fmt.Errorf("NewScreen(): in create tcell.Screen, err=\n\t%w", err)
	}
	sf := &Screen{
		app:      app,
		scr:      scr,
		size:     size.NewSize(),
		posShift: pos.NewPos(),
	}
	return sf, nil
}

// Run -- запускает экран в работу
func (sf *Screen) Run() error {
	defer func() {
		sf.scr.Fini()
		sf.app.CancelApp()
	}()
	if err := sf.scr.Init(); err != nil {
		return fmt.Errorf("Screen.Run(): in init tcell.Screen, err=\n\t%w", err)
	}
	sf.scr.EnableMouse()
	sf.scr.HideCursor()
	sf.setGeomShift()
	sf.Clear()
	sf.Draw() // sf.scr.Show()  // Обновить экран
	for {     // Главный цикл работы
		event := sf.scr.PollEvent() // Получить событие
		// Process event
		switch ev := event.(type) {
		case *tcell.EventResize:
			sf.scr.Sync()
			x, y := ev.Size()
			sf.size.Set(alias.SizeX(x), alias.SizeY(y))
		case *tcell.EventKey:
			if ev.Key() == tcell.KeyCtrlQ { // ev.Key() == tcell.KeyEscape
				return nil
			}
			if ev.Key() == tcell.KeyCtrlD { // Показать отладочную информацию
				// if sf.screen.WinDebug().IsVisible() { // Переключение состояния показа окна отладки
				// 	sf.screen.WinDebug().Hide()
				// } else {
				// 	sf.screen.WinDebug().Show()
				// }
			}
		case *tcell.EventMouse: // Мышка подвинулась
			x, y := ev.Position()
			sf.app.Cursor().SetPos(alias.PosX(x), alias.PosY(y))
		}
		sf.Draw()
	}
}

// setGeomShift -- устанавливает геометрическое начало координат
func (sf *Screen) setGeomShift() {
	_, sizeY := sf.scr.Size()
	// Сдвигает по вертикали координату вниз
	sf.posShift.Set(0, alias.PosY(sizeY))
}

// Size -- возвращает размер экрана
func (sf *Screen) Size() (alias.SizeX, alias.SizeY) {
	return sf.size.Get()
}

// WinDebug -- возвращает объект окна отладки экрана
// func (sf *Screen) WinDebug() types.IWinDebug {
// 	return sf.winDebug
// }

// Resize -- изменяет размер экрана
func (sf *Screen) Resize(x alias.SizeX, y alias.SizeY) {
	sf.size.Set(x, y)
}

// GetCell -- возвращает ячейку по указанному знакоместу
func (sf *Screen) GetCell(posX alias.PosX, posY alias.PosY) types.ICell {
	rune_, _, style, _ := sf.scr.GetContent(int(posX), int(posY))
	cell := cell.NewCell()
	cell.SetLit(alias.Lit(rune_))
	cell.SetStyle(alias.Style(style))
	return cell
}

// SetCell -- устанавливает ячейку на экран
func (sf *Screen) SetCell(cell types.ICell) {
	x, y := cell.Pos()
	style := cell.Style()
	lit := cell.Lit()
	sf.scr.SetCell(int(x), int(y), tcell.Style(style), rune(lit))
}

// Draw -- отрисовка экранасебя по требованию
func (sf *Screen) Draw() {
	sf.scr.Clear()
	// sf.winDebug.Draw()
	// sf.cursor.Draw()
	sf.scr.Show() // Обновить экран

}

// Clear -- очистка экрана
func (sf *Screen) Clear() {
	sf.scr.Clear() // Зачистить экран перед началом работы
}
