#[allow(clippy::empty_docs)]
///
pub mod from_tree {
    use std::collections::VecDeque;

    use bstr::{BStr, BString, ByteSlice, ByteVec};
    use gix_object::{tree, tree::EntryKind, FindExt};
    use gix_traverse::tree::{breadthfirst, visit::Action, Visit};

    use crate::{
        entry::{Flags, Mode, Stat},
        Entry, PathStorage, State, Version,
    };

    /// The error returned by [State::from_tree()].
    #[derive(Debug, thiserror::Error)]
    #[allow(missing_docs)]
    pub enum Error {
        #[error("The path \"{path}\" is invalid")]
        InvalidComponent {
            path: BString,
            source: gix_validate::path::component::Error,
        },
        #[error(transparent)]
        Traversal(#[from] gix_traverse::tree::breadthfirst::Error),
    }

    /// Initialization
    impl State {
        /// Return a new and empty in-memory index assuming the given `object_hash`.
        pub fn new(object_hash: gix_hash::Kind) -> Self {
            State {
                object_hash,
                timestamp: filetime::FileTime::now(),
                version: Version::V2,
                entries: vec![],
                path_backing: vec![],
                is_sparse: false,
                tree: None,
                link: None,
                resolve_undo: None,
                untracked: None,
                fs_monitor: None,
                offset_table_at_decode_time: false,
                end_of_index_at_decode_time: false,
            }
        }
        /// Create an index [`State`] by traversing `tree` recursively, accessing sub-trees
        /// with `objects`.
        /// `validate` is used to determine which validations to perform on every path component we see.
        ///
        /// **No extension data is currently produced**.
        pub fn from_tree<Find>(
            tree: &gix_hash::oid,
            objects: Find,
            validate: gix_validate::path::component::Options,
        ) -> Result<Self, Error>
        where
            Find: gix_object::Find,
        {
            let _span = gix_features::trace::coarse!("gix_index::State::from_tree()");
            let mut buf = Vec::new();
            let root = objects
                .find_tree_iter(tree, &mut buf)
                .map_err(breadthfirst::Error::from)?;
            let mut delegate = CollectEntries::new(validate);
            match breadthfirst(root, breadthfirst::State::default(), &objects, &mut delegate) {
                Ok(()) => {}
                Err(gix_traverse::tree::breadthfirst::Error::Cancelled) => {
                    let (path, err) = delegate
                        .invalid_path
                        .take()
                        .expect("cancellation only happens on validation error");
                    return Err(Error::InvalidComponent { path, source: err });
                }
                Err(err) => return Err(err.into()),
            }

            let CollectEntries {
                mut entries,
                path_backing,
                path: _,
                path_deque: _,
                validate: _,
                invalid_path: _,
            } = delegate;

            entries.sort_by(|a, b| Entry::cmp_filepaths(a.path_in(&path_backing), b.path_in(&path_backing)));

            Ok(State {
                object_hash: tree.kind(),
                timestamp: filetime::FileTime::now(),
                version: Version::V2,
                entries,
                path_backing,
                is_sparse: false,
                tree: None,
                link: None,
                resolve_undo: None,
                untracked: None,
                fs_monitor: None,
                offset_table_at_decode_time: false,
                end_of_index_at_decode_time: false,
            })
        }
    }

    struct CollectEntries {
        entries: Vec<Entry>,
        path_backing: PathStorage,
        path: BString,
        path_deque: VecDeque<BString>,
        validate: gix_validate::path::component::Options,
        invalid_path: Option<(BString, gix_validate::path::component::Error)>,
    }

    impl CollectEntries {
        pub fn new(validate: gix_validate::path::component::Options) -> CollectEntries {
            CollectEntries {
                entries: Vec::new(),
                path_backing: Vec::new(),
                path: BString::default(),
                path_deque: VecDeque::new(),
                validate,
                invalid_path: None,
            }
        }

        fn push_element(&mut self, name: &BStr) {
            if !self.path.is_empty() {
                self.path.push(b'/');
            }
            self.path.push_str(name);
            if self.invalid_path.is_none() {
                if let Err(err) = gix_validate::path::component(name, None, self.validate) {
                    self.invalid_path = Some((self.path.clone(), err))
                }
            }
        }

        pub fn add_entry(&mut self, entry: &tree::EntryRef<'_>) {
            let mode = match entry.mode.kind() {
                EntryKind::Tree => unreachable!("visit_non_tree() called us"),
                EntryKind::Blob => Mode::FILE,
                EntryKind::BlobExecutable => Mode::FILE_EXECUTABLE,
                EntryKind::Link => Mode::SYMLINK,
                EntryKind::Commit => Mode::COMMIT,
            };
            // There are leaf-names that require special validation, specific to their mode.
            // Double-validate just for this case, as the previous validation didn't know the mode yet.
            if self.invalid_path.is_none() {
                let start = self.path.rfind_byte(b'/').map(|pos| pos + 1).unwrap_or_default();
                if let Err(err) = gix_validate::path::component(
                    self.path[start..].as_ref(),
                    (entry.mode.kind() == EntryKind::Link).then_some(gix_validate::path::component::Mode::Symlink),
                    self.validate,
                ) {
                    self.invalid_path = Some((self.path.clone(), err));
                }
            }

            let path_start = self.path_backing.len();
            self.path_backing.extend_from_slice(&self.path);

            let new_entry = Entry {
                stat: Stat::default(),
                id: entry.oid.into(),
                flags: Flags::empty(),
                mode,
                path: path_start..self.path_backing.len(),
            };

            self.entries.push(new_entry);
        }

        fn determine_action(&self) -> Action {
            if self.invalid_path.is_none() {
                Action::Continue
            } else {
                Action::Cancel
            }
        }
    }

    impl Visit for CollectEntries {
        fn pop_front_tracked_path_and_set_current(&mut self) {
            self.path = self
                .path_deque
                .pop_front()
                .expect("every call is matched with push_tracked_path_component");
        }

        fn push_back_tracked_path_component(&mut self, component: &BStr) {
            self.push_element(component);
            self.path_deque.push_back(self.path.clone());
        }

        fn push_path_component(&mut self, component: &BStr) {
            self.push_element(component);
        }

        fn pop_path_component(&mut self) {
            if let Some(pos) = self.path.rfind_byte(b'/') {
                self.path.resize(pos, 0);
            } else {
                self.path.clear();
            }
        }

        fn visit_tree(&mut self, _entry: &gix_object::tree::EntryRef<'_>) -> Action {
            self.determine_action()
        }

        fn visit_nontree(&mut self, entry: &gix_object::tree::EntryRef<'_>) -> Action {
            self.add_entry(entry);
            self.determine_action()
        }
    }
}
