package producer

import (
	"image"
	"math"

	log "github.com/sirupsen/logrus"
	"gocv.io/x/gocv"
)

type PhaseShiftM struct {
	dx       float32
	dy       float32
	response float64
	Block    Block
}

type Block struct {
	width  int
	height int
	coord  image.Point // top-left corner of the block in the original image
}

func (r *Registrator) calculateBlockPhaseShift(panBlock, mssBlock gocv.Mat) (gocv.Point2f, float64) {
	pan := gocv.NewMat()
	mss := gocv.NewMat()

	panBlock.ConvertTo(&pan, gocv.MatTypeCV32FC1)
	defer pan.Close()
	mssBlock.ConvertTo(&mss, gocv.MatTypeCV32FC1)
	defer mss.Close()

	hann := gocv.NewMat()
	defer hann.Close()

	shift, response := gocv.PhaseCorrelate(pan, mss, hann)

	dx := shift.X
	dy := shift.Y
	log.Debugf("Block shift: dx = %f, dy = %f. response = %f", dx, dy, response)

	return shift, response
}

func (r *Registrator) DoMssPhaseShift() error {
	// 使用平均偏移量来做平移变换
	for band := 0; band < MssBands; band++ {
		var efficientShiftM int
		var xTotal, yTotal float32
		for _, shift := range r.phaseShifts[band] {
			if math.IsNaN(float64(shift.dx)) || math.IsNaN(float64(shift.dy)) {
				continue
			}
			efficientShiftM += 1
			xTotal += shift.dx
			yTotal += shift.dy
		}
		dx := xTotal / float32(efficientShiftM)
		dy := yTotal / float32(efficientShiftM)
		log.Println("Band", band+1, "average shift:", dx, dy, "efficientShiftM:", efficientShiftM)

		translationMat := gocv.NewMatWithSize(2, 3, gocv.MatTypeCV32F)
		defer translationMat.Close()

		translationMat.SetFloatAt(0, 0, 1)
		translationMat.SetFloatAt(0, 1, 0)
		translationMat.SetFloatAt(0, 2, dx)
		translationMat.SetFloatAt(1, 0, 0)
		translationMat.SetFloatAt(1, 1, 1)
		translationMat.SetFloatAt(1, 2, dy)

		alignedMss := gocv.NewMatWithSize(r.MssHeight, r.MssWidth, gocv.MatTypeCV32FC1)
		defer alignedMss.Close()

		cvtMss := gocv.NewMat()
		defer cvtMss.Close()

		r.MssImages[band].ConvertTo(&cvtMss, gocv.MatTypeCV32FC1)
		// 手动平移像素
		outY := math.MaxInt
		for y := 0; y < r.MssHeight; y++ {
			for x := 0; x < r.MssWidth; x++ {
				// 计算新的坐标
				newX := x + int(dx)
				newY := y + int(dy)

				// 如果新坐标在图像范围内，进行像素值赋值
				if newX >= 0 && newX < r.MssWidth && newY >= 0 && newY < r.MssHeight {
					alignedMss.SetFloatAt(y, x, cvtMss.GetFloatAt(newY, newX))
				} else {
					// 如果新坐标不在图像范围内，设置为黑色
					alignedMss.SetFloatAt(y, x, 0)
					if outY > y {
						outY = y
						log.Println("Warning: pixel out of range", x, y)
					}
				}
			}
		}

		// gocv.WarpAffine(cvtMss, &alignedMss, translationMat, image.Pt(cvtMss.Size()[1], cvtMss.Size()[0]))
		r.registeredMssImages[band] = gocv.NewMat()
		alignedMss.ConvertTo(&r.registeredMssImages[band], gocv.MatTypeCV16U)

		log.Println("Band", band+1, "registeredMssImages size:", r.registeredMssImages[band].Size())
	}

	return nil
}
