use super::*;
use crate::entity::field::{Decode, Encode, FieldPath, FieldState, FieldValue, Skip};
use crate::proto::{CSvcMsgPacketEntities, Message};
use crate::reader::{FieldPathCodec, SliceReader};
use crate::stream::copy::{bit_position, copy_original_bits};
use crate::stream::field_path::FieldOp;
use crate::writer::{BitsWriter, BitstreamWriter};
use std::rc::Rc;

pub(super) const ENTITY_REWRITE_BUFFER_LEN: usize = 8192;

pub(super) struct FieldReplacement {
    serializer: Rc<crate::entity::field::Serializer>,
    fp: FieldPath,
    value: FieldValue,
    value_start: usize,
    value_end: usize,
}

pub(super) struct DecodedEntityField {
    fp: FieldPath,
    name: Rc<str>,
    value_start: usize,
    value_end: usize,
}

impl<'a, R, W> DemoWriter<'a, R, W>
where
    R: BitsReader + MessageReader,
    W: Write + Seek,
{
    #[inline]
    fn clear_entity_paths(&mut self) {
        self.entity_rewrite_paths_len = 0;
    }

    #[inline]
    fn push_entity_path(&mut self, fp: FieldPath) {
        debug_assert!(
            self.entity_rewrite_paths_len < self.entity_rewrite_paths.len(),
            "entity rewrite path buffer length exceeded"
        );
        self.entity_rewrite_paths[self.entity_rewrite_paths_len].write(fp);
        self.entity_rewrite_paths_len += 1;
    }

    #[inline]
    fn entity_paths(&self) -> &[FieldPath] {
        unsafe {
            std::slice::from_raw_parts(
                self.entity_rewrite_paths.as_ptr() as *const FieldPath,
                self.entity_rewrite_paths_len,
            )
        }
    }

    #[inline]
    fn clear_decoded_fields(&mut self) {
        self.entity_decoded_fields_len = 0;
    }

    #[inline]
    fn push_decoded_field(&mut self, field: DecodedEntityField) {
        debug_assert!(
            self.entity_decoded_fields_len < self.entity_decoded_fields.len(),
            "entity decoded field buffer length exceeded"
        );
        self.entity_decoded_fields[self.entity_decoded_fields_len].write(field);
        self.entity_decoded_fields_len += 1;
    }

    #[inline]
    fn push_field_replacement(&mut self, replacement: FieldReplacement) {
        debug_assert!(
            self.entity_replacements_len < self.entity_replacements.len(),
            "entity replacement buffer length exceeded"
        );
        self.entity_replacements[self.entity_replacements_len].write(replacement);
        self.entity_replacements_len += 1;
    }
}

