use crate::{
    common::{self, IError, IResult},
    mobi::{builder::MobiBuilder, core::MobiAssets, image::get_attr_value},
    prelude::{EpubBook, EpubBuilder, EpubHtml, EpubNav, MobiBook, MobiHtml, MobiNav},
};

fn to_epub_nav(mobi: &MobiNav, parent: &str) -> EpubNav {
    let mut n = EpubNav::default();
    n = n.with_title(mobi.title());
    n = n.with_file_name(format!("{parent}{}.xhtml", mobi.title).as_str());

    for ele in mobi.child() {
        n.push(to_epub_nav(
            ele,
            format!("{parent}{}/", mobi.title()).as_str(),
        ));
    }

    n
}

/// 找到章节对应的目录
/// 返回多个层级所属目录
fn get_mobi_chapter_nav<'a>(chap: &MobiHtml, nav: &'a [MobiNav]) -> Option<Vec<&'a MobiNav>> {
    for ele in nav {
        if ele.id() == chap.nav_id() {
            return Some(vec![ele]);
        }
        if let Some(mut v) = get_mobi_chapter_nav(chap, ele.child().as_slice()) {
            v.insert(0, ele);
            return Some(v);
        }
    }
    None
}

fn get_mobi_assets_file_name(a: &MobiAssets) -> String {
    format!("image/{}", a.file_name())
}

/// mobi 转 epub
///
/// # Examples
/// ```no_run
/// use iepub::prelude::*;
/// use iepub::prelude::adapter::mobi_to_epub;
///
/// let mut book = std::fs::File::open(std::path::PathBuf::from("example.mobi"))
/// .map_err(|e| IError::Io(e))
/// .and_then(|f| MobiReader::new(f))
/// .and_then(|mut f| f.load())
/// .unwrap();
///
/// let mut epub = mobi_to_epub(&mut book).unwrap();
/// EpubWriter::write_to_mem(&mut epub, true).unwrap();
/// ```
pub fn mobi_to_epub(mobi: &mut MobiBook) -> IResult<EpubBook> {
    let mut builder = EpubBuilder::new();

    // 添加图片
    for ele in mobi.assets_mut() {
        builder = builder.add_assets(
            get_mobi_assets_file_name(ele).as_str(),
            ele.data().unwrap().to_vec(),
        );
    }

    // 添加目录
    for n in mobi.nav() {
        builder = builder.custome_nav(true);
        builder = builder.add_nav(to_epub_nav(n, ""));
    }

    let assets = mobi.assets().as_slice();
    // 添加文本
    for chap in mobi.chapters() {
        let nav: Vec<&str> = get_mobi_chapter_nav(chap, mobi.nav().as_slice())
            .unwrap()
            .iter()
            .map(|f| f.title())
            .collect();

        builder = builder.add_chapter(
            EpubHtml::default()
                .with_title(chap.title())
                .with_file_name(format!("{}.xhtml", nav.join("/")).as_str())
                .with_data(convert_mobi_html_data(
                    nav.len() - 1,
                    chap.string_data().as_str(),
                    assets,
                )),
        );
    }

    // 封面
    if let Some(cover) = mobi.cover() {
        builder = builder.cover(cover.file_name(), cover.data().unwrap().to_vec());
    }
    // 元数据
    builder = builder
        .with_title(mobi.title())
        .with_identifier(mobi.identifier());

    if let Some(v) = mobi.contributor() {
        builder = builder.with_contributor(v);
    }
    if let Some(v) = mobi.creator() {
        builder = builder.with_creator(v);
    }
    if let Some(v) = mobi.description() {
        builder = builder.with_description(v);
    }
    if let Some(v) = mobi.date() {
        builder = builder.with_date(v);
    }
    if let Some(v) = mobi.format() {
        builder = builder.with_format(v);
    }
    if let Some(v) = mobi.last_modify() {
        builder = builder.with_last_modify(v);
    }
    if let Some(v) = mobi.publisher() {
        builder = builder.with_publisher(v);
    }
    if let Some(v) = mobi.subject() {
        builder = builder.with_subject(v);
    }

    builder.book()
}

