#![allow(incomplete_features)]
#![feature(const_generics)]
#![feature(seek_convenience)]

pub mod crypto;
pub mod packet;
pub mod character;
pub mod util;
pub mod item;

use std::io::{Read, Seek};
#[derive(Debug, PartialEq)]
pub enum PacketParseError {
    NotEnoughBytes,
    WrongPacketCommand {expected: u16, got: u16},
    WrongPacketForServerType(u16, Vec<u8>),
    UnknownPacket(u16, Vec<u8>),
    WrongPacketSize(u16, usize),
    WrongMessageCommand {expected: u8, got: u8},
    UnknownMessage(u8, Vec<u8>),
    DataStructNotLargeEnough(u64, usize),
    InvalidValue,
    ReadError,
}

pub trait PSOPacketData {
    //fn size(&self) -> usize;
    fn from_bytes<R: Read + Seek>(cursor: &mut R) -> Result<Self, PacketParseError> where Self: Sized;
    fn as_bytes(&self) -> Vec<u8>;
}

impl PSOPacketData for u8 {
    fn from_bytes<R: Read>(cursor: &mut R) -> Result<u8, PacketParseError>  {
        let mut bytes = [0u8; 1];
        let len = cursor.read(&mut bytes).map_err(|_| PacketParseError::ReadError)?;
        if len == 1 {
            Ok(bytes[0])
        } else{
            Err(PacketParseError::NotEnoughBytes)
        }
    }
    fn as_bytes(&self) -> Vec<u8> {
        vec![*self]
    }
}

impl PSOPacketData for u16 {
    fn from_bytes<R: Read>(cursor: &mut R) -> Result<u16, PacketParseError>  {
        let mut bytes = [0u8; 2];
        let len = cursor.read(&mut bytes).map_err(|_| PacketParseError::ReadError)?;
        if len == 2 {
            Ok(u16::from_le_bytes(bytes))
        }
        else {
            Err(PacketParseError::NotEnoughBytes)
        }
    }
    fn as_bytes(&self) -> Vec<u8> {
        u16::to_le_bytes(*self).to_vec()
    }
}

impl PSOPacketData for u32 {
    fn from_bytes<R: Read>(cursor: &mut R) -> Result<u32, PacketParseError>  {
        let mut bytes = [0u8; 4];
        let len = cursor.read(&mut bytes).map_err(|_| PacketParseError::ReadError)?;
        if len == 4 {
            Ok(u32::from_le_bytes(bytes))
        }
        else {
            Err(PacketParseError::NotEnoughBytes)
        }
    }
    fn as_bytes(&self) -> Vec<u8> {
        u32::to_le_bytes(*self).to_vec()
    }
}

impl PSOPacketData for f32 {
    fn from_bytes<R: Read>(cursor: &mut R) -> Result<f32, PacketParseError>  {
        let mut bytes = [0u8; 4];
        let len = cursor.read(&mut bytes).map_err(|_| PacketParseError::ReadError)?;
        if len == 4 {
            Ok(f32::from_le_bytes(bytes))
        }
        else {
            Err(PacketParseError::NotEnoughBytes)
        }
    }
    fn as_bytes(&self) -> Vec<u8> {
        f32::to_le_bytes(*self).to_vec()
    }
}

impl PSOPacketData for String {
    fn from_bytes<R: Read>(cursor: &mut R) -> Result<String, PacketParseError>  {
        let mut s: Vec<u8> = Vec::new();
        cursor.read_to_end(&mut s).map_err(|_| PacketParseError::ReadError)?;
        let mut utf16 = Vec::new();
        for c in s.chunks(2) {
            utf16.push(u16::from_le_bytes([c[0], c[1]]));
        }
        Ok(String::from_utf16_lossy(utf16.as_slice()))
    }
    fn as_bytes(&self) -> Vec<u8> {
        let mut buf = Vec::new();
        for c in self.as_str().encode_utf16() {
            buf.extend_from_slice(&c.to_le_bytes());
        }
        buf
    }
}


pub trait PSOPacket: std::fmt::Debug {
    // const CMD: u16;
    fn from_bytes(data: &[u8]) -> Result<Self, PacketParseError> where Self: Sized;
    fn as_bytes(&self) -> Vec<u8>;
}



#[cfg(test)]
mod test {
    use super::*;
    use psopacket::{pso_packet, pso_message, PSOPacketData};
    use crate::packet::messages::PSOMessage;

    #[test]
    fn test_basic_pso_packet() {
        #[pso_packet(0x23)]
        struct Test {
            a: u32,
            b: u16,
            c: u16,
        }

        let test = Test {
            a: 123456789,
            b: 54321,
            c: 9999,
        };

        let mut bytes = test.as_bytes();
        assert!(bytes == vec![16, 0, 35, 0, 0, 0, 0, 0, 21, 205, 91, 7, 49, 212, 15, 39]);

        bytes[11] = 17;
        let test2 = Test::from_bytes(&bytes).unwrap();
        assert!(test2 == Test {
            a: 291228949,
            b: 54321,
            c: 9999,
        });
    }