impl<'a, R, W> DemoWriter<'a, R, W>
where
    R: BitsReader + MessageReader,
    W: Write + Seek,
{
    pub(crate) fn rewrite_svc_packet_entities(
        &mut self,
        msg: &[u8],
    ) -> Result<Option<Vec<u8>>, ParserError> {
        let mut packet_entities = CSvcMsgPacketEntities::decode(msg)?;
        let Some(entity_data) = packet_entities.entity_data.as_deref() else {
            return Ok(None);
        };

        let (rewritten, changed) =
            self.rewrite_entity_data(entity_data, packet_entities.updated_entries())?;
        if changed {
            packet_entities.entity_data = Some(rewritten);
            packet_entities.serialized_entities = None;
            Ok(Some(packet_entities.encode_to_vec()))
        } else {
            Ok(None)
        }
    }

    fn rewrite_entity_data(
        &mut self,
        entity_data: &[u8],
        updated_entries: i32,
    ) -> Result<(Vec<u8>, bool), ParserError> {
        let mut reader = SliceReader::new(entity_data);
        self.entity_replacements_len = 0;
        let mut index = usize::MAX;
        let path_reader = self.field_path_codec.clone();

        for _ in 0..updated_entries {
            let delta = reader.read_ubit_var();
            index = index.wrapping_add((delta + 1) as usize);

            let cmd = reader.read_bits(2);

            if cmd == 1 {
                continue;
            }

            match EntityEvents::from_cmd(cmd) {
                EntityEvents::Created => {
                    self.rewrite_entity_created(&mut reader, &path_reader, index)?;
                }
                EntityEvents::Updated => {
                    self.rewrite_entity_updated(&mut reader, &path_reader, index)?;
                }
                EntityEvents::Deleted => {
                    self.parser.context.entities.entities_vec[index].index = u32::MAX;
                }
            }
        }

        if self.entity_replacements_len == 0 {
            return Ok((Vec::new(), false));
        }

        let mut out = Vec::with_capacity(entity_data.len());
        let mut writer = BitstreamWriter::new(&mut out);
        let mut copy_start = 0;
        let replacements_len = self.entity_replacements_len;
        self.entity_replacements_len = 0;
        for i in 0..replacements_len {
            let replacement = unsafe { self.entity_replacements[i].assume_init_read() };
            copy_original_bits(
                entity_data,
                copy_start,
                replacement.value_start - copy_start,
                &mut writer,
            )?;
            replacement
                .serializer
                .get_decoder(&replacement.fp)
                .encode(&mut writer, &replacement.value)?;
            copy_start = replacement.value_end;
        }
        copy_original_bits(
            entity_data,
            copy_start,
            entity_data.len() * 8 - copy_start,
            &mut writer,
        )?;
        writer.flush()?;
        drop(writer);
        Ok((out, true))
    }

    fn rewrite_entity_created(
        &mut self,
        reader: &mut SliceReader<'_>,
        path_reader: &FieldPathCodec,
        index: usize,
    ) -> Result<(), ParserError> {
        let class_id = reader.read_bits(self.parser.context.classes.class_id_size) as i32;

        let serial = reader.read_bits(17);

        let _ = reader.read_var_u32();

        let class = self
            .parser
            .context
            .classes
            .get_by_id_rc(class_id as usize)
            .clone();

        let state = self.entity_baseline_state(class_id, &class.serializer);
        let mut entity = Entity::new(index as u32, serial, class, state);

        let track = self.should_track_entity(EntityEvents::Created, &entity);
        let rewrite = self.should_rewrite_entity(EntityEvents::Created, &entity);
        if track || rewrite {
            self.rewrite_fields(
                reader,
                path_reader,
                EntityEvents::Created,
                &mut entity,
                rewrite,
            )?;
        } else {
            self.skip_original_fields(reader, path_reader, &entity);
        }
        if !track {
            entity.state = FieldState::default();
        }
        self.parser.context.entities.entities_vec[index] = entity;

        Ok(())
    }

    fn rewrite_entity_updated(
        &mut self,
        reader: &mut SliceReader<'_>,
        path_reader: &FieldPathCodec,
        index: usize,
    ) -> Result<(), ParserError> {
        let class = self.parser.context.entities.entities_vec[index]
            .class
            .clone();
        let placeholder = Entity {
            index: u32::MAX,
            serial: 0,
            class,
            state: FieldState::default(),
        };
        let mut entity = std::mem::replace(
            &mut self.parser.context.entities.entities_vec[index],
            placeholder,
        );
        let track = self.should_track_entity(EntityEvents::Updated, &entity);
        let rewrite = self.should_rewrite_entity(EntityEvents::Updated, &entity);
        if track || rewrite {
            self.rewrite_fields(
                reader,
                path_reader,
                EntityEvents::Updated,
                &mut entity,
                rewrite,
            )?;
        } else {
            self.skip_original_fields(reader, path_reader, &entity);
        }
        if !track {
            entity.state = FieldState::default();
        }
        self.parser.context.entities.entities_vec[index] = entity;

        Ok(())
    }

    fn skip_original_fields(
        &mut self,
        reader: &mut SliceReader<'_>,
        path_reader: &FieldPathCodec,
        entity: &Entity,
    ) {
        self.clear_entity_paths();
        let mut fp = FieldPath::default();

        loop {
            reader.refill();
            let op = path_reader.read_op(reader);
            if let FieldOp::FieldPathEncodeFinish = op {
                break;
            }
            op.execute(reader, &mut fp);
            self.push_entity_path(fp);
        }

        for fp in self.entity_paths().iter().copied() {
            entity.class.serializer.get_decoder(&fp).skip(reader);
        }
    }

    fn rewrite_fields(
        &mut self,
        reader: &mut SliceReader<'_>,
        path_reader: &FieldPathCodec,
        event: EntityEvents,
        entity: &mut Entity,
        rewrite: bool,
    ) -> Result<(), ParserError> {
        self.clear_entity_paths();
        let mut fp = FieldPath::default();

        loop {
            reader.refill();
            let op = path_reader.read_op(reader);
            if op == FieldOp::FieldPathEncodeFinish {
                break;
            }
            op.execute(reader, &mut fp);
            self.push_entity_path(fp);
        }

        if !rewrite {
            for fp in self.entity_paths().iter().copied() {
                let decoder = entity.class.serializer.get_decoder(&fp);
                let value = decoder.decode(reader);
                entity.state.set(&fp, value);
            }
            return Ok(());
        }

        self.clear_decoded_fields();
        for i in 0..self.entity_rewrite_paths_len {
            let fp = unsafe { self.entity_rewrite_paths[i].assume_init_read() };
            let name = entity.class.serializer.get_name(&fp);
            let decoder = entity.class.serializer.get_decoder(&fp);
            let value_start = bit_position(reader);
            let value = decoder.decode(reader);
            let value_end = bit_position(reader);
            entity.state.set(&fp, value);
            self.push_decoded_field(DecodedEntityField {
                fp,
                name,
                value_start,
                value_end,
            });
        }

        let decoded_fields_len = self.entity_decoded_fields_len;
        self.entity_decoded_fields_len = 0;
        for i in 0..decoded_fields_len {
            let field = unsafe { self.entity_decoded_fields[i].assume_init_read() };
            let Some(value) = entity.state.get_value(&field.fp) else {
                continue;
            };
            let replacement = self.replace_entity_field(event, entity, &field.name, value);

            if let Some(next_value) = replacement {
                entity.state.set(&field.fp, next_value.clone());
                self.push_field_replacement(FieldReplacement {
                    serializer: entity.class.serializer.clone(),
                    fp: field.fp,
                    value: next_value,
                    value_start: field.value_start,
                    value_end: field.value_end,
                });
            }
        }

        Ok(())
    }

    fn entity_baseline_state(
        &mut self,
        class_id: i32,
        serializer: &crate::entity::field::Serializer,
    ) -> FieldState {
        self.parser
            .context
            .baselines
            .states
            .entry(class_id)
            .or_insert_with(|| {
                let mut state = FieldState::default();
                if let Some(baseline) = self.parser.context.baselines.baselines.get(&class_id) {
                    self.parser.field_reader.read_fields(
                        &mut SliceReader::new(baseline.as_ref()),
                        serializer,
                        &mut state,
                    );
                }
                state
            })
            .clone()
    }
}