/// 转换 mobi 的 html 文本，主要是处理其中的img标签，添加src属性
fn convert_mobi_html_data(indent: usize, data: &str, assets: &[MobiAssets]) -> Vec<u8> {
    let mut v: String = data.to_string();
    let indent = (0..indent).map(|_| "../").collect::<Vec<&str>>().join("");
    for ele in assets {
        let target = format!(
            r#"src="{}{}""#,
            if indent.is_empty() {
                "./"
            } else {
                indent.as_str()
            },
            get_mobi_assets_file_name(ele)
        );
        // 还有层级问题
        // 有可能误伤，但是暂时没有更好的办法
        v = v
            .replace(
                format!("recindex=\"{:05}\"", ele.recindex).as_str(),
                target.as_str(),
            )
            .replace(
                format!("recindex='{:05}'", ele.recindex).as_str(),
                target.as_str(),
            )
            .replace(
                format!("recindex={:05}", ele.recindex).as_str(),
                target.as_str(),
            );
    }

    v.into_bytes()
}

fn epub_nav_to_mobi_nav(
    nav: std::slice::Iter<EpubNav>,
    start: usize,
    chap: &[(MobiHtml, String)],
) -> Vec<MobiNav> {
    let mut res = Vec::new();
    for ele in nav.enumerate() {
        let mut n = MobiNav::default(ele.0 + start).with_title(ele.1.title());

        // 关联章节
        if let Some(id) = chap
            .iter()
            .find(|(_, file)| file == ele.1.file_name())
            .map(|f| f.0.id)
        {
            n.chap_id = id;
        }

        if ele.1.child().len() > 0 {
            let c = epub_nav_to_mobi_nav(ele.1.child(), ele.0 + start + 1, chap);
            for ele1 in c {
                n.add_child(ele1);
            }
        }
        res.push(n);
    }
    res
}

/// 处理图片地址，把可能存在的相对路径换成绝对路径
fn convert_epub_html_img(html: &[u8], path: &str) -> Vec<u8> {
    let current = crate::path::Path::system(path).pop();
    let v = |v| {
        let path = String::from_utf8(v).unwrap_or_default();
        // 修正路径
        let t = current.join(path.as_str());
        format!("'{}'", t.to_str()).as_bytes().to_vec()
    };
    let html = generate_text_img_xml(html, "img", "src", v);
    generate_text_img_xml(html.as_slice(), "image", "xlink:href", v)
}

/// 修改xml片段中的img标签的src属性的路径
pub fn generate_text_img_xml<T: Fn(Vec<u8>) -> Vec<u8>>(
    html: &[u8],
    tag: &str,
    attr: &str,
    callback: T,
) -> Vec<u8> {
    let mut text = Vec::new();
    let mut index: usize = 0;
    let chars = html;
    let tag = format!("<{tag} ");
    let attr = format!(" {attr}=");
    let key = tag.as_bytes();

    while index < chars.len() {
        let mut now = chars[index];
        let mut j = 0;
        while j < key.len() {
            if now == key[j] {
                now = chars[index + j + 1];
            } else {
                break;
            }
            j += 1;
        }
        if j == key.len() {
            // 找到 img 标签，接下来查找 src 属性
            text.append(&mut key.to_vec());
            index += j;
            // 查找完后数据被分成三段，第一段 为开头到 src=，第二段是src=到value结束，第三段是value结束到之后
            // 第一段原样添加，第二段如果找到值替换recindex，没找到则原样添加，第三段继续循环

            let att = get_attr_value(&chars[index - 1..], &attr);
            if let Some(v) = att.0 {
                // 有src属性
                let start = att.1;
                for i in index..index + start {
                    text.push(chars[i]);
                }
                index += start;
                text.append(&mut attr.as_bytes()[1..].to_vec());
                text.append(&mut callback(v));
                let len = att.2;
                index += len - 1;

                continue;
            }

            for i in index..(index + att.1) {
                if i < chars.len() {
                    text.push(chars[i]);
                }
            }
            index += att.1;
        } else {
            text.push(chars[index]);
            index += 1;
        }
    }

    text
}

