package atree

import (
	"fmt"

	diploma "gordenko.dev/dima/qb"
)

type ContinueFullScanReq struct {
	FracDigits     byte
	ResponseWriter AtreeMeasureConsumer
	LastPageNo     uint32
}

func (s *Atree) ContinueFullScan(req ContinueFullScanReq) error {
	buf, err := s.fetchDataPage(req.LastPageNo)
	if err != nil {
		return fmt.Errorf("fetchDataPage(%d): %s", req.LastPageNo, err)
	}

	treeCursor, err := NewBackwardCursor(BackwardCursorOptions{
		PageNo:     req.LastPageNo,
		PageData:   buf,
		Atree:      s,
		FracDigits: req.FracDigits,
		MetricType: diploma.Instant,
	})
	if err != nil {
		return err
	}
	defer treeCursor.Close()

	for {
		timestamp, value, done, err := treeCursor.Prev()
		if err != nil {
			return err
		}
		if done {
			return nil
		}
		req.ResponseWriter.Feed(timestamp, value)
	}
}

type ContinueRangeScanReq struct {
	FracDigits     byte
	ResponseWriter AtreeMeasureConsumer
	LastPageNo     uint32
	Since          uint32
}

func (s *Atree) ContinueRangeScan(req ContinueRangeScanReq) error {
	buf, err := s.fetchDataPage(req.LastPageNo)
	if err != nil {
		return fmt.Errorf("fetchDataPage(%d): %s", req.LastPageNo, err)
	}

	treeCursor, err := NewBackwardCursor(BackwardCursorOptions{
		PageNo:     req.LastPageNo,
		PageData:   buf,
		Atree:      s,
		FracDigits: req.FracDigits,
		MetricType: diploma.Instant,
	})
	if err != nil {
		return err
	}
	defer treeCursor.Close()

	for {
		timestamp, value, done, err := treeCursor.Prev()
		if err != nil {
			return err
		}
		if done {
			return nil
		}
		req.ResponseWriter.Feed(timestamp, value)
		if timestamp < req.Since {
			return nil
		}
	}
}

type RangeScanReq struct {
	FracDigits     byte
	ResponseWriter AtreeMeasureConsumer
	RootPageNo     uint32
	Since          uint32
	Until          uint32
}

func (s *Atree) RangeScan(req RangeScanReq) error {
	pageNo, buf, err := s.findDataPage(req.RootPageNo, req.Until)
	if err != nil {
		return err
	}

	cursor, err := NewBackwardCursor(BackwardCursorOptions{
		PageNo:     pageNo,
		PageData:   buf,
		Atree:      s,
		FracDigits: req.FracDigits,
		MetricType: diploma.Instant,
	})
	if err != nil {
		return err
	}
	defer cursor.Close()

	for {
		timestamp, value, done, err := cursor.Prev()
		if err != nil {
			return err
		}
		if done {
			return nil
		}

		if timestamp <= req.Until {
			req.ResponseWriter.Feed(timestamp, value)

			if timestamp < req.Since {
				// - записи, удовлетворяющие временным рамкам, закончились.
				return nil
			}
		}
	}
}
