import zipLib, { JSZip } from '../../epubtpl-lib/zip';
import { compileTpl, Handlebars } from '../../epubtpl-lib/handlebar-helpers';
import { fetchFile } from '../../epubtpl-lib/ajax';
import { compileCss } from '../../epubtpl-lib/postcss';
import path from 'upath2';
import { IBuilder } from '../../var';
import { EpubMaker } from '../../index';
import { BPromise, shortid } from '../../lib/util';
import { EnumEpubConfigVertical } from '../../config';

export const EPUB_TEMPLATES_PATH = path.join(__dirname) as string;
export const EPUB_TEMPLATES_TPL = path.join(EPUB_TEMPLATES_PATH, 'tpl') as string;

declare module '../../index'
{
	namespace EpubMaker
	{
		interface Section
		{
			needPage: boolean;
			name: string;

			rank: number | string;
		}
	}
}

export namespace Builder
{
	export let templates = {
		//mimetype: 'mimetype',
		//container: 'META-INF/container.xml',
		opf: 'EPUB/content.opf',
		ncx: 'EPUB/toc.ncx',
		nav: 'EPUB/nav.xhtml',
		css: 'EPUB/css/main.css',
		content: 'EPUB/content.xhtml',
		autoToc: 'EPUB/auto-toc.xhtml',
		sectionsNavTemplate: 'EPUB/sections-nav-template.html',
		sectionsNCXTemplate: 'EPUB/sections-ncx-template.xml',
		sectionsOPFManifestTemplate: 'EPUB/sections-opf-manifest-template.xml',
		sectionsOPFSpineTemplate: 'EPUB/sections-opf-spine-template.xml',

		coverPage: 'EPUB/CoverPage.xhtml',
		tableOfContents: 'EPUB/TableOfContents.xhtml',

		sectionsInfo: 'EPUB/sections-info.html',
		sectionsScript: 'EPUB/sections-script.html',

		contents: 'EPUB/contents.xhtml',
	};

	for (let i in templates)
	{
		templates[i] = `\{\{import \'${path.join(EPUB_TEMPLATES_TPL, templates[i])}'\}\}`;
	}

	let playOrder = 0;

	export let staticFiles = {
		'mimetype': 'mimetype',
		'META-INF/container.xml': 'META-INF/container.xml',
	};

	for (let i in staticFiles)
	{
		staticFiles[i] = path.join(EPUB_TEMPLATES_TPL, staticFiles[i]);
	}

	export function make(epub: EpubMaker, options?): BPromise<JSZip>
	{
		//let epubConfig = epub.epubConfig;

		options = Object.assign({}, {
			templates: templates,
		}, options);

		//console.debug('[building epub]', epub.epubConfig);
		//console.debug('[building epub]', options);
		let zip = new JSZip();

		//await addAditionalInfo(zip, epub, options);

		Handlebars.registerPartial('sectionsInfo', options.templates.sectionsInfo);
		Handlebars.registerPartial('sectionsScript', options.templates.sectionsScript);

		return BPromise
			.mapSeries([
				addStaticFiles,

				addAditionalInfo,

				//zipLib.addMimetype,
				//zipLib.addContainerInfo,
				addCover,

				zipLib.addFiles,

				addStylesheets,
				addManifestOpf,
				addEpub2Nav,
				addEpub3Nav,
				addContent,

				tableOfContents,
			], async function (fn, index)
			{
				if (fn === zipLib.addFiles)
				{
					return (fn as typeof zipLib.addFiles)(zip, epub, options)
						.then(function (ls)
						{
							return ls;
						})
						;
				}

				return fn(zip, epub, options);
			})
			.tap(function ()
			{
				//console.log(epub.epubConfig.cover);
			})
			.then(function ()
			{
				return zip;
			})
			//.catch(err => console.log(err))
			;
	}

	export function addStaticFiles(zip, epub: EpubMaker, options)
	{
		let ls = Object.keys(staticFiles).reduce(function (a, key)
		{
			let b = {
				name: key,
				ext: '',
				file: staticFiles[key],
			};

			a.push(b);

			return a;
		}, []);

		return zipLib.addStaticFiles(zip, ls);
	}

	export async function tableOfContents(zip, epub: EpubMaker, options)
	{
		zip
			.folder('EPUB')
			.file('TableOfContents.xhtml', compileTpl(options.templates.tableOfContents, epub.epubConfig))
		;

		zip
			.folder('EPUB')
			.file('contents.xhtml', compileTpl(options.templates.contents, epub.epubConfig))
		;
	}

	export async function addCover(zip, epub: EpubMaker, options)
	{
		let bool = await zipLib.addCover(zip, epub, options);

		if (bool)
		{
			zip
				.folder('EPUB')
				.file('CoverPage.xhtml', compileTpl(options.templates.coverPage, epub.epubConfig))
			;
		}
		else
		{
			epub.epubConfig.cover = null;
		}
	}