/// epub 转 mobi
///
/// # Examples
/// ```no_run
/// use iepub::prelude::*;
/// use iepub::prelude::adapter::epub_to_mobi;
/// use iepub::prelude::read_from_file;
///
/// let mut epub = read_from_file("example.epub").unwrap();
/// let mut mobi = epub_to_mobi(&mut epub).unwrap();
/// MobiWriter::new(std::fs::File::create("conver.mobi").unwrap())
/// .with_append_title(false)
/// .write(&mobi)
/// .unwrap();
/// ```
pub fn epub_to_mobi(epub: &mut EpubBook) -> IResult<MobiBook> {
    let mut builder = MobiBuilder::new()
        .with_title(epub.title())
        .with_identifier(epub.identifier());

    if let Some(v) = epub.contributor() {
        builder = builder.with_contributor(v);
    }
    if let Some(v) = epub.creator() {
        if v.contains(common::info::PROJECT_NAME) {
            builder = builder.with_creator(v);
        } else {
            builder = builder.with_creator(format!("{v} {}", common::info::PKG_NAME));
        }
    }
    if let Some(v) = epub.description() {
        builder = builder.with_description(v);
    }
    if let Some(v) = epub.date() {
        // 处理时间格式，2022-03-03 -> 2022-03-03T16:00:00+00:00
        if v.len() == 10 {
            builder = builder.with_date(format!("{v}T16:00:00+00:00"));
        } else {
            builder = builder.with_date(v);
        }
    }
    if let Some(v) = epub.format() {
        builder = builder.with_format(v);
    }
    if let Some(v) = epub.last_modify() {
        builder = builder.with_last_modify(v);
    }
    if let Some(v) = epub.publisher() {
        builder = builder.with_publisher(v);
    }
    if let Some(v) = epub.subject() {
        builder = builder.with_subject(v);
    }

    let chap = epub.chapters_mut();

    let chap_temp: Vec<(MobiHtml, String)> = chap
        .enumerate()
        .map(|(index, html)| {
            let file_name = html.file_name().to_string();
            (
                MobiHtml::new(index).with_title(html.title()).with_data(
                    html.data_mut()
                        .map(|v| convert_epub_html_img(v, file_name.as_str()))
                        // .unwrap_or_else(||Err(FromUtf8Error { bytes: Vec::n, error: e }))
                        .unwrap_or(Vec::new()),
                ),
                file_name,
            )
        })
        .collect();

    let nav = epub_nav_to_mobi_nav(epub.nav(), 0, &chap_temp);

    builder = builder.custome_nav(true);
    for ele in nav {
        builder = builder.add_nav(ele);
    }
    // 静态资源
    for ele in epub.assets_mut().filter(|f| f.file_name() != "toc.ncx") {
        let data = ele.data_mut().ok_or(IError::Unknown)?.to_vec();
        builder = builder.add_assets(ele.file_name(), data);
    }
    // 添加文本
    for (html, _) in chap_temp {
        builder = builder.add_chapter(html);
    }

    if let Some(c) = epub.cover_mut() {
        builder = builder.cover(c.data_mut().ok_or(IError::Unknown)?.to_vec());
    }

    builder.book()
}

pub mod concat {
    use crate::{
        common::{get_css_content_url, get_media_type, IResult},
        path,
        prelude::{EpubAssets, EpubBook, EpubBuilder, EpubHtml, EpubLink, EpubNav},
    };
    use std::collections::{HashMap, HashSet};

    use super::generate_text_img_xml;

    fn clone_epub_nav(
        nav: &EpubNav,
        new_file_name: &mut HashMap<String, String>,
        len: usize,
    ) -> (EpubNav, usize) {
        let mut len = len;
        let mut new_nav = EpubNav::default().with_title(nav.title());

        if let Some(nt) = new_file_name.get(nav.file_name()) {
            new_nav.set_file_name(nt.as_str());
        } else {
            let nt = format!("text/{:05}.xhtml", len);
            new_nav.set_file_name(nt.as_str());
            new_file_name.insert(nav.file_name().to_string(), nt);
            len += 1;
        }

        for ele in nav.child() {
            let (nav, l) = clone_epub_nav(ele, new_file_name, len);
            len += l;
            new_nav.push(nav);
        }
        (new_nav, len)
    }

