use core::{fmt::Debug, str};
use std::io::{self, Cursor, Read, Write};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use crate::{header::DatabaseHeader, info::ExtraInfoRecord};
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ExtraInfoCategory {
	pub category_id: u8,
	pub name: [u8; 16],
	pub renamed: bool,
}
impl ExtraInfoCategory {
	pub fn name_try_str<'x>(&'x self) -> Result<&'x str, str::Utf8Error> {
		let mut idx = 0;
		while idx < self.name.len() {
			if self.name[idx] == 0u8 {
				break;
			}
			idx += 1;
		}
		str::from_utf8(&self.name[0..idx])
	}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct AppInfoCategories {
	pub renamed_categories: u16,
	pub categories: Vec<ExtraInfoCategory>,
	category_unique_ids: [u8; 16],
	last_unique_id: u8,
	rsvd: u8,
	is_data: bool,
}
impl AppInfoCategories {
	pub fn from_bytes(hdr: &DatabaseHeader, rdr: &mut Cursor<&[u8]>) -> Result<Self, io::Error> {
		if &hdr.type_code[..] != b"DATA" {
			return Ok(Default::default());
		}
		let mut categories = Vec::new();
		let renamed_flags = rdr.read_u16::<BigEndian>()?;
		for category_id in 0..16 {
			let name = {
				let mut buf = [0u8; 16];
				rdr.read_exact(&mut buf)?;
				buf
			};
			if name == [0u8; 16] {
				continue;
			}
			categories.push(ExtraInfoCategory {
				category_id,
				name,
				renamed: (renamed_flags & (1 << category_id)) != 0,
			});
		}
		let mut category_unique_ids = [0_u8; 16];
		for idx in 0..16 {
			category_unique_ids[idx] = rdr.read_u8()?;
		}
		let last_unique_id = rdr.read_u8()?;
		let rsvd = rdr.read_u8()?;
		Ok(Self {
			renamed_categories: renamed_flags,
			categories,
			category_unique_ids,
			last_unique_id,
			rsvd,
			is_data: true,
		})
	}
}
impl ExtraInfoRecord for AppInfoCategories {
	const SIZE: usize = 2 + 16 * 16 + 16 + 1 + 1;
	fn from_bytes(hdr: &DatabaseHeader, data: &mut Cursor<&[u8]>) -> Result<Self, io::Error> {
		Self::from_bytes(hdr, data)
	}
	fn to_bytes(&self) -> Result<Vec<u8>, io::Error> {
		if !self.is_data {
			return Ok(vec![]);
		}
		let mut cursor = Cursor::new(Vec::new());
		cursor.write_u16::<BigEndian>(self.renamed_categories)?;
		for cat in self.categories.iter() {
			cursor.write(&cat.name)?;
		}
		for _ in self.categories.len()..16 {
			cursor.write(&[0_u8; 16])?;
		}
		cursor.write(&self.category_unique_ids)?;
		cursor.write_u8(self.last_unique_id)?;
		cursor.write_u8(self.rsvd)?;
		Ok(cursor.into_inner())
	}
	fn data_empty(&self) -> bool {
		false
	}
	fn data_item_categories(&self) -> Option<Vec<ExtraInfoCategory>> {
		Some(self.categories.clone())
	}
}