package multisyswebcam

import (
	"image"
	"image/color"
	"time"
	"math/rand"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/canvas"
	"fyne.io/fyne/v2/widget"
	"gocv.io/x/gocv"
)

var _ fyne.WidgetRenderer = (*multisysMultisysWebcamRenderer)(nil)

type WebcamSystem int64

const (
	WebcamSystemDisabled WebcamSystem = iota
	WebcamSystemGoCV
	WebcamSystemWinAviCapDll
)


type MultisysWebcam struct {
	widget.BaseWidget

	System WebcamSystem

	MultisysWebcamID int64
	UpdateFPS    int64
	fpsTimer     *time.Ticker

}

func NewMultisysWebcam() *MultisysWebcam {
	w := &MultisysWebcam{}
	w.ExtendBaseWidget(w)
	w.MultisysWebcamID = 0
	w.UpdateFPS = 25
	w.System = WebcamSystemDisabled

	return w
}

func (w *MultisysWebcam) Resize(s fyne.Size) {
	w.BaseWidget.Resize(s)
}

func (w *MultisysWebcam) CreateRenderer() fyne.WidgetRenderer {
	fpsTimer := time.NewTicker(time.Duration(1000/25) * time.Millisecond)
	go func(w *MultisysWebcam) {
		for {
			_ = <-fpsTimer.C
			if w != nil {
				w.Refresh()
			}
		}
	}(w)
	return newMultisysWebcamRenderer(w)
}

func staticNoiseImage(w, h int) *image.RGBA {
	i := image.NewRGBA(image.Rect(0, 0, w, h))
	for x := 0; x < w; x++ {
		for y := 0; y < h; y++ {
			lum := uint8(rand.Float32() * 255)
			i.Set(x, y, color.RGBA{lum, lum, lum, 255})
		}
	}
	return i
}

func (w *MultisysWebcam) actualrenderframe(width, height int) image.Image {
	switch w.System {
	case WebcamSystemDisabled:
		return staticNoiseImage(width,height)
	case WebcamSystemGoCV:
		gocvWebcam, _ := gocv.VideoCaptureDevice(int(w.MultisysWebcamID))
		img := gocv.NewMat()
		gocvWebcam.Read(&img)
		frameImage, err := img.ToImage()
		if err != nil {
			frameImage = image.NewRGBA(image.Rect(0, 0, width, height))
		}
		return frameImage
	}
	return image.NewRGBA(image.Rect(0, 0, width, height))
}

func newMultisysWebcamRenderer(w *MultisysWebcam) *multisysMultisysWebcamRenderer {
	renderer := &multisysMultisysWebcamRenderer{
		multisysMultisysWebcam: w,
		background:     canvas.NewRectangle(color.RGBA{255, 0, 255, 255}),
	}
	renderer.currentframe = canvas.NewRaster(w.actualrenderframe)
	return renderer
}

type multisysMultisysWebcamRenderer struct {
	multisysMultisysWebcam   *MultisysWebcam
	background       *canvas.Rectangle
	currentframe     *canvas.Raster
	goCVVideoCapture *gocv.VideoCapture
}

func (r *multisysMultisysWebcamRenderer) Objects() []fyne.CanvasObject {
	// The order is critical, rect is drawn first then currentframe
	return []fyne.CanvasObject{r.background, r.currentframe}
}

func (r *multisysMultisysWebcamRenderer) Layout(s fyne.Size) {
	r.background.Resize(s)
	r.currentframe.Resize(s)
}

func (r *multisysMultisysWebcamRenderer) MinSize() fyne.Size {
	return fyne.NewSize(200, 200)
}

func (r *multisysMultisysWebcamRenderer) Refresh() {
	if r != nil {
		if r.currentframe != nil {
			r.currentframe.Refresh()
		}
	}
}

func (r *multisysMultisysWebcamRenderer) Destroy() {
	if r.multisysMultisysWebcam != nil {
		if r.multisysMultisysWebcam.fpsTimer != nil {
			r.multisysMultisysWebcam.fpsTimer.Stop()
		}
	}
} // Called when the renderer is destroyed