    /// 替换html文本中的资源文件
    /// [data] html数据
    /// [asset_map] asset路径新旧映射
    /// [old_chapter_file] 章节文件旧目录
    /// [new_chapter_file] 章节文件新目录
    fn replace_html_assets(
        data: &[u8],
        asset_map: &HashMap<String, String>,
        old_chapter_file: String,
        new_chapter_file: &str,
    ) -> Vec<u8> {
        let callback = |v| {
            // 根据旧的src，转换成文件路径，再找到对应的新的文件路径，再转换成新的src
            String::from_utf8(v)
                .ok()
                .map(|f| {
                    path::Path::system(old_chapter_file.as_str())
                        .pop()
                        .join(f.as_str())
                        .to_str()
                })
                .and_then(|f| asset_map.get(f.as_str()))
                .map(|f| {
                    format!(
                        r#""{}""#,
                        crate::path::Path::system(new_chapter_file)
                            .pop()
                            .releative(f.as_str())
                    )
                    .as_bytes()
                    .to_vec()
                })
                .unwrap_or_default()
        };
        let data = generate_text_img_xml(data, "img", "src", callback);
        generate_text_img_xml(data.as_slice(), "image", "xlink:href", callback)
    }

    pub fn add_into_epub(
        builder: EpubBuilder,
        epub: &mut EpubBook,
        len: usize,
        asset_len: usize,
        skip: usize,
        parent_nav_title: Option<String>,
        exclude: &[String],
    ) -> IResult<(EpubBuilder, usize, usize)> {
        let mut len = len;
        let mut asset_len = asset_len;
        let mut builder = builder;
        let mut new_file_name = HashMap::new();
        let mut new_asset_file_name = HashMap::new();
        // 图片也要重新编号
        let mut assets = Vec::new();

        for ele in epub.assets_mut() {
            let me = get_media_type(ele.file_name());
            if me.is_empty() {
                continue;
            }
            let prefix = {
                if me.contains("image") {
                    "image"
                } else if me.contains("font") {
                    "font"
                } else if me.contains("css") {
                    "css"
                } else {
                    "other"
                }
            };
            let f = ele
                .data_mut()
                .map(|f| f.to_vec())
                .unwrap_or_else(|| panic!("{} not exist", ele.file_name()));
            asset_len += 1;

            let sufix = ele.file_name().find('.').unwrap_or(0);
            let sufix = &ele.file_name()[(sufix + 1)..];
            let nn = format!("{prefix}/{}.{}", asset_len, sufix);
            if me.contains("text/css") {
                assets.push(
                    EpubAssets::default()
                        .with_file_name(nn.as_str())
                        .with_data(f),
                );
            } else {
                builder = builder.add_assets(nn.as_str(), f);
            }
            new_asset_file_name.insert(ele.file_name().to_string(), nn);
        }

        // 替换css文件中的引用，因为asset 顺序不固定，所以只有读取完所有asset后再处理
        for mut ele in assets {
            if let Some(d) = ele.data_mut() {
                if let Ok(css) = String::from_utf8(d.to_vec()) {
                    let url = get_css_content_url(css.as_str());

                    let mut n_css = css.clone();
                    for u in url {
                        let old = crate::path::Path::system(ele.file_name())
                            .pop()
                            .join(u)
                            .to_str();
                        if let Some(new_filename) = new_asset_file_name.get(old.as_str()) {
                            n_css = n_css.replace(
                                u,
                                crate::path::Path::system(ele.file_name())
                                    .releative(new_filename.as_str())
                                    .as_str(),
                            );
                        }
                    }
                    builder = builder.add_assets(ele.file_name(), n_css.as_bytes().to_vec());
                }
            }
        }

        let mut rm = HashSet::new();
        let mut new_nav = Vec::new();
        // 文件名需要重新编号，所以目录也要变一下
        for (index, ele) in epub.nav().enumerate() {
            let (nav, l) = clone_epub_nav(ele, &mut new_file_name, len);
            len = l;
            if index < skip || exclude.contains(&ele.title().to_string()) {
                rm.insert(ele.file_name().to_string());
                continue;
            }
            new_nav.push(nav);
        }
        // len += 1;
        if let Some(cc) = epub.cover_chapter() {
            // 文件名编号在后面，但是目录里在前面
            let (nav, l) = clone_epub_nav(
                &EpubNav::default()
                    .with_file_name(cc.file_name())
                    .with_title(cc.title()),
                &mut new_file_name,
                len,
            );

            len = l;
            new_nav.insert(0, nav);
        } else if let Some(cc) = epub.cover() {
            // 只有封面
            let (nav, l) = clone_epub_nav(
                &EpubNav::default()
                    .with_file_name(format!("{}.xhtml", cc.file_name()))
                    .with_title("封面"),
                &mut new_file_name,
                len,
            );
            len = l;
            new_nav.insert(0, nav);
        }

        if !new_nav.is_empty() {
            if let Some(t) = &parent_nav_title {
                let mut v = EpubNav::default()
                    .with_file_name(new_nav[0].file_name())
                    .with_title(t);
                for ele in new_nav {
                    v.push(ele);
                }
                builder = builder.add_nav(v);
            } else {
                for ele in new_nav {
                    builder = builder.add_nav(ele);
                }
            }
        }

        // 添加一个封面页
        if let Some(cc) = epub.cover_chapter() {
            if let Some(nf) = new_file_name.get(cc.file_name()) {
                epub.insert_chapter(0, cc.clone().with_file_name(nf));
                len += 1;
            }
        } else if let Some(cover) = epub.cover() {
            let old = format!("{}.xhtml", cover.file_name());
            let nc = crate::path::Path::system(old.as_str())
                .pop()
                .releative(cover.file_name());
            epub.insert_chapter(
                0,
                EpubHtml::default()
                    .with_file_name(old.as_str())
                    .with_title("封面")
                    .with_data(
                        format!(
                            r#"<div style="width:100%;text-align:center;"><img src="{}"/></div>"#,
                            nc
                        )
                        .as_bytes()
                        .to_vec(),
                    ),
            );
            len += 1;
        }

        for ele in epub.chapters_mut() {
            if rm.contains(ele.file_name()) {
                continue;
            }
            let old = ele.file_name().to_string();
            let v = if let Some(v) = new_file_name.get(ele.file_name()) {
                v.to_string()
            } else {
                len += 1;
                format!("text/{:05}.xhtml", len)
            };

            let mut new_html = EpubHtml::default()
                .with_file_name(v.as_str())
                .with_title(ele.title())
                .with_data(replace_html_assets(
                    ele.data_mut().unwrap(),
                    &new_asset_file_name,
                    old.to_string(),
                    v.as_str(),
                ));
            new_html.body_attribute = ele.body_attribute.clone();

            for ele in ele.links().unwrap_or_default() {
                // link 也需要调整引用路径
                let link_ab = path::Path::system(old.as_str())
                    .pop()
                    .join(ele.href.as_str())
                    .to_str();
                if let Some(n) = new_asset_file_name.get(link_ab.as_str()) {
                    // 替换路径
                    new_html.add_link(EpubLink {
                        rel: ele.rel.clone(),
                        file_type: ele.file_type.clone(),
                        href: crate::path::Path::system(v.as_str())
                            .pop()
                            .releative(n.as_str()),
                    });
                }
            }
            if let Some(css) = ele.css() {
                new_html.set_css(css);
            }
            builder = builder.add_chapter(new_html);
        }

        Ok((builder, len, asset_len))
    }

