import { Authorized, Body, JsonController, Post, QueryParam, Res } from 'routing-controllers';
import { OpenAPI } from 'routing-controllers-openapi';
import { CertificateRunner } from '../models/CertificateRunner';
import { Runner } from '../models/Runner';
import { RunnerCard } from '../models/RunnerCard';
import { PdfCreator } from '../PdfCreator';

/**
 * The pdf controller handels all endpoints concerning pdf generation.
 * It therefore is the hearth of the document-generation server's endpoints.
 * All endpoints have to accept a locale query-param to support i18n. 
 */
@JsonController()
@Authorized()
@OpenAPI({ security: [{ "AuthToken": [] }] })
export class PdfController {
    private pdf: PdfCreator = new PdfCreator();
    private initialized: boolean = false;

    @Post('/contracts')
    @OpenAPI({ description: "Generate Sponsoring contract pdfs from runner objects.<br>You can choose your prefered locale by passing the 'locale' query-param.<br> If you provide more than 100 runenrs this could take a moment or two (we tested up to 1000 runners in about 70sec so far)." })
    async generateContracts(@Body({ validate: true, options: { limit: "500mb" } }) runners: Runner[], @Res() res: any, @QueryParam("locale") locale: string, @QueryParam("codeformat") codeformat: string, @QueryParam("download") download: boolean) {
        if (!this.initialized) {
            await this.pdf.init();
            this.initialized = true;
        }
        if (!Array.isArray(runners)) {
            runners = [runners];
        }
        runners = this.mapRunnerGroupNames(runners)
        const contracts = await this.pdf.generateSponsoringContract(runners, locale, codeformat);
        res.setHeader('content-type', 'application/pdf');
        if (download) {
            res.setHeader('Content-Disposition', 'attachment; filename="contracts.pdf"')
        }
        return contracts;
    }

    @Post('/cards')
    @OpenAPI({ description: "Generate runner card pdfs from runner card objects.<br>You can choose your prefered locale by passing the 'locale' query-param." })
    async generateCards(@Body({ validate: true, options: { limit: "500mb" } }) cards: RunnerCard | RunnerCard[], @Res() res: any, @QueryParam("locale") locale: string, @QueryParam("download") download: boolean) {
        if (!this.initialized) {
            await this.pdf.init();
            this.initialized = true;
        }
        if (!Array.isArray(cards)) {
            cards = [cards];
        }
        cards = this.mapCardGroupNames(cards);
        const contracts = await this.pdf.generateRunnerCards(cards, locale);
        res.setHeader('content-type', 'application/pdf');
        if (download) {
            res.setHeader('Content-Disposition', 'attachment; filename="cards.pdf"')
        }
        return contracts;
    }

    @Post('/certificates')
    @OpenAPI({ description: "Generate runner certificate pdfs from certificate runner objects.<br>You can choose your prefered locale by passing the 'locale' query-param.<br> If you provide more than 100 runenrs this could take a moment or two (we tested up to 1000 runners in about 70sec so far)." })
    async generateCertificates(@Body({ validate: true, options: { limit: "500mb" } }) runners: CertificateRunner[], @Res() res: any, @QueryParam("locale") locale: string, @QueryParam("download") download: boolean) {
        if (!this.initialized) {
            await this.pdf.init();
            this.initialized = true;
        }
        if (!Array.isArray(runners)) {
            runners = [runners];
        }
        runners = this.mapCertificatRunnersGroupNames(runners)
        const certificates = await this.pdf.generateRunnerCertficates(runners, locale);
        res.setHeader('content-type', 'application/pdf');
        if (download) {
            res.setHeader('Content-Disposition', 'attachment; filename="certificates.pdf"')
        }
        return certificates;
    }

    private mapRunnerGroupNames(runners: Runner[]): Runner[] {
        let response = new Array<Runner>();
        for (let runner of runners) {
            if (!runner.group.parentGroup) {
                runner.group.fullName = runner.group.name;
            }
            else {
                runner.group.fullName = `${runner.group.parentGroup.name}/${runner.group.name}`;
            }
            response.push(runner)
        }
        return response;
    }

    private mapCertificatRunnersGroupNames(runners: CertificateRunner[]): CertificateRunner[] {
        let response = new Array<CertificateRunner>();
        for (let runner of runners) {
            if (!runner.group.parentGroup) {
                runner.group.fullName = runner.group.name;
            }
            else {
                runner.group.fullName = `${runner.group.parentGroup.name}/${runner.group.name}`;
            }
            runner.donationPerDistanceTotal = runner.distanceDonations.reduce(function (sum, current) {
                return sum + current.amountPerDistance;
            }, 0);
            runner.donationTotal = runner.distanceDonations.reduce(function (sum, current) {
                return sum + current.amount;
            }, 0);
            response.push(runner)
        }
        return response;
    }

    private mapCardGroupNames(cards: RunnerCard[]): RunnerCard[] {
        let response = new Array<RunnerCard>();
        for (let card of cards) {
            if (!card.runner) {
                card.runner = {
                    id: 0,
                    firstname: "Blank",
                    lastname: "Blank",
                    distance: 0,
                    group: {
                        id: 0,
                        name: "Blank",
                        fullName: "Blank"
                    }
                }
            }
            else if (!card.runner.group.parentGroup) {
                card.runner.group.fullName = card.runner.group.name;
            }
            else {
                card.runner.group.fullName = `${card.runner.group.parentGroup.name}/${card.runner.group.name}`;
            }
            response.push(card)
        }
        return response;
    }
}