    #[test]
    fn test_array_in_packet() {
        #[pso_packet(0x23)]
        struct Test {
            a: u32,
            b: u16,
            c: [u16; 3],
        }

        let test = Test {
            a: 123456789,
            b: 54321,
            c: [1111, 2222, 3333],
        };

        let mut bytes = test.as_bytes();
        assert!(bytes == [20, 0, 35, 0, 0, 0, 0, 0, 21, 205, 91, 7, 49, 212, 87, 4, 174, 8, 5, 13]);

        bytes[17] = 17;
        let test2 = Test::from_bytes(&bytes).unwrap();
        assert!(test2 == Test {
            a: 123456789,
            b: 54321,
            c: [1111, 4526, 3333],
        });

    }

    #[test]
    fn test_custom_type_in_packet() {
        #[derive(Clone, Debug, PartialEq)]
        pub struct MyType {
            k: u8,
            j: u32,
        }

        impl PSOPacketData for MyType {
            fn from_bytes<R: std::io::Read>(cursor: &mut R) -> Result<MyType, PacketParseError> {
                let mut kb = [0u8; 1];
                cursor.read(&mut kb).map_err(|_| PacketParseError::ReadError)?;
                let mut jb = [0u8; 4];
                cursor.read(&mut jb).map_err(|_| PacketParseError::ReadError)?;
                Ok(MyType {
                    k: kb[0],
                    j: u32::from_le_bytes(jb)
                })
            }
            fn as_bytes(&self) -> Vec<u8> {
                let jbytes = u32::to_le_bytes(self.j);
                vec![self.k, jbytes[0], jbytes[1], jbytes[2], jbytes[3]]
            }
        }

        #[pso_packet(0x23)]
        struct Test {
            a: u32,
            b: u16,
            c: MyType,
            d: u8,
        }


        let test = Test {
            a: 123456789,
            b: 54321,
            c: MyType {
                k: 23,
                j: 999999,
            },
            d: 5,
        };

        let mut bytes = test.as_bytes();
        assert!(bytes == [20, 0, 35, 0, 0, 0, 0, 0, 21, 205, 91, 7, 49, 212, 23, 63, 66, 15, 0, 5]);
        bytes[17] = 17;
        let test2 = Test::from_bytes(&bytes).unwrap();
        assert!(test2 == Test {
            a: 123456789,
            b: 54321,
            c: MyType {
                k: 23,
                j: 1131071,
            },
            d: 5,
        });
    }

    #[test]
    fn test_string_in_packet() {
        #[pso_packet(0x23)]
        struct Test {
            a: u32,
            b: u16,
            s: String,
        }

        let test = Test {
            a: 123456789,
            b: 54321,
            s: "asdf あえいおう".to_string(),
        };

        let mut bytes = test.as_bytes();
        assert!(bytes == vec![36, 0, 35, 0, 0, 0, 0, 0, 21, 205, 91, 7, 49, 212, 97, 0, 115, 0, 100, 0,
                              102, 0, 32, 0, 66, 48, 72, 48, 68, 48, 74, 48, 70, 48, 0, 0]);
        bytes[18] = 99;
        let test2 = Test::from_bytes(&bytes).unwrap();
        assert!(test2 == Test {
            a: 123456789,
            b: 54321,
            s: "ascf あえいおう\u{0}".to_string(),
        });
    }

    #[test]
    fn test_vec_in_packet() {
        #[pso_packet(0x23)]
        struct Test {
            a: u32,
            b: u16,
            v: Vec<u16>,
        }

        let test = Test {
            a: 123456789,
            b: 54321,
            v: vec![123,456,789],
        };

        let mut bytes = test.as_bytes();
        assert!(bytes == vec![20, 0, 35, 0, 3, 0, 0, 0, 21, 205, 91, 7, 49, 212, 123, 0, 200, 1, 21, 3]);
        bytes[18] = 99;
        let test2 = Test::from_bytes(&bytes).unwrap();
        assert!(test2 == Test {
            a: 123456789,
            b: 54321,
            v: vec![123,456,867],
        });
    }

    #[test]
    fn test_no_flag_packet() {
        #[pso_packet(0x23, no_flag)]
        struct Test {
            a: u32,
            b: u16,
            c: u16,
        }

        let test = Test {
            a: 123456789,
            b: 54321,
            c: 9999,
        };

        let mut bytes = test.as_bytes();
        assert!(bytes == vec![12, 0, 35, 0, 21, 205, 91, 7, 49, 212, 15, 39]);

        bytes[11] = 17;
        let test2 = Test::from_bytes(&bytes).unwrap();
        assert!(test2 == Test {
            a: 123456789,
            b: 54321,
            c: 4367,
        });
    }

    #[test]
    fn test_command_error() {
        #[pso_packet(0x23)]
        struct Test {
            a: u32,
            b: u16,
            #[nodebug]
            c: [u8; 0x2000],
        }

        let test = Test {
            a: 123456789,
            b: 54321,
            c: [0; 0x2000],
        };

        let mut bytes = test.as_bytes();
        bytes[2] = 17;
        let test2 = Test::from_bytes(&bytes);
        assert!(test2 == Err(PacketParseError::WrongPacketCommand { expected: 0x23, got: 17}));
    }