    #[cfg(test)]
    mod tests {
        use std::collections::HashMap;

        use crate::prelude::{adapter::add_into_epub, EpubBuilder, EpubHtml, EpubNav};

        use super::replace_html_assets;

        #[test]
        fn test_replace_html_img_src() {
            let asset_map = HashMap::from([("2.png".to_string(), "384.png".to_string())]);
            let old_chapter_file = "3.xhtml";
            let new_chapter_file = "n.xhtml";
            let html = r#"<p>测试<img src="2.png"></p>"#;
            let res = replace_html_assets(
                html.as_bytes(),
                &asset_map,
                old_chapter_file.to_string(),
                new_chapter_file,
            );
            assert_eq!(
                r#"<p>测试<img src="384.png"></p>"#,
                String::from_utf8(res).unwrap().as_str()
            );
        }

        #[test]
        fn concat_epub() {
            let mut nav = EpubNav::default()
                .with_title("1.")
                .with_file_name("1/1.xhtml");
            nav.push(
                EpubNav::default()
                    .with_title("1.1")
                    .with_file_name("1/1.xhtml"),
            );
            let mut builder = EpubBuilder::new()
                .custome_nav(true)
                .with_title("测试合并")
                .with_creator("作者")
                .add_nav(nav)
                .add_nav(
                    EpubNav::default()
                        .with_title("2.")
                        .with_file_name("1/2.xhtml"),
                )
                .add_chapter(
                    EpubHtml::default()
                        .with_file_name("1/1.xhtml")
                        .with_title("1.")
                        .with_data(b"<p>1.</p>".to_vec()),
                )
                .add_chapter(
                    EpubHtml::default()
                        .with_file_name("1/2.xhtml")
                        .with_title("2.")
                        .with_data(b"<p>2.</p>".to_vec()),
                );
            let mut book1 = builder.book().unwrap();
            // book2
            let mut nav = EpubNav::default()
                .with_title("3.")
                .with_file_name("2/1.xhtml");
            nav.push(
                EpubNav::default()
                    .with_title("3.1")
                    .with_file_name("2/1.xhtml"),
            );
            let mut builder = EpubBuilder::new()
                .custome_nav(true)
                .with_title("测试合并2")
                .with_creator("作者2")
                .add_nav(nav)
                .add_nav(
                    EpubNav::default()
                        .with_title("3.")
                        .with_file_name("2/2.xhtml"),
                )
                .add_chapter(
                    EpubHtml::default()
                        .with_file_name("2/1.xhtml")
                        .with_title("333.")
                        .with_data(b"<p>333.</p>".to_vec()),
                )
                .add_chapter(
                    EpubHtml::default()
                        .with_file_name("2/2.xhtml")
                        .with_title("2.")
                        .with_data(b"<p>2.</p>".to_vec()),
                );
            let mut book2 = builder.book().unwrap();

            let mut builder = EpubBuilder::default();
            let (mut builder, len, a_len) =
                add_into_epub(builder, &mut book1, 0, 0, 0, None, &[]).unwrap();

            let (mut builder, len, a_len) =
                add_into_epub(builder, &mut book2, len, a_len, 0, None, &[]).unwrap();

            let b = builder.book().unwrap();

            println!("{:?}", b.nav());
            println!("{:?}", b.chapters());

            assert_eq!(
                b.nav().as_slice()[0].file_name(),
                b.chapters().next().unwrap().file_name()
            );
        }
    }
}
#[cfg(test)]
mod tests {
    use super::{convert_mobi_html_data, epub_to_mobi, mobi_to_epub};
    use crate::{
        adapter::core::convert_epub_html_img,
        common::IError,
        mobi::core::MobiAssets,
        prelude::{EpubBuilder, EpubHtml, EpubWriter, MobiReader, MobiWriter},
    };

