package atree

import (
	"errors"
	"fmt"

	"gordenko.dev/dima/qb"
)

type BackwardCursor struct {
	metricType            qb.MetricType
	fracDigits            byte
	atree                 *Atree
	pageNo                uint32
	pageData              []byte
	timestampDecompressor qb.TimestampDecompressor
	valueDecompressor     qb.ValueDecompressor
}

type BackwardCursorOptions struct {
	MetricType qb.MetricType
	FracDigits byte
	PageNo     uint32
	PageData   []byte
	Atree      *Atree
}

func NewBackwardCursor(opt BackwardCursorOptions) (*BackwardCursor, error) {
	switch opt.MetricType {
	case qb.Instant, qb.Cumulative:
		// ok
	default:
		return nil, fmt.Errorf("MetricType option has wrong value: %d", opt.MetricType)
	}
	if opt.FracDigits > qb.MaxFracDigits {
		return nil, errors.New("FracDigits option is required")
	}
	if opt.Atree == nil {
		return nil, errors.New("Atree option is required")
	}
	if opt.PageNo == 0 {
		return nil, errors.New("PageNo option is required")
	}
	if len(opt.PageData) == 0 {
		return nil, errors.New("PageData option is required")
	}

	s := &BackwardCursor{
		metricType: opt.MetricType,
		fracDigits: opt.FracDigits,
		atree:      opt.Atree,
		pageNo:     opt.PageNo,
		pageData:   opt.PageData,
	}
	err := s.makeDecompressors()
	if err != nil {
		return nil, err
	}
	return s, nil
}

// timestamp, value, done, error
func (s *BackwardCursor) Prev() (uint32, float64, bool, error) {
	var (
		timestamp uint32
		value     float64
		//done      bool
		//err       error
	)

	// timestamp, done = s.timestampDecompressor.NextValue()
	// if !done {
	// 	value, done = s.valueDecompressor.NextValue()
	// 	if done {
	// 		return 0, 0, false,
	// 			fmt.Errorf("corrupted data page %d: has timestamp, no value",
	// 				s.pageNo)
	// 	}
	// 	return timestamp, value, false, nil
	// }

	// prevPageNo, _ := bin.GetUint32(s.pageData[prevPageIdx:])
	// if prevPageNo == 0 {
	// 	return 0, 0, true, nil
	// }
	// s.atree.releasePage(s.pageNo)

	// s.pageNo = prevPageNo
	// s.pageData, err = s.atree.fetchDataPage(s.pageNo)
	// if err != nil {
	// 	return 0, 0, false, fmt.Errorf("atree.fetchDataPage(%d): %s", s.pageNo, err)
	// }

	// err = s.makeDecompressors()
	// if err != nil {
	// 	return 0, 0, false, err
	// }

	// timestamp, done = s.timestampDecompressor.NextValue()
	// if done {
	// 	return 0, 0, false,
	// 		fmt.Errorf("corrupted data page %d: no timestamps",
	// 			s.pageNo)
	// }
	// value, done = s.valueDecompressor.NextValue()
	// if done {
	// 	return 0, 0, false,
	// 		fmt.Errorf("corrupted data page %d: no values",
	// 			s.pageNo)
	// }
	return timestamp, value, false, nil
}

func (s *BackwardCursor) Close() {
	s.atree.releasePage(s.pageNo)
}

// HELPER

func (s *BackwardCursor) makeDecompressors() error {
	// timestampsSize, _ := bin.GetUint16(s.pageData[timestampsSizeIdx:])
	// valuesSize, _ := bin.GetUint16(s.pageData[valuesSizeIdx:])

	// payloadSize := timestampsSize + valuesSize

	// if payloadSize > dataFooterIdx {
	// 	return fmt.Errorf("corrupted data page %d: timestamps + values size %d gt payload size",
	// 		s.pageNo, payloadSize)
	// }

	// s.timestampDecompressor = enc.NewTimeDeltaDecompressor(
	// 	s.pageData[:timestampsSize],
	// )

	// vbuf := s.pageData[timestampsSize : timestampsSize+valuesSize]

	// switch s.metricType {
	// case qb.Instant:
	// 	s.valueDecompressor = enc.NewInstantDeltaDecompressor(
	// 		vbuf, s.fracDigits)

	// case qb.Cumulative:
	// 	s.valueDecompressor = enc.NewCumulativeDeltaDecompressor(
	// 		vbuf, s.fracDigits)

	// default:
	// 	return fmt.Errorf("bug: wrong metricType %d", s.metricType)
	// }
	return nil
}

func makeDecompressors(pageData []byte, metricType qb.MetricType, fracDigits byte) (
	qb.TimestampDecompressor, qb.ValueDecompressor, error,
) {
	// timestampsSize, _ := bin.GetUint16(pageData[timestampsSizeIdx:])
	// valuesSize, _ := bin.GetUint16(pageData[valuesSizeIdx:])

	// payloadSize := timestampsSize + valuesSize

	// if payloadSize > dataFooterIdx {
	// 	return nil, nil, fmt.Errorf("corrupted: timestamps + values size %d > payload size",
	// 		payloadSize)
	// }

	// timestampDecompressor := enc.NewTimeDeltaDecompressor(
	// 	pageData[:timestampsSize],
	// )

	// vbuf := pageData[timestampsSize : timestampsSize+valuesSize]

	// var valueDecompressor qb.ValueDecompressor
	// switch metricType {
	// case qb.Instant:
	// 	valueDecompressor = enc.NewInstantDeltaDecompressor(
	// 		vbuf, fracDigits)

	// case qb.Cumulative:
	// 	valueDecompressor = enc.NewCumulativeDeltaDecompressor(
	// 		vbuf, fracDigits)

	// default:
	// 	return nil, nil, fmt.Errorf("bug: wrong metricType %d", metricType)
	// }
	//return timestampDecompressor, valueDecompressor, nil
	return nil, nil, nil
}
