use std::sync::Arc;
use super::*;

pub struct DocumentBuilder {
    pub(crate) document: Document,
}

impl DocumentBuilder {
    pub fn content(mut self, node: DocumentNode) -> Self {
        self.document.content.push(node);
        self
    }

    pub fn page_size(mut self, page_size: PageSize) -> Self {
        self.document.page_size = page_size;
        self
    }

    pub fn page_margins(mut self, page_margins: Margins) -> Self {
        self.document.page_margins = page_margins;
        self
    }

    pub fn default_style(mut self, style: Style) -> Self {
        self.document.default_style = style;
        self
    }

    pub fn style(mut self, name: impl Into<String>, style: Style) -> Self {
        self.document.styles.insert(name.into(), style);
        self
    }

    pub fn font(mut self, family: impl Into<String>, path: impl Into<String>) -> Self {
        self.document.fonts.insert(family.into(), FontSource::path(path));
        self
    }

    pub fn watermark(mut self, watermark: WatermarkConfig) -> Self {
        self.document.watermark = Some(watermark);
        self
    }

    pub fn background(mut self, node: DocumentNode) -> Self {
        self.document.background = Some(node);
        self
    }

    pub fn info(mut self, info: DocumentInfo) -> Self {
        self.document.info = Some(info);
        self
    }

    pub fn header(mut self, node: DocumentNode) -> Self {
        self.document.header = Some(HeaderFooter::from_static(node));
        self
    }

    pub fn header_fn<F>(mut self, f: F) -> Self
    where
        F: Fn(u32, u32, &PageSize) -> DocumentNode + Send + Sync + 'static,
    {
        self.document.header = Some(HeaderFooter::from_fn(f));
        self
    }

    pub fn footer(mut self, node: DocumentNode) -> Self {
        self.document.footer = Some(HeaderFooter::from_static(node));
        self
    }

    pub fn footer_fn<F>(mut self, f: F) -> Self
    where
        F: Fn(u32, u32, &PageSize) -> DocumentNode + Send + Sync + 'static,
    {
        self.document.footer = Some(HeaderFooter::from_fn(f));
        self
    }

    pub fn encryption(mut self, encryption: PdfEncryption) -> Self {
        self.document.encryption = Some(encryption);
        self
    }

    pub fn pdf_version(mut self, version: impl Into<String>) -> Self {
        self.document.pdf_version = Some(version.into());
        self
    }

    pub fn compress(mut self, value: bool) -> Self {
        self.document.compress = Some(value);
        self
    }

    pub fn language(mut self, lang: impl Into<String>) -> Self {
        self.document.language = Some(lang.into());
        self
    }

    pub fn max_pages(mut self, count: usize) -> Self {
        self.document.max_pages = Some(count);
        self
    }

    pub fn tagged(mut self, value: bool) -> Self {
        self.document.tagged = Some(value);
        self
    }

    pub fn named_dest(mut self, id: impl Into<String>, page_index: usize, x: f32, y: f32) -> Self {
        self.document.named_dests.push(NamedDest { id: id.into(), page_index, x, y });
        self
    }

    pub fn outline(mut self, id: impl Into<String>, text: impl Into<String>) -> Self {
        self.document.outlines.push(OutlineEntry { id: id.into(), text: text.into(), parent_id: None });
        self
    }

    pub fn outline_child(mut self, id: impl Into<String>, text: impl Into<String>, parent_id: impl Into<String>) -> Self {
        self.document.outlines.push(OutlineEntry { id: id.into(), text: text.into(), parent_id: Some(parent_id.into()) });
        self
    }

    pub fn attachment(mut self, name: impl Into<String>, data: Vec<u8>, mime_type: impl Into<String>) -> Self {
        self.document.attachments.push(Attachment { name: name.into(), data, mime_type: mime_type.into() });
        self
    }

    pub fn page_break_before(mut self, callback: impl Fn(&PageBreakInfo) -> bool + Send + Sync + 'static) -> Self {
        self.document.page_break_before = Some(PageBreakCallback(Arc::new(callback)));
        self
    }

    pub fn build(self) -> Document {
        self.document
    }
}