    #[test]
    #[ignore = "dan.mobi"]
    fn test_convert() {
        let mut book = std::env::current_dir()
            .ok()
            .map(|f| f.join("../dan.mobi"))
            .map_or(Err(std::io::Error::other("error")), |f| {
                std::fs::File::open(f)
            })
            .map_err(|_| IError::Unknown)
            .and_then(|f| MobiReader::new(f))
            .and_then(|mut f| f.load())
            .unwrap();

        let mut epub = mobi_to_epub(&mut book).unwrap();
        EpubWriter::write_to_mem(&mut epub, true).unwrap();
        // epub.write("convert.epub").unwrap();
    }

    #[test]
    #[cfg(feature = "no_nav")]
    fn test_convert_no_nav() {
        use crate::common::tests::download_zip_file;
        let name = "convert.mobi";

        let mut mobi = MobiReader::new(
            std::fs::File::open(download_zip_file(
                name,
                "https://github.com/user-attachments/files/18818424/convert.mobi.zip",
            ))
            .unwrap(),
        )
        .unwrap();

        let mut book = mobi.load().unwrap();

        assert_eq!(188, book.chapters().len());
        let mut epub = mobi_to_epub(&mut book).unwrap();

        assert_eq!(188, epub.chapters().len());
        assert_eq!(Some("1"), epub.chapters().next().map(|f| f.title()));

        EpubWriter::write_to_mem(&mut epub, false).unwrap();
    }

