import template from "./reports-byapi-runtime.html";
import { Component, RuntimeComponent, OnMounted, OnDestroyed, Param } from "@paperbits/common/ko/decorators";
import { widgetRuntimeSelector, defaultPageSize } from "../../constants";
import * as ko from "knockout";
import { ReportQuery } from "../../../../../src/services/reportQuery";
import { ReportRecordByApiViewModel } from "../../../../../src/components/reports/ko/runtime/reportRecordByApiViewModel";
import { AnalyticsServiceCustom } from "../../../../../src/services/analyticsServiceCustom";
import { Utils } from "../../../../../src/utils";
import { SubscriptionListDropdown } from "../../../subscription-list/ko/runtime/subscription-list-dropdown";
import * as moment from "moment";

@RuntimeComponent({
    selector: widgetRuntimeSelector
})
@Component({
    selector: widgetRuntimeSelector,
    template: template
})
export class ReportsByApiRuntime {
    private chartUpdateTimeout: number;
    public readonly startTime: ko.Observable<Date>;
    public readonly endTime: ko.Observable<Date>;
    public readonly selectedPeriod: ko.Observable<string>;
    public readonly lastRefreshedAt: ko.Observable<string>;

    public readonly reportByApi: ko.Observable<ReportRecordByApiViewModel[]>;
    public readonly reportByApiOrder: ko.Observable<string>;
    public readonly reportByApiPage: ko.Observable<number>;
    public readonly reportByApiHasPager: ko.Computed<boolean>;
    public readonly reportByApiHasPrevPage: ko.Observable<boolean>;
    public readonly reportByApiHasNextPage: ko.Observable<boolean>;
    public readonly reportByApiWorking: ko.Observable<boolean>;
    public readonly reportByApiHasData: ko.Computed<boolean>;

    public readonly selectedSubscription: ko.Observable<string>;

    @Param()
    public readonly customFilterStartTime: ko.Observable<string>;
    @Param()
    public readonly customFilterEndTime: ko.Observable<string>;
    @Param()
    public readonly pageSize: ko.Observable<number>;


    constructor(private readonly analyticsServiceCustom: AnalyticsServiceCustom) {

        this.startTime = ko.observable();
        this.endTime = ko.observable();
        this.selectedPeriod = ko.observable();

        this.reportByApi = ko.observable([]);
        this.reportByApiOrder = ko.observable("callCountSuccess");
        this.reportByApiPage = ko.observable(1);
        this.reportByApiHasPrevPage = ko.observable(false);
        this.reportByApiHasNextPage = ko.observable(false);
        this.reportByApiHasPager = ko.computed(() => this.reportByApiHasPrevPage() || this.reportByApiHasNextPage());
        this.reportByApiWorking = ko.observable(false);
        this.reportByApiHasData = ko.computed(() => this.reportByApi().length !== 0);

        this.customFilterStartTime = ko.observable();
        this.customFilterEndTime = ko.observable();
        this.pageSize = ko.observable();
        this.lastRefreshedAt = ko.observable();

        this.selectedSubscription = ko.observable();

    }

    @OnMounted()
    public async initialize(): Promise<void> {
        this.lastRefreshedAt("NA");
        this.setTimeRange7Days();

        await this.buildCharts();

        this.startTime.subscribe(this.scheduleChartsUpdate);
        this.endTime.subscribe(this.scheduleChartsUpdate);
        this.pageSize.subscribe(this.scheduleChartsUpdate);

        this.selectedSubscription.subscribe(this.scheduleChartsUpdate);
    }

    private scheduleChartsUpdate(): void {
        clearTimeout(this.chartUpdateTimeout);
        this.chartUpdateTimeout = window.setTimeout(() => this.buildCharts(), 500);
    }

    private async buildCharts(): Promise<void> {
        const apiPromise = this.getReportsByApi();

        Promise.all([
            apiPromise,
        ]);
    }

