// tslint:disable:no-console
import * as fs from 'fs';
import * as moment from 'moment-timezone';
import * as mongoose from 'mongoose';

import { chevre } from '../../../../lib/index';

const PROJECT_ID = String(process.env.PROJECT_ID);
// const SCREEN_CODE = '10';
// const MOVIE_THEATER_CODE = '118';
const SCREEN_CODE = '130';
// const SCREEN_CODE = '211';
const MOVIE_THEATER_CODE = '020';
const AGGREGATE_PERIOD_IN_MONTHS = 12;
// tslint:disable-next-line:max-func-body-length
async function main() {
    await mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });

    const aggregateOrderRepo = await chevre.repository.AggregateOrder.createInstance(mongoose.connection);
    const seatRepo = await chevre.repository.place.Seat.createInstance(mongoose.connection);
    const orderRepo = await chevre.repository.Order.createInstance(mongoose.connection);

    const royalCustomers = await aggregateOrderRepo.searchRoyalCustomers({
        limit: 300,
        project: { id: PROJECT_ID },
        aggregateOrder: { orderCount: { $gte: 12 } }
    });
    // tslint:disable-next-line:no-null-keyword
    console.dir(royalCustomers, { depth: null });
    console.log(royalCustomers.length, 'royalCustomers found');

    const customerEmails = royalCustomers.map(({ identifier }) => identifier);

    const seats = <Pick<chevre.factory.place.seat.IPlace, 'branchCode'>[]>await seatRepo.searchSeats({
        // limit: 50,
        $projection: {
            additionalProperty: 0,
            'containedInPlace.typeOf': 0,
            'containedInPlace.name': 0,
            'containedInPlace.containedInPlace': 0,
            name: 0, typeOf: 0
        },
        project: { id: { $eq: PROJECT_ID } },
        containedInPlace: {
            containedInPlace: {
                branchCode: { $eq: SCREEN_CODE },
                containedInPlace: { branchCode: { $eq: MOVIE_THEATER_CODE } }
            }
        }
    });
    // tslint:disable-next-line:no-null-keyword
    // console.dir(seats, { depth: null });
    console.log(seats.length, 'seats found');

    const orderDateGte: Date = moment()
        .add(-AGGREGATE_PERIOD_IN_MONTHS, 'months')
        .toDate();
    const orderDateLte: Date = moment()
        .toDate();

    let maxSumGraceTime: number = 0;
    let maxRepeatRate: number = 0;
    const seatsWithAggregateOrder: {
        branchCode: string;
        aggregateOrder: {
            emailCount: number;
            orderCount: number;
            repeatRate: number;
            avgGraceTime?: number;
            sumGraceTime: number;
            avgGraceTimeInHours?: number;
            sumGraceTimeInHours: number;
        };
        score?: number;
    }[] = [];
    let i = 1;
    for (const { branchCode } of seats) {
        i += 1;
        const startTime = process.hrtime();
        const aggregateResult = await orderRepo.aggregateOrderOfSeat({
            project: { id: { $eq: PROJECT_ID } },
            orderDate: { $gte: orderDateGte, $lte: orderDateLte },
            acceptedOffers: {
                itemOffered: {
                    reservationFor: {
                        location: { branchCode: SCREEN_CODE },
                        superEvent: { location: { branchCode: MOVIE_THEATER_CODE } }
                    },
                    reservedTicket: { ticketedSeat: { seatNumber: branchCode } }
                }
            },
            customer: { email: { $in: customerEmails } }
        });
        console.log('aggregateOrder:result', aggregateResult, orderDateGte, orderDateLte, i);
        const diff = process.hrtime(startTime);
        console.log(`aggregateOrderOfSeat took ${diff[0]} seconds and ${diff[1]} nanoseconds.`);

        const emailCount = (typeof aggregateResult.aggregation.emailCount === 'number')
            ? aggregateResult.aggregation.emailCount
            : 0;
        const repeatRate = (aggregateResult.aggregation.orderCount > 0)
            // tslint:disable-next-line:no-magic-numbers
            ? (aggregateResult.aggregation.orderCount - emailCount) * 100 / aggregateResult.aggregation.orderCount
            : 0;
        const sumGraceTime = (typeof aggregateResult.aggregation.sumGraceTime === 'number')
            ? aggregateResult.aggregation.sumGraceTime
            : 0;
        const avgGraceTimeInHours = (typeof aggregateResult.aggregation.sumGraceTime === 'number')
            ? Math.floor(
                moment.duration(Math.floor(aggregateResult.aggregation.sumGraceTime / aggregateResult.aggregation.orderCount), 'milliseconds')
                    .asHours()
            )
            : 0;
        const sumGraceTimeInHours = (typeof aggregateResult.aggregation.sumGraceTime === 'number')
            ? Math.floor(moment.duration(aggregateResult.aggregation.sumGraceTime, 'milliseconds')
                .asHours())
            : 0;
        maxSumGraceTime = Math.max(sumGraceTime, maxSumGraceTime);
        maxRepeatRate = Math.max(repeatRate, maxRepeatRate);

        seatsWithAggregateOrder.push({
            branchCode,
            aggregateOrder: {
                ...aggregateResult.aggregation,
                emailCount,
                repeatRate,
                avgGraceTimeInHours,
                sumGraceTimeInHours,
                sumGraceTime
            }
        });
    }

    const seatsJson = seatsWithAggregateOrder.map((seat, key) => {
        // tslint:disable-next-line:no-magic-numbers
        const score = Math.floor(seat.aggregateOrder.sumGraceTime * 100 / maxSumGraceTime);
        console.log('aggregateOrder:result', seat.branchCode, key);

        return {
            branchCode: seat.branchCode,
            score
        };
    });

    const scoresByEmailJson = seatsWithAggregateOrder.map((seat, key) => {
        // tslint:disable-next-line:no-magic-numbers
        const score = Math.floor(seat.aggregateOrder.repeatRate * 100 / maxRepeatRate);
        console.log('aggregateOrder:result', seat.branchCode, seat.aggregateOrder.emailCount, key);

        return {
            branchCode: seat.branchCode,
            score
            // repeatRate: seat.aggregateOrder.repeatRate,
            // emailCount: seat.aggregateOrder.emailCount,
            // orderCount: seat.aggregateOrder.orderCount
        };
    });

    console.log('maxSumGraceTime:', maxSumGraceTime);
    console.log('maxRepeatRate:', maxRepeatRate);

    // tslint:disable-next-line:non-literal-fs-path no-null-keyword
    fs.writeFileSync(`${__dirname}/seatScoresByGraceTime.json`, JSON.stringify(seatsJson, null, '    '));
    // tslint:disable-next-line:non-literal-fs-path no-null-keyword
    fs.writeFileSync(`${__dirname}/seatScoresByEmail.json`, JSON.stringify(scoresByEmailJson, null, '    '));
}

main()
    .then(() => {
        console.log('success!');
    })
    .catch(console.error);