    #[test]
    fn test_epub_to_mobi() {
        let img = crate::common::tests::get_req_mem(
            "https://www.rust-lang.org/static/images/user-logos/yelp.png",
        );
        let img2 = crate::common::tests::get_req_mem("https://blog.rust-lang.org/images/2024-05-17-enabling-rust-lld-on-linux/ripgrep-comparison.png");

        let mut epub = EpubBuilder::default()
            .with_title("书名")
            .with_creator("作者")
            .with_date("2024-03-14")
            .with_description("一本好书")
            .with_identifier("isbn")
            .with_publisher("行星出版社")
            .add_chapter(
                EpubHtml::default()
                    .with_title("测试标题")
                    .with_file_name("1/0.xhtml")
                    .with_data(
                        "<p>锻炼</p><img src='../1.jpg'/>"
                            .to_string()
                            .as_bytes()
                            .to_vec(),
                    ),
            )
            .add_assets("1.jpg", img.clone())
            .cover("cover.jpg", img2.clone())
            .book()
            .unwrap();

        let mobi = epub_to_mobi(&mut epub).unwrap();
        let mut v = std::io::Cursor::new(Vec::new());
        MobiWriter::new(&mut v)
            .with_append_title(false)
            .write(&mobi)
            .unwrap();

        let n_mobi = MobiReader::new(&mut v).unwrap().load().unwrap();

        assert_eq!(epub.title(), n_mobi.title());
        assert_eq!(epub.description(), n_mobi.description());

        assert_eq!(epub.chapters().len(), mobi.chapters().len());
        assert_eq!(epub.chapters().len(), n_mobi.chapters().len());
        assert_eq!(epub.assets().len(), n_mobi.assets().len());
    }

    #[test]
    fn test_convert_html_img() {
        let data = r#"<h1>插图</h1>
<p height="1em" width="0pt" align="center"><font size="7"><b>第六卷</b></font></p><p height="1em" width="0pt" align="center"><font size="6"><b>插图</b></font></p><p height="1em" width="0pt"> <img recindex="00055" align="baseline" width="1086" height="1526"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129720.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00018" align="baseline" width="600" height="800"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129721.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00056" align="baseline" width="600" height="800"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129722.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00019" align="baseline" width="580" height="799"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129723.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00061" align="baseline" width="800" height="600"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129724.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00024" align="baseline" width="759" height="451"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129725.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00062" align="baseline" width="800" height="600"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129726.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00025" align="baseline" width="600" height="800"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129727.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00063" align="baseline" width="500" height="666"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129728.jpg"> </a> </p>"#;

        let assets = vec![
            MobiAssets {
                _file_name: "1.jpg".to_string(),
                media_type: String::new(),
                _data: None,
                recindex: 55,
            },
            MobiAssets {
                _file_name: "2.jpg".to_string(),
                media_type: String::new(),
                _data: None,
                recindex: 56,
            },
        ];

        let r = convert_mobi_html_data(2, data, &assets);

        assert_eq!(
            String::from_utf8(r).unwrap(),
            r#"<h1>插图</h1>
<p height="1em" width="0pt" align="center"><font size="7"><b>第六卷</b></font></p><p height="1em" width="0pt" align="center"><font size="6"><b>插图</b></font></p><p height="1em" width="0pt"> <img src="../../image/1.jpg" align="baseline" width="1086" height="1526"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129720.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00018" align="baseline" width="600" height="800"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129721.jpg"> </a> </p><p height="3pt" width="0pt"> <img src="../../image/2.jpg" align="baseline" width="600" height="800"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129722.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00019" align="baseline" width="580" height="799"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129723.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00061" align="baseline" width="800" height="600"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129724.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00024" align="baseline" width="759" height="451"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129725.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00062" align="baseline" width="800" height="600"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129726.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00025" align="baseline" width="600" height="800"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129727.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00063" align="baseline" width="500" height="666"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129728.jpg"> </a> </p>"#
        );

        let r = convert_mobi_html_data(0, data, &assets);

        assert_eq!(
            String::from_utf8(r).unwrap(),
            r#"<h1>插图</h1>
<p height="1em" width="0pt" align="center"><font size="7"><b>第六卷</b></font></p><p height="1em" width="0pt" align="center"><font size="6"><b>插图</b></font></p><p height="1em" width="0pt"> <img src="./image/1.jpg" align="baseline" width="1086" height="1526"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129720.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00018" align="baseline" width="600" height="800"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129721.jpg"> </a> </p><p height="3pt" width="0pt"> <img src="./image/2.jpg" align="baseline" width="600" height="800"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129722.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00019" align="baseline" width="580" height="799"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129723.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00061" align="baseline" width="800" height="600"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129724.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00024" align="baseline" width="759" height="451"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129725.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00062" align="baseline" width="800" height="600"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129726.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00025" align="baseline" width="600" height="800"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129727.jpg"> </a> </p><p height="3pt" width="0pt"> <img recindex="00063" align="baseline" width="500" height="666"></img><a href="https://pic.wenku8.com/pictures/1/1946/105571/129728.jpg"> </a> </p>"#
        );
    }

