#[allow(warnings)]
#[cfg(feature = "docx")]
pub mod docx {
    use std::{fs::File, io::Read};

    use zip::ZipArchive;

    /// docx_replace
    ///
    /// finds all 'name' and replace with 'andrew'
    /// ```rust
    ///use doe::*;
    ///docx::docx_replace("./name.docx","name","andrew").unwrap();
    /// ```
    pub fn docx_replace(
        docx_path: &str,
        target: &str,
        new_target: &str,
    ) -> Result<(), Box<dyn std::error::Error>> {
        use std::fs::File;
        use std::io::prelude::*;
        use zip::read::ZipArchive;
        use zip::write::FileOptions;
        use zip::CompressionMethod;

        // Open the .docx file as a zip
        let file = File::open(docx_path)?;
        let mut archive = ZipArchive::new(file)?;
        let new_archive_path = "new_archive.zip";

        let options = FileOptions::default()
            .compression_method(CompressionMethod::Stored)
            .unix_permissions(0o755);

        let file = File::create(&new_archive_path).unwrap();
        let mut new_zip = zip::ZipWriter::new(file);

        // Loop over all of the files in the .docx archive
        for i in 0..archive.len() {
            let mut file_in_archive = archive.by_index(i).unwrap();
            let file_in_archive_name = &file_in_archive.name();
            if file_in_archive_name.to_string() == "word/document.xml" {
                let mut contents = String::new();
                file_in_archive.read_to_string(&mut contents).unwrap();
                // Perform text replacement
                let new_contents = contents.replace(target, new_target);
                new_zip.start_file("word/document.xml", options)?;
                new_zip.write_all(new_contents.as_bytes())?;
            } else {
                new_zip.start_file(file_in_archive_name.to_string(), options)?;
                let mut buffer = Vec::new();
                file_in_archive.read_to_end(&mut buffer)?;
                new_zip.write_all(&buffer)?;
            }
        }
        std::fs::rename(new_archive_path, docx_path).unwrap();
        Ok(())
    }
    ///```rust
    /// use doe::*;
    /// docx::docx_replace_values("./rust.docx", &[("[name]","andrew")]).unwrap();
    /// ```
    pub fn docx_replace_values(
        docx_path: &str,
        values: &[(&str, &str)],
    ) -> Result<(), Box<dyn std::error::Error>> {
        use std::fs::File;
        use std::io::prelude::*;
        use zip::read::ZipArchive;
        use zip::write::FileOptions;
        use zip::CompressionMethod;

        // Open the .docx file as a zip
        let file = File::open(docx_path)?;
        let mut archive = ZipArchive::new(file)?;
        let new_archive_path = "new_archive.zip";

        let options = FileOptions::default()
            .compression_method(CompressionMethod::Stored)
            .unix_permissions(0o755);

        let file = File::create(&new_archive_path).unwrap();
        let mut new_zip = zip::ZipWriter::new(file);

        // Loop over all of the files in the .docx archive
        for i in 0..archive.len() {
            let mut file_in_archive = archive.by_index(i).unwrap();
            let file_in_archive_name = &file_in_archive.name();
            if file_in_archive_name.to_string() == "word/document.xml" {
                let mut contents = String::new();
                file_in_archive.read_to_string(&mut contents).unwrap();
                let mut new_contents = contents.to_string();
                for value in values {
                    let (target, new_target) = value;
                    // Perform text replacement
                    new_contents = new_contents.replace(target, new_target);
                }
                new_zip.start_file("word/document.xml", options)?;
                new_zip.write_all(new_contents.as_bytes())?;
            } else {
                new_zip.start_file(file_in_archive_name.to_string(), options)?;
                let mut buffer = Vec::new();
                file_in_archive.read_to_end(&mut buffer)?;
                new_zip.write_all(&buffer)?;
            }
        }
        std::fs::rename(new_archive_path, docx_path).unwrap();
        Ok(())
    }
    pub fn docx_get_xml(docx_path: impl AsRef<str>) -> Result<String, Box<dyn std::error::Error>> {
        let reader = File::open(docx_path.as_ref())?;
        let mut zip = ZipArchive::new(reader)?;
        let mut file = zip.by_name("word/document.xml")?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(contents)
    }
    #[cfg(target_os = "unix")]
    pub fn docx_remove_read_only(
        docx_path: impl AsRef<str>,
    ) -> Result<(), Box<dyn std::error::Error>> {
        use std::fs::{metadata, set_permissions};
        use std::os::unix::fs::PermissionsExt;
        let docx_path = docx_path.as_ref();
        let meta = metadata(docx_path)?;
        let mut permissions = meta.permissions();
        let mode = permissions.mode();
        let new_mode = mode & !0o400;
        permissions.set_mode(new_mode);
        set_permissions(docx_path, permissions)?;
        Ok(())
    }

    pub fn parse_xml_get_content(xml: impl AsRef<str>) -> Vec<String> {
        use xml::reader::{EventReader, XmlEvent};
        let parser = EventReader::from_str(xml.as_ref());
        let mut content = vec![];
        for e in parser {
            match e {
                #[allow(warnings)]
                Ok(XmlEvent::StartElement { name, .. }) => {}
                #[allow(warnings)]
                Ok(XmlEvent::EndElement { name }) => {}
                Ok(XmlEvent::Characters(chars)) => {
                    content.push(chars);
                }
                Err(e) => {
                    println!("Error: {}", e);
                    break;
                }
                _ => {}
            }
        }
        content
    }
    pub fn docx_get_content(
        docx_path: impl AsRef<str>,
    ) -> Result<Vec<String>, Box<dyn std::error::Error>> {
        let xml = crate::docx::docx_get_xml(docx_path)?;
        Ok(crate::docx::parse_xml_get_content(xml))
    }
}

#[cfg(feature = "docx")]
pub use docx::*;
