use super::super::embedded_names::EmbeddedNameRow;

#[derive(Clone)]
pub(crate) struct PayloadEnvelopeRow {
    pub(in crate::inspect::smp) name_tag_relative_offset: usize,
    pub(in crate::inspect::smp) primary_name: Option<String>,
    pub(in crate::inspect::smp) secondary_name: Option<String>,
    pub(in crate::inspect::smp) name_payload_end_relative_offset: Option<usize>,
    pub(in crate::inspect::smp) policy_tag_relative_offset: Option<usize>,
    pub(in crate::inspect::smp) profile_tag_relative_offset: Option<usize>,
    pub(in crate::inspect::smp) next_name_tag_relative_offset: Option<usize>,
    pub(in crate::inspect::smp) name_to_policy_gap_len: Option<usize>,
    pub(in crate::inspect::smp) policy_chunk_len: Option<usize>,
    pub(in crate::inspect::smp) profile_chunk_len_to_next_name_or_end: Option<usize>,
    pub(in crate::inspect::smp) short_profile_first_flag_byte: Option<u8>,
    pub(in crate::inspect::smp) short_profile_second_flag_byte: Option<u8>,
}

pub(crate) fn build_payload_envelope_rows(
    records_payload: &[u8],
    embedded_name_tag_offsets: &[usize],
    embedded_name_rows: &[EmbeddedNameRow],
    policy_tag_offsets: &[usize],
    profile_tag_offsets: &[usize],
) -> Vec<PayloadEnvelopeRow> {
    embedded_name_rows
        .iter()
        .enumerate()
        .map(|(row_index, row)| {
            let next_name_tag_relative_offset = embedded_name_tag_offsets
                .get(row_index + 1)
                .copied()
                .or(Some(records_payload.len()));
            let name_payload_end_relative_offset = Some(
                row.name_tag_relative_offset
                    + row.name_payload_relative_offset
                    + row.name_payload_len,
            );
            let policy_tag_relative_offset = policy_tag_offsets.iter().copied().find(|offset| {
                *offset > row.name_tag_relative_offset
                    && next_name_tag_relative_offset.is_none_or(|next_name| *offset < next_name)
            });
            let profile_tag_relative_offset = policy_tag_relative_offset.and_then(|policy| {
                profile_tag_offsets.iter().copied().find(|offset| {
                    *offset > policy
                        && next_name_tag_relative_offset.is_none_or(|next_name| *offset < next_name)
                })
            });
            let name_to_policy_gap_len = name_payload_end_relative_offset
                .zip(policy_tag_relative_offset)
                .and_then(
                    |(name_payload_end_relative_offset, policy_tag_relative_offset)| {
                        policy_tag_relative_offset.checked_sub(name_payload_end_relative_offset)
                    },
                );
            let policy_chunk_len = policy_tag_relative_offset
                .zip(profile_tag_relative_offset)
                .and_then(
                    |(policy_tag_relative_offset, profile_tag_relative_offset)| {
                        profile_tag_relative_offset.checked_sub(policy_tag_relative_offset + 4)
                    },
                );
            let profile_chunk_len_to_next_name_or_end =
                profile_tag_relative_offset.and_then(|profile_tag_relative_offset| {
                    next_name_tag_relative_offset.and_then(|next_name_tag_relative_offset| {
                        next_name_tag_relative_offset.checked_sub(profile_tag_relative_offset + 4)
                    })
                });
            let short_profile_first_flag_byte =
                profile_tag_relative_offset.and_then(|profile_tag_relative_offset| {
                    records_payload
                        .get(profile_tag_relative_offset + 4)
                        .copied()
                });
            let short_profile_second_flag_byte =
                profile_tag_relative_offset.and_then(|profile_tag_relative_offset| {
                    records_payload
                        .get(profile_tag_relative_offset + 5)
                        .copied()
                });
            PayloadEnvelopeRow {
                name_tag_relative_offset: row.name_tag_relative_offset,
                primary_name: row.primary_name.clone(),
                secondary_name: row.secondary_name.clone(),
                name_payload_end_relative_offset,
                policy_tag_relative_offset,
                profile_tag_relative_offset,
                next_name_tag_relative_offset,
                name_to_policy_gap_len,
                policy_chunk_len,
                profile_chunk_len_to_next_name_or_end,
                short_profile_first_flag_byte,
                short_profile_second_flag_byte,
            }
        })
        .collect()
}