    #[test]
    fn test_derive_pso_data_packet() {
        #[derive(PSOPacketData)]
        struct Test {
            a: u8,
            b: u32,
            c: u16,
        }

        let test = Test {
            a: 12,
            b: 34567,
            c: 890,
        };

        let mut bytes = test.as_bytes();
        assert!(bytes == vec![12, 7, 135, 0, 0, 122, 3]);
        bytes[2] = 17;
        let mut cur = std::io::Cursor::new(bytes.clone());
        let test2 = Test::from_bytes(&mut cur).unwrap();
        assert!(test2 == Test {
            a: 12,
            b: 4359,
            c: 890
        });
    }

    #[test]
    fn test_derive_pso_data_packet_array() {
        #[derive(PSOPacketData)]
        struct Test {
            a: u8,
            b: u32,
            c: u16,
            d: [u8; 5],
        }

        let test = Test {
            a: 12,
            b: 34567,
            c: 890,
            d: [1,2,3,4,5],
        };

        let mut bytes = test.as_bytes();
        assert!(bytes == vec![12, 7, 135, 0, 0, 122, 3, 1, 2, 3, 4, 5]);
        bytes[10] = 17;
        let mut cur = std::io::Cursor::new(bytes.clone());
        let test2 = Test::from_bytes(&mut cur).unwrap();
        assert!(test2 == Test {
            a: 12,
            b: 34567,
            c: 890,
            d: [1,2,3,17,5]
        });
    }

    #[test]
    fn test_derive_pso_data_packet_not_enough_data() {
        #[derive(PSOPacketData)]
        struct Test {
            a: u8,
            b: u32,
            c: u16,
        }

        let test = Test {
            a: 12,
            b: 34567,
            c: 890,
        };

        let mut bytes = test.as_bytes();
        bytes.extend(test.as_bytes());

        let mut cur = std::io::Cursor::new(bytes.clone());
        let test2 = Test::from_bytes(&mut cur).unwrap();
        assert!(test2 == Test {
            a: 12,
            b: 34567,
            c: 890,
        });

        let bytes2 = (0..14).collect::<Vec<_>>();
        let mut cur = std::io::Cursor::new(bytes2);
        let test3 = Test::from_bytes(&mut cur);
        assert!(test3 == Ok(Test {
            a: 0,
            b: 67305985,
            c: 1541,
        }));
        let test4 = Test::from_bytes(&mut cur);
        assert!(test4 == Ok(Test {
            a: 7,
            b: 185207048,
            c: 3340,
        }));
        let test5 = Test::from_bytes(&mut cur);
        assert!(test5 == Err(PacketParseError::NotEnoughBytes));
    }

    #[test]
    fn test_pso_packet_manual_flag() {
        #[pso_packet(0x23, manual_flag)]
        struct Test {
            flag: u32,
            a: u32,
            b: u32,
        }

        let test = Test {
            flag: 99,
            a: 123,
            b: 456,
        };

        let mut bytes = test.as_bytes();
        assert!(bytes == vec![16, 0, 35, 0, 99, 0, 0, 0, 123, 0, 0, 0, 200, 1, 0, 0]);

        bytes[6] = 2;
        let test2 = Test::from_bytes(&bytes).unwrap();
        assert!(test2 == Test {
            flag: 131171,
            a: 123,
            b: 456,
        });
    }

    #[test]
    fn test_pso_message() {
        #[pso_message(0x23)]
        struct Test {
            a: u32,
            b: f32,
        }

        let test = Test {
            client: 1,
            target: 2,
            a: 123,
            b: 4.56,
        };

        let mut bytes = test.as_bytes();
        assert!(bytes == vec![35, 3, 1, 2, 123, 0, 0, 0, 133, 235, 145, 64]);

        bytes[6] = 2;
        let test2 = Test::from_bytes(&mut std::io::Cursor::new(bytes)).unwrap();
        assert!(test2 == Test {
            client: 1,
            target: 2,
            a: 131195,
            b: 4.56,
        });
    }

    #[test]
    fn test_pso_message_non_4_byte_size() {
        #[pso_message(0x23)]
        struct Test {
            a: u32,
            b: f32,
            c: u8,
        }

        let test = Test {
            client: 1,
            target: 2,
            a: 123,
            b: 4.56,
            c: 5,
        };

        let mut bytes = test.as_bytes();
        assert!(bytes == vec![35, 4, 1, 2, 123, 0, 0, 0, 133, 235, 145, 64, 5, 0, 0, 0]);

        bytes[6] = 2;
        let test2 = Test::from_bytes(&mut std::io::Cursor::new(bytes)).unwrap();
        assert!(test2 == Test {
            client: 1,
            target: 2,
            a: 131195,
            b: 4.56,
            c: 5,
        });
    }
}