package main

import (
	"image/color"
	"log"
	"time"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/canvas"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/storage"
	"fyne.io/fyne/v2/widget"
)

type FlashKind int

const (
	FlashError FlashKind = iota
	FlashSuccess
)

var (
	presFileFilter  []string = []string{".pptx", ".odp"}
	videoFileFilter []string = []string{".mp4", ".mkv", ".mov", ".webm"}

	flashTimers = map[*widget.Button]*time.Timer{}
)

func flashColor(btn *widget.Button, kind FlashKind) {
	if t, ok := flashTimers[btn]; ok {
		t.Stop() // cancel previous flash
	}

	duration := 1 * time.Second // default flash duration
	// Determine button style based on kind
	var importance widget.Importance
	switch kind {
	case FlashError:
		importance = widget.DangerImportance
	case FlashSuccess:
		importance = widget.SuccessImportance
		duration = 3 * time.Second
	}

	// Apply the flash immediately on UI thread
	fyne.CurrentApp().Driver().DoFromGoroutine(func() {
		btn.Importance = importance
		btn.Refresh()
	}, false)

	// Schedule reset after duration (non-blocking)
	flashTimers[btn] = time.AfterFunc(duration, func() {
		fyne.CurrentApp().Driver().DoFromGoroutine(func() {
			btn.Importance = widget.LowImportance
			btn.Refresh()
		}, false)
	})
}

func drawSeparator(preNewLine, postNewLine bool) *fyne.Container {
	emptyLabel := widget.NewLabel("") // Give it some space at the bottom with an empty line
	separatorLine := canvas.NewLine(color.Gray{Y: 128})

	var items []fyne.CanvasObject
	if preNewLine {
		items = append(items, emptyLabel)
	}

	items = append(items, separatorLine)

	if postNewLine {
		items = append(items, emptyLabel)
	}

	separContainer := container.NewVBox(items...)
	return separContainer
}

func drawModeRow(targetMode *int) *fyne.Container {
	actionText := widget.NewLabel("Select Mode")
	// targetMode is defined as:
	// 0 undefined / not used
	// 1 presentation (PowerPoint, Impress)
	// 2 video (mp4, mkv)
	var presModeBtn *widget.Button
	var videoModeBtn *widget.Button
	presModeBtn = widget.NewButton("Presentation", func() {
		*targetMode = 1
		presModeBtn.Importance = widget.HighImportance
		videoModeBtn.Importance = widget.LowImportance
		log.Println("Set mode to presentation", *targetMode)
		refreshButtons(presModeBtn, videoModeBtn)
	})
	presWide := container.NewGridWrap(
		dButtonSize,
		presModeBtn,
	)

	videoModeBtn = widget.NewButton("Video", func() {
		*targetMode = 2
		presModeBtn.Importance = widget.LowImportance
		videoModeBtn.Importance = widget.HighImportance
		log.Println("Set mode to video", *targetMode)
		refreshButtons(presModeBtn, videoModeBtn)
	})
	videoWide := container.NewGridWrap(
		dButtonSize,
		videoModeBtn,
	)

	modeRow := container.NewHBox(
		presWide,
		videoWide,
	)

	modeCol := container.NewVBox(
		actionText,
		modeRow,
	)

	return modeCol
}

func drawTargetSection(raspiNames []string, raspiTarget *string, uploadBtn, reloadBtn *widget.Button, cfg RaspiConfig) *fyne.Container {
	actionText := widget.NewLabel("Select Target")

	var previousTarget string
	var verifyBtn *widget.Button

	// Left side for selection of target
	piSelection := widget.NewRadioGroup(raspiNames, func(selected string) {
		if selected == previousTarget {
			return // nothing changed
		}
		previousTarget = selected
		*raspiTarget = selected

		refreshButtons(verifyBtn, uploadBtn, reloadBtn)
	})

	selecCol := container.NewVBox(
		actionText,
		piSelection,
	)

	var credOK bool
	verifyBtn = widget.NewButton("Check Connection", func() {
		verifyBtn.Importance = widget.HighImportance
		refreshButtons(verifyBtn)

		log.Println("Verifying credentials...")
		uploadBtn.Disable()
		reloadBtn.Disable()
		refreshButtons(verifyBtn, uploadBtn, reloadBtn)

		go func() {
			credOK = verifyCred(*raspiTarget, cfg)

			if credOK {
				// Must update UI on main thread
				fyne.CurrentApp().Driver().DoFromGoroutine(func() {
					flashColor(verifyBtn, FlashSuccess) // flashcolor should handle RunOnMain internally
					uploadBtn.Enable()
					reloadBtn.Enable()
				}, false)

			} else {
				flashColor(verifyBtn, FlashError) // flashcolor should handle RunOnMain internally
			}
		}()
	})
	verifyWide := container.NewGridWrap(
		buttonSize,
		verifyBtn,
	)

	wholeCol := container.NewVBox(
		selecCol,
		widget.NewLabel(""),
		verifyWide,
	)

	return wholeCol
}

