// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of K9s

package view

import (
	"context"

	"github.com/derailed/k9s/internal/config"
	"github.com/derailed/k9s/internal/model"
	"github.com/derailed/k9s/internal/ui"
	"github.com/derailed/tcell/v2"
	"github.com/derailed/tview"
)

// Logger represents a generic log viewer.
type Logger struct {
	*tview.TextView

	actions        *ui.KeyActions
	app            *App
	title, subject string
	cmdBuff        *model.FishBuff
}

// NewLogger returns a logger viewer.
func NewLogger(app *App) *Logger {
	return &Logger{
		TextView: tview.NewTextView(),
		app:      app,
		actions:  ui.NewKeyActions(),
		cmdBuff:  model.NewFishBuff('/', model.FilterBuffer),
	}
}

// Init initializes the viewer.
func (l *Logger) Init(_ context.Context) error {
	if l.title != "" {
		l.SetBorder(true)
	}
	l.SetScrollable(true).SetWrap(true)
	l.SetDynamicColors(true)
	l.SetHighlightColor(tcell.ColorOrange)
	l.SetTitleColor(tcell.ColorAqua)
	l.SetInputCapture(l.keyboard)
	l.SetBorderPadding(0, 0, 1, 1)

	l.app.Styles.AddListener(l)
	l.StylesChanged(l.app.Styles)

	l.app.Prompt().SetModel(l.cmdBuff)
	l.cmdBuff.AddListener(l)

	l.bindKeys()
	l.SetInputCapture(l.keyboard)

	return nil
}

// BufferChanged indicates the buffer was changed.
func (*Logger) BufferChanged(_, _ string) {}

// BufferCompleted indicates input was accepted.
func (*Logger) BufferCompleted(_, _ string) {}

// BufferActive indicates the buff activity changed.
func (l *Logger) BufferActive(state bool, k model.BufferKind) {
	l.app.BufferActive(state, k)
}

func (l *Logger) bindKeys() {
	l.actions.Bulk(ui.KeyMap{
		tcell.KeyEscape: ui.NewKeyAction("Back", l.resetCmd, false),
		ui.KeyQ:         ui.NewKeyAction("Back", l.resetCmd, false),
		tcell.KeyCtrlS:  ui.NewKeyAction("Save", l.saveCmd, false),
		ui.KeyC:         ui.NewKeyAction("Copy", cpCmd(l.app.Flash(), l.TextView), true),
		ui.KeySlash:     ui.NewSharedKeyAction("Filter Mode", l.activateCmd, false),
		tcell.KeyDelete: ui.NewSharedKeyAction("Erase", l.eraseCmd, false),
	})
}

func (l *Logger) keyboard(evt *tcell.EventKey) *tcell.EventKey {
	if a, ok := l.actions.Get(ui.AsKey(evt)); ok {
		return a.Action(evt)
	}

	return evt
}

// StylesChanged notifies the skin changed.
func (l *Logger) StylesChanged(*config.Styles) {
	l.SetBackgroundColor(l.app.Styles.BgColor())
	l.SetTextColor(l.app.Styles.FgColor())
	l.SetBorderFocusColor(l.app.Styles.Frame().Border.FocusColor.Color())
}

// SetSubject updates the subject.
func (l *Logger) SetSubject(s string) {
	l.subject = s
}

// Actions returns menu actions.
func (l *Logger) Actions() *ui.KeyActions {
	return l.actions
}

// Name returns the component name.
func (l *Logger) Name() string { return l.title }

// Start starts the view updater.
func (*Logger) Start() {}

// Stop terminates the updater.
func (l *Logger) Stop() {
	l.app.Styles.RemoveListener(l)
}

// Hints returns menu hints.
func (l *Logger) Hints() model.MenuHints {
	return l.actions.Hints()
}

// ExtraHints returns additional hints.
func (*Logger) ExtraHints() map[string]string {
	return nil
}

func (l *Logger) activateCmd(evt *tcell.EventKey) *tcell.EventKey {
	if l.app.InCmdMode() {
		return evt
	}
	l.app.ResetPrompt(l.cmdBuff)

	return nil
}

func (l *Logger) eraseCmd(*tcell.EventKey) *tcell.EventKey {
	if !l.cmdBuff.IsActive() {
		return nil
	}
	l.cmdBuff.Delete()

	return nil
}

func (l *Logger) resetCmd(evt *tcell.EventKey) *tcell.EventKey {
	if !l.cmdBuff.InCmdMode() {
		l.cmdBuff.Reset()
		return l.app.PrevCmd(evt)
	}
	l.cmdBuff.SetActive(false)
	l.cmdBuff.Reset()

	return nil
}

func (l *Logger) saveCmd(*tcell.EventKey) *tcell.EventKey {
	if path, err := saveYAML(l.app.Config.K9s.ContextScreenDumpDir(), l.title, l.GetText(true)); err != nil {
		l.app.Flash().Err(err)
	} else {
		l.app.Flash().Infof("Log %s saved successfully!", path)
	}

	return nil
}