	export function addInfoSection(section, titlePrefix?, namePrefix?)
	{
		let c = '_';

		if (!section.content)
		{
			section.content = {};
		}
		if (titlePrefix)
		{
			titlePrefix = section.content.fullTitle = titlePrefix + ' - ' + section.content.title;
			namePrefix = section.name = namePrefix + c + section.rank;
		}
		else
		{
			titlePrefix = section.content.fullTitle = section.content.title;
			namePrefix = section.name = section.rank;
		}
		if (section.content.content || section.content.renderTitle || section.epubType == 'auto-toc')
		{
			section.needPage = true;
		}

		section.playOrder = playOrder++;

		if (!section.id)
		{
			section.id = (section.epubType || '').toString().replace('/\W/g', '') + shortid();
		}

		for (let i = 0; i < section.subSections.length; i++)
		{
			section.subSections[i].rank = i.toString().padStart(3, '0');
			addInfoSection(section.subSections[i], titlePrefix, namePrefix);
		}
	}

	export function addAditionalInfo(zip, epub: EpubMaker, options)
	{
		//Default options
		// @ts-ignore
		epub.epubConfig.options.tocName = epub.epubConfig.options.tocName || 'Menu';
		//Generate name and full title for each section/subsection
		for (let i = 0; i < epub.epubConfig.sections.length; i++)
		{
			epub.epubConfig.sections[i].rank = i.toString().padStart(3, '0');
			addInfoSection(epub.epubConfig.sections[i]);
		}
	}

	export function addManifestOpf(zip, epub: EpubMaker, options)
	{
		Handlebars.registerPartial('sectionsOPFManifestTemplate', options.templates.sectionsOPFManifestTemplate);
		Handlebars.registerPartial('sectionsOPFSpineTemplate', options.templates.sectionsOPFSpineTemplate);

		zip.folder('EPUB').file('content.opf', compileTpl(options.templates.opf, epub.epubConfig));
	}

	export function addEpub2Nav(zip, epub: EpubMaker, options)
	{
		Handlebars.registerPartial('sectionsNCXTemplate', options.templates.sectionsNCXTemplate);
		zip.folder('EPUB').file('toc.ncx', compileTpl(options.templates.ncx, epub.epubConfig));
	}

	export function addEpub3Nav(zip, epub: EpubMaker, options)
	{
		Handlebars.registerPartial('sectionsNavTemplate', options.templates.sectionsNavTemplate);
		zip.folder('EPUB').file('nav.xhtml', compileTpl(options.templates.nav, epub.epubConfig));
	}

	export async function addStylesheets(zip, epub: EpubMaker, options)
	{
		if (epub.epubConfig.vertical === EnumEpubConfigVertical.VERTICAL_RL)
		{
			try
			{
				const fs = require('fs') as typeof import('fs');

				let data = fs.readFileSync(path.join(__dirname, './tpl/EPUB/css/vertical-rl.css'));

				let file = await fetchFile({
					data,
				});

				epub.epubConfig.stylesheet.styles += "\n" + file.data.toString();
			}
			catch (e)
			{
				console.error(e);
			}
		}

		if (epub.epubConfig.stylesheet.url || epub.epubConfig.stylesheet.file)
		{
			let file = await fetchFile(epub.epubConfig.stylesheet);

			epub.epubConfig.stylesheet.styles += "\n" + file.data.toString();
		}

		return compileAndAddCss();

		async function compileAndAddCss()
		{
			let styles = {
				original: epub.epubConfig.stylesheet.replaceOriginal ? '' : options.templates.css,
				custom: epub.epubConfig.stylesheet.styles || '',
			};

			let css = await compileTpl(`${styles.original}\n${styles.custom}`, styles, true);

			css = await compileCss(css);

			return zip.folder('EPUB')
				.folder('css')
				.file('main.css', css)
				;
		}
	}

	export function addSection(zip: JSZip, section: EpubMaker.Section, epub: EpubMaker, options)
	{
		return zipLib.addSubSections(zip, section, function (zip, section, epubConfig, options)
		{
			if (section.needPage)
			{
				let name = section.name + '.xhtml';

				if (section.epubType == 'auto-toc')
				{
					return zip
						.folder('EPUB')
						.file(name, compileTpl(options.templates.autoToc, section))
						;
				}
				else
				{
					return zip
						.folder('EPUB')
						.file(name, compileTpl(options.templates.content, section))
						;
				}
			}

			return false;
		}, epub, options);
	}

	export function addContent(zip, epub: EpubMaker, options)
	{
		return BPromise.mapSeries(epub.epubConfig.sections, function (section)
		{
			return addSection(zip, section, epub, options);
		});
	}
}

// @ts-ignore
export const builder = Builder as IBuilder;
export default builder as IBuilder;

/*
if (typeof window !== 'undefined')
{
	// @ts-ignore
	window.epubMaker = builder;
}
*/

