use anyhow::Result;
use byteorder::{LittleEndian, ReadBytesExt};
use serde::{Deserialize, Serialize};
use std::io::{Cursor, Read};
use std::path::Path;

/// Item tile metadata from tiledata.mul.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ItemTileData {
    pub id: u32,
    pub flags: u64,
    pub weight: u8,
    pub quality: u8,
    pub anim_id: u16,
    pub height: u8,
    pub hue: u8,
    pub name: String,
}

/// Read all item tile entries from tiledata.mul.
/// Land tiles (first 428 blocks × 32 entries) are skipped — we only care about items.
pub fn read_item_tiles(tiledata_path: &Path) -> Result<Vec<ItemTileData>> {
    let data = std::fs::read(tiledata_path)?;
    let mut cursor = Cursor::new(&data);

    // Skip land tiles: 512 blocks of 32 land entries
    // Each land block: 4-byte header + 32 × (8 flags + 2 texid + 20 name) = 4 + 32*30 = 964 bytes
    // Actually: 4 + 32*(4+2+20) = 4 + 832 = 836 for old format; new (HS+) uses 8-byte flags
    // Use the newer format (64-bit flags) as ServUO targets it.
    // Land block size: 4 (header) + 32 * (8 flags + 2 texid + 20 name) = 4 + 960 = 964
    let land_block_size: u64 = 4 + 32 * (8 + 2 + 20);
    let land_blocks: u64 = 512;
    cursor.set_position(land_blocks * land_block_size);

    let mut items = Vec::new();
    let mut id = 0u32;

    while (cursor.position() as usize) < data.len() {
        // Block header (4 bytes, skip)
        let mut header = [0u8; 4];
        if cursor.read_exact(&mut header).is_err() {
            break;
        }

        for _ in 0..32 {
            if (cursor.position() as usize) >= data.len() {
                break;
            }

            let flags = cursor.read_u64::<LittleEndian>()?;
            let weight = cursor.read_u8()?;
            let quality = cursor.read_u8()?;
            let _unknown1 = cursor.read_u16::<LittleEndian>()?;
            let _unknown2 = cursor.read_u8()?;
            let _quantity = cursor.read_u8()?;
            let anim_id = cursor.read_u16::<LittleEndian>()?;
            let _unknown3 = cursor.read_u8()?;
            let hue = cursor.read_u8()?;
            let _unknown4 = cursor.read_u16::<LittleEndian>()?;
            let height = cursor.read_u8()?;

            let mut name_buf = [0u8; 20];
            cursor.read_exact(&mut name_buf)?;
            let name = String::from_utf8_lossy(&name_buf)
                .trim_end_matches('\0')
                .to_string();

            items.push(ItemTileData {
                id,
                flags,
                weight,
                quality,
                anim_id,
                height,
                hue,
                name,
            });
            id += 1;
        }
    }

    Ok(items)
}