    #[test]
    fn test_convert_epub_html_img() {
        // let html = r#"<img src="../ok.jpg"/>"#;
        // let v = convert_epub_html_img(html.to_string(), "/parent1/parent.xhtml");

        // println!("{}", v);

        // let html = r#"<img data-src="3.jpg" src="../ok.jpg"/>"#;
        // let v = convert_epub_html_img(html.to_string(), "/parent1/parent.xhtml");

        // println!("{}", v);

        // let html = r#" class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86275.jpg' src="../temp/2356/images/www.bilinovel.com/2356/0/86275.jpg"/><img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86276.jpg' src="../temp/2356/images/www.bilinovel.com/2356/0/86276.jpg"/><img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86277.jpg' src="../temp/2356/images/www.bilinovel.com/2356/0/86277.jpg"/><img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86278.jpg' src="../temp/2356/images/www.bilinovel.com/2356/0/86278.jpg"/><img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86279.jpg' src="../temp/2356/images/www.bilinovel.com/2356/0/86279.jpg"/>"#;
        //         let v = get_attr_value(html.as_bytes().to_vec().as_slice(), " src=");

        //         assert_ne!(None,v.0);
        //         assert_eq!(91,v.1);

        let html = r#"<img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86275.jpg' src="../temp/2356/images/www.bilinovel.com/2356/0/86275.jpg"/><img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86276.jpg' src="../temp/2356/images/www.bilinovel.com/2356/0/86276.jpg"/><img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86277.jpg' src="../temp/2356/images/www.bilinovel.com/2356/0/86277.jpg"/><img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86278.jpg' src="../temp/2356/images/www.bilinovel.com/2356/0/86278.jpg"/><img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86279.jpg' src="../temp/2356/images/www.bilinovel.com/2356/0/86279.jpg"/>
</div>
  </body></html>"#;
        let v = convert_epub_html_img(html.as_bytes(), "/parent1/parent.xhtml");

        println!("{}", String::from_utf8(v.clone()).unwrap());
        assert_eq!(
            r#"<img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86275.jpg' src='/temp/2356/images/www.bilinovel.com/2356/0/86275.jpg'/><img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86276.jpg' src='/temp/2356/images/www.bilinovel.com/2356/0/86276.jpg'/><img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86277.jpg' src='/temp/2356/images/www.bilinovel.com/2356/0/86277.jpg'/><img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86278.jpg' src='/temp/2356/images/www.bilinovel.com/2356/0/86278.jpg'/><img class="imagecontent lazyload" data-src='https://img3.readpai.com/2/2356/121744/86279.jpg' src='/temp/2356/images/www.bilinovel.com/2356/0/86279.jpg'/>
</div>
  </body></html>"#,
            String::from_utf8(v).unwrap()
        );
    }
}
