use anyhow::{Context, Result, ensure};

use crate::conveyer::{keys, types::DatabaseBranchId};

const PIDX_PGNO_BYTES: usize = std::mem::size_of::<u32>();
const PIDX_TXID_BYTES: usize = std::mem::size_of::<u64>();

#[derive(Debug, Clone, Copy)]
pub(super) struct PageRef {
	pub(super) source: super::plan::ReadSource,
	pub(super) txid: u64,
	pub(super) kind: PageRefKind,
}

#[derive(Debug, Clone, Copy)]
pub(super) enum PageRefKind {
	Pidx,
	HistoricalDelta,
}

pub(super) fn decode_branch_pidx_pgno(branch_id: DatabaseBranchId, key: &[u8]) -> Result<u32> {
	let prefix = keys::branch_pidx_prefix(branch_id);
	ensure!(
		key.starts_with(&prefix),
		"branch pidx key did not start with expected prefix"
	);

	let suffix = &key[prefix.len()..];
	ensure!(
		suffix.len() == PIDX_PGNO_BYTES,
		"branch pidx key suffix had {} bytes, expected {}",
		suffix.len(),
		PIDX_PGNO_BYTES
	);

	Ok(u32::from_be_bytes(
		suffix
			.try_into()
			.context("branch pidx key suffix should decode as u32")?,
	))
}

pub(super) fn decode_pidx_txid(value: &[u8]) -> Result<u64> {
	ensure!(
		value.len() == PIDX_TXID_BYTES,
		"pidx value had {} bytes, expected {}",
		value.len(),
		PIDX_TXID_BYTES
	);

	Ok(u64::from_be_bytes(
		value
			.try_into()
			.context("pidx value should decode as u64")?,
	))
}