func drawFileSelection(localPath *string, targetMode *int, parentWindow fyne.Window) *fyne.Container {
	actionText := widget.NewLabel("Select File")
	pathLabel := widget.NewLabel("No File Selected Yet...")

	var uploadBtn *widget.Button
	uploadBtn = widget.NewButton("Click to Select File", func() {
		// Stupid dialog error on 'headless' servers...
		log.Println("Ignore the next error. ~Refer: https://github.com/fyne-io/fyne/issues/4110")

		// Use NewFileOpen to get the dialog object
		uploadSelecDiag := dialog.NewFileOpen(func(r fyne.URIReadCloser, err error) {
			if r != nil {
				defer r.Close()

				pathLabel.SetText(r.URI().Name())
				*localPath = r.URI().Path()

				uploadBtn.Importance = widget.HighImportance
				refreshButtons(uploadBtn)
				log.Println("Local path of selected file:", *localPath)
			}
		}, parentWindow)

		var fileFilter storage.FileFilter
		switch *targetMode {
		case 1:
			fileFilter = storage.NewExtensionFileFilter(presFileFilter)
		case 2:
			fileFilter = storage.NewExtensionFileFilter(videoFileFilter)
		}

		uploadSelecDiag.SetFilter(fileFilter)

		// Resize the dialog to the whole window, if it wants to do that -
		uploadSelecDiag.Resize(windowSize)
		uploadSelecDiag.Show()
	})
	uploadWide := container.NewGridWrap(
		buttonSize,
		uploadBtn,
	)

	fileSelecRow := container.NewHBox(
		uploadWide,
		pathLabel,
	)

	fileSelecCol := container.NewVBox(
		actionText,
		fileSelecRow,
	)

	return fileSelecCol
}

// targetMode *int
func drawFooter(app fyne.App, raspiTarget, localUploadPath *string, targetMode *int, cfg RaspiConfig) (*fyne.Container, *widget.Button, *widget.Button) {
	remotePresPath := "/opt/raspscreen/media/media"

	// Configuration of the bottom of the application
	var uploadBtn *widget.Button
	uploadBtn = widget.NewButton("Upload File", func() {
		uploadBtn.Importance = widget.HighImportance
		refreshButtons(uploadBtn)

		go func() {
			ok := sftpUploadFile(*raspiTarget, *localUploadPath, remotePresPath, cfg)

			if ok {
				flashColor(uploadBtn, FlashSuccess)
			} else {
				flashColor(uploadBtn, FlashError)
			}
		}()
	})
	uploadWide := container.NewGridWrap(
		dButtonSize,
		uploadBtn,
	)

	var reloadBtn *widget.Button
	reloadBtn = widget.NewButton("Restart Program", func() {
		reloadBtn.Importance = widget.HighImportance
		refreshButtons(uploadBtn)

		go func() {
			ok := restartShow(*raspiTarget, *targetMode, cfg)

			if ok {
				flashColor(reloadBtn, FlashSuccess)
			} else {
				flashColor(reloadBtn, FlashError)
			}
		}()
	})
	reloadWide := container.NewGridWrap(
		dButtonSize,
		reloadBtn,
	)

	cancelBtn := widget.NewButton("Exit", func() {
		log.Println("Quitting")
		app.Quit()
	})
	cancelWide := container.NewGridWrap(
		dButtonSize,
		cancelBtn,
	)

	bottom := container.NewHBox(
		uploadWide,         // left
		reloadWide,         // also next to the one above
		layout.NewSpacer(), // flexible space
		cancelWide,         // right
	)

	uploadBtn.Disable()
	reloadBtn.Disable()
	return bottom, uploadBtn, reloadBtn
}