        /**
     * Creates a view model for metrics aggregated by API.
     */
    private async getReportsByApi(): Promise<void> {
        const startTime = this.startTime();
        const endTime = this.endTime();
        const pageNumber = this.reportByApiPage() - 1;
        const orderBy = this.reportByApiOrder();
        const pageSize = this.pageSize() || defaultPageSize;
        const selectedSubscription = this.selectedSubscription();
        const query: ReportQuery = {
            startTime: startTime,
            endTime: endTime,
            skip: pageNumber * pageSize,
            take: pageSize,
            orderBy: orderBy,
            subscription: selectedSubscription,
        };

        this.reportByApiWorking(true);

        const pageOfRecords = await this.analyticsServiceCustom.getReportsByApi(query);
        const records = pageOfRecords.value;
        this.lastRefreshedAt(pageOfRecords.maxTimestamp?moment(pageOfRecords.maxTimestamp).format('hh:MM A, MM-DD-YYYY'):'NA');

        this.reportByApiHasPrevPage(pageNumber > 0);
        this.reportByApiHasNextPage(!!pageOfRecords.nextLink);

        const viewModels: ReportRecordByApiViewModel[] = records.map(contract => {
            const viewModel = new ReportRecordByApiViewModel();
            viewModel.apiId("");
            viewModel.apiName(contract.name);

            viewModel.callCountSuccess(Utils.formatNumber(contract.callCountSuccess));
            viewModel.callCountBlocked(Utils.formatNumber(contract.callCountBlocked));
            viewModel.callCountFailed(Utils.formatNumber(contract.callCountFailed));
            viewModel.callCountOther(Utils.formatNumber(contract.callCountOther));
            viewModel.callCountTotal(Utils.formatNumber(contract.callCountTotal));
            viewModel.apiTimeAvg(Utils.formatTimespan(contract.apiTimeAvg));
            viewModel.bandwidth(Utils.formatBytes(contract.bandwidth));

            return viewModel;
        });

        this.reportByApi(viewModels);
        this.reportByApiWorking(false);
    }

    public setTimeRange1Hour(): void {
        this.startTime(moment().subtract(1, "hours").toDate());
        this.endTime(moment().toDate());
        this.selectedPeriod("1hour");
    }

    public setTimeRange1Day(): void {
        this.startTime(moment().subtract(1, "days").toDate());
        this.endTime(moment().toDate());
        this.selectedPeriod("1day");
    }


    public handleSubscriptionListDropdownSelect(data: SubscriptionListDropdown
        // , event
    ): void {
        let selectedSubscription = data.selectedSubscription();
        if (selectedSubscription) {
            this.selectedSubscription(selectedSubscription.name);
        }
    }


    public setTimeRange7Days(): void {
        this.startTime(moment().subtract(7, "days").toDate());
        this.endTime(moment().toDate());
        this.selectedPeriod("7days");
    }

    public setTimeRange30Days(): void {
        this.startTime(moment().subtract(30, "days").toDate());
        this.endTime(moment().toDate());
        this.selectedPeriod("30days");
    }

    public setTimeRange90Days(): void {
        this.startTime(moment().subtract(90, "days").toDate());
        this.endTime(moment().toDate());
        this.selectedPeriod("90days");
    }

    public setTimeRangeCustom(): void {
        const customFilterStartTime = `${this.customFilterStartTime()}T00:00:00.000Z`;
        const customFilterEndTime = `${this.customFilterEndTime()}T23:59:59.999Z`;
        this.startTime(moment(customFilterStartTime, "MM-DD-YYYYThh:mm:ss.SSSZ").toDate());
        this.endTime(moment(customFilterEndTime, "MM-DD-YYYYThh:mm:ss.SSSZ").toDate());
        this.selectedPeriod("Custom");
    }

    public reportByApiPrevPage(): void {
        this.reportByApiPage(this.reportByApiPage() - 1);
        this.getReportsByApi();
    }

    public reportByApiNextPage(): void {
        this.reportByApiPage(this.reportByApiPage() + 1);
        this.getReportsByApi();
    }

    public reportByApiOrderBy(fieldName: string): void {
        this.reportByApiOrder(fieldName);
        this.getReportsByApi();
    }

    @OnDestroyed()
    public async dispose(): Promise<void> {
        // Your cleanup widget logic
    }
}