'use strict';

var index = require('./node_modules/fs-extra/lib/index.js');
var dimension = require('./design/dimension.js');
var palette = require('./design/palette.js');
var FirstPageHeader = require('./internal/component/PageHeader/FirstPageHeader.js');
var OtherPageHeader = require('./internal/component/PageHeader/OtherPageHeader.js');
var SolutionPageHeader = require('./internal/component/PageHeader/SolutionPageHeader.js');
var ProblemItem = require('./internal/component/ProblemItem/ProblemItem.js');
var SolutionItem = require('./internal/component/SolutionItem/SolutionItem.js');
var Doc = require('./internal/util/Doc.js');
var EnvUtil = require('./internal/util/EnvUtil.js');
var ImageUtil = require('./internal/util/ImageUtil.js');
var Logger = require('./internal/util/Logger.js');
var ProblemRenderer = require('./internal/util/ProblemRenderer.js');
var ThemeUtil = require('./internal/util/ThemeUtil.js');
var WritableBufferStream = require('./internal/util/WritableBufferStream.js');

async function createExamPdf(params) {
    const stream = new WritableBufferStream.WritableBufferStream({});
    Doc.Doc.init({ params });
    Doc.Doc.get().pipe(stream);
    // pre download all images to buffer
    Logger.logger.info('start problem & solution image pre-download');
    await Promise.all([...params.problems.flatMap((p) => p.images), ...params.solutions.flatMap((p) => p.images)].map(async (url) => {
        await ImageUtil.ImageUtil.downloadAndSaveToStorage(url);
        Logger.logger.info(`image download complete [${url}]`);
    }));
    if (params.logoUrl) {
        await ImageUtil.ImageUtil.downloadAndSaveToStorage(params.logoUrl);
    }
    Logger.logger.info('end problem image pre-download');
    // 문제 생성
    if (params.problems.length) {
        Logger.logger.info('start problem arrange, rendering');
        await ProblemRenderer.ProblemRenderer.renderProblems({
            problemLayout: params.problemLayout,
            problemImages: params.problems.map((p) => p.images),
            componentHeaderHeight: dimension.ProblemDimension.problemHeaderHeight,
            renderComponent: async ({ imageSegments, segmentStartAt, offsetX, index, offsetY }) => {
                const problem = params.problems[index];
                await Doc.Doc.renderComponent(ProblemItem.ProblemItem({
                    index,
                    color: ['t2'].includes(params.pdfTemplate)
                        ? palette.default.gray900
                        : ThemeUtil.ThemeUtil.getDefaultColor(params.theme),
                    imageSegments,
                    offsetX,
                    offsetY,
                    segmentStartAt,
                    difficulty: problem.difficulty,
                    subtext: problem.subtext,
                }));
            },
            onAddPage: async ({ isFirstPage }) => {
                await Doc.Doc.addPage({
                    color: ['t2'].includes(params.pdfTemplate) ? palette.default.gray900 : palette.default.gray200,
                    withHeaderDivider: ['t1', 't2', 't3'].includes(params.pdfTemplate) ? true : false,
                }, {
                    logo: ImageUtil.ImageUtil.getFromStorage(params.logoUrl)?.buffer,
                });
                if (isFirstPage) {
                    await Doc.Doc.renderComponent(FirstPageHeader.FirstPageHeader({
                        title: params.title,
                        description: params.description,
                        titleTag: params.titleTag,
                        color: ThemeUtil.ThemeUtil.getDefaultColor(params.theme),
                        pdfTemplate: params.pdfTemplate,
                    }));
                }
                else {
                    await Doc.Doc.renderComponent(OtherPageHeader.OtherPageHeader({
                        title: params.title,
                        description: params.description,
                        color: ThemeUtil.ThemeUtil.getDefaultColor(params.theme),
                        pdfTemplate: params.pdfTemplate,
                    }));
                }
            },
        });
        Logger.logger.info('end problem arrange, rendering');
    }
    // 해설 생성
    if (params.solutions.length) {
        Logger.logger.info('start solution arrange, rendering');
        await ProblemRenderer.ProblemRenderer.renderProblems({
            problemLayout: 'h2-free',
            problemImages: params.solutions.map((p) => p.images),
            componentHeaderHeight: dimension.ProblemDimension.problemHeaderHeight,
            renderComponent: async ({ imageSegments, segmentStartAt, offsetX, index, offsetY }) => {
                const solution = params.solutions[index];
                await Doc.Doc.renderComponent(SolutionItem.SolutionItem({
                    index,
                    colorSet: ['t2'].includes(params.pdfTemplate)
                        ? [palette.default.gray900, palette.default.gray900]
                        : [ThemeUtil.ThemeUtil.getDefaultColor(params.theme), ThemeUtil.ThemeUtil.getBoldColor(params.theme)],
                    imageSegments,
                    offsetX,
                    offsetY,
                    segmentStartAt,
                    answer: solution.answer,
                }));
            },
            onAddPage: async () => {
                await Doc.Doc.addPage({
                    color: ['t2'].includes(params.pdfTemplate) ? palette.default.gray900 : palette.default.gray200,
                    withHeaderDivider: ['t1', 't2', 't3'].includes(params.pdfTemplate) ? true : false,
                }, {
                    logo: ImageUtil.ImageUtil.getFromStorage(params.logoUrl)?.buffer,
                });
                await Doc.Doc.renderComponent(SolutionPageHeader.SolutionPageHeader({
                    title: '정답과 풀이',
                    description: params.description,
                    color: ThemeUtil.ThemeUtil.getDefaultColor(params.theme),
                    pdfTemplate: params.pdfTemplate,
                }));
            },
        });
        Logger.logger.info('end solution arrange, rendering');
    }
    Doc.Doc.end();
    ImageUtil.ImageUtil.clearStorage();
    const buffer = await WritableBufferStream.streamToPromise(stream);
    if (EnvUtil.isDev) {
        index.writeFileSync('test/output.pdf', buffer);
    }
    return buffer;
}

exports.createExamPdf = createExamPdf;
