//SCREEN-BOILERPLATE
//this boilerplate builds screens that are gonna be shown in the <div class='content'> tag of our main HTML.
//do not build app components with this boilerplate, only screens (reports)

define([
    'app',
    'js/templates-loader',
    'moment',
    'components/ag-grid/ag-grid-module',
],
    function (app, T, moment, AgGridModule) {

        var Screen = { Models: {}, Views: {}, Collections: {} };

        // ---------------------------------------------------------------
        // Configuration
        // ---------------------------------------------------------------
        var AUTO_REFRESH_INTERVAL_SECONDS = 15;
        var AUTO_REFRESH_STORAGE_KEY = 'power-peaks.autoRefresh.enabled';

        // ---------------------------------------------------------------
        // Cell renderers / formatters
        // ---------------------------------------------------------------
        function loadFormatter(params) {
            if (params.value == null || params.value === '') return '';
            var n = Number(params.value);
            if (isNaN(n)) return params.value;
            return n.toLocaleString(undefined, { maximumFractionDigits: 0 });
        }

        function priceFormatter(params) {
            if (params.value == null || params.value === '') return '';
            var n = Number(params.value);
            if (isNaN(n)) return params.value;
            return '$' + n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
        }

        // Highlight the #1 row inside each grid
        function rankRowClassRules() {
            return {
                'row-top-peak': function (params) {
                    return params.data && Number(params.data.rn) === 1;
                }
            };
        }

        // ---------------------------------------------------------------
        // Column definitions
        // ---------------------------------------------------------------
        function pjmColumnDefs() {
            return [
                { field: 'rn',              headerName: '#',         width: 60,  cellClass: 'cell-rank text-center', headerClass: 'ag-header-cell-center' },
                { field: 'EventTime',       headerName: 'Date / Hour', flex: 1.4, minWidth: 160, cellClass: 'text-center', headerClass: 'ag-header-cell-center' },
                { field: 'RTOMeteredLoad',  headerName: 'PJM Load (MW)', flex: 1, minWidth: 110, cellClass: 'text-right',  headerClass: 'ag-header-cell-center', valueFormatter: loadFormatter },
                { field: 'SDIMeteredLoad',  headerName: 'SDI Load (MW)', flex: 1, minWidth: 110, cellClass: 'text-right',  headerClass: 'ag-header-cell-center', valueFormatter: loadFormatter },
                { field: 'AveragePrice',    headerName: 'Avg Price',     flex: 1, minWidth: 100, cellClass: 'text-right',  headerClass: 'ag-header-cell-center', valueFormatter: priceFormatter },
            ];
        }

        function aepColumnDefs() {
            return [
                { field: 'rn',              headerName: '#',         width: 60,  cellClass: 'cell-rank text-center', headerClass: 'ag-header-cell-center' },
                { field: 'EventTime',       headerName: 'Date / Hour', flex: 1.4, minWidth: 160, cellClass: 'text-center', headerClass: 'ag-header-cell-center' },
                { field: 'AEPMeteredLoad',  headerName: 'AEP Load (MW)', flex: 1, minWidth: 110, cellClass: 'text-right',  headerClass: 'ag-header-cell-center', valueFormatter: loadFormatter },
                { field: 'SDIMeteredLoad',  headerName: 'SDI Load (MW)', flex: 1, minWidth: 110, cellClass: 'text-right',  headerClass: 'ag-header-cell-center', valueFormatter: loadFormatter },
                { field: 'AveragePrice',    headerName: 'Avg Price',     flex: 1, minWidth: 100, cellClass: 'text-right',  headerClass: 'ag-header-cell-center', valueFormatter: priceFormatter },
            ];
        }

        // ---------------------------------------------------------------
        // Model
        // ---------------------------------------------------------------
        Screen.Models.Main = Backbone.Epoxy.Model.extend({
            defaults: {
                hasData: false,
                isLoading: false,

                // Auto refresh
                autoRefreshEnabled: true,
                countdown: AUTO_REFRESH_INTERVAL_SECONDS,

                // Header strings
                lastMeteredUpdate: '-',

                // KPI tiles
                topPjmLoad: '-', topPjmWhen: '-',
                topAepLoad: '-', topAepWhen: '-',

                // Per-grid counts
                pjmCount: '0 peaks',
                aepCount: '0 peaks',
            },
        });

        // ---------------------------------------------------------------
        // View
        // ---------------------------------------------------------------
        Screen.Views.Main = Backbone.Epoxy.View.extend({
            template: 'power-peaks',
            id: 'power-peaks',
            title: 'Power Peaks',
            isCacheable: false,
            events: function () {
                return {
                    'click #refreshBtn':       this.refreshBtn_click,
                    'click #autoRefreshToggle': this.autoRefreshToggle_click,
                };
            },
            bindings: 'data-bind',
            grids: null,
            subviews: null,
            viewParams: null,

            initialize: function () {
                this.options.state = app.view_states.loading;
                this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

                if (!this.model) this.model = new Screen.Models.Main();

                // Restore saved auto-refresh preference
                try {
                    var saved = localStorage.getItem(AUTO_REFRESH_STORAGE_KEY);
                    if (saved === 'false') this.model.set('autoRefreshEnabled', false);
                } catch (e) { /* localStorage may be unavailable */ }

                this.grids = {};
                this.subviews = {};
                this.isFetching = false;

                this.autoRefresh = {
                    tickId: null,
                    remaining: AUTO_REFRESH_INTERVAL_SECONDS,
                };

                var gridOptions = {
                    rowClassRules: rankRowClassRules(),
                };

                this.grids.pjm = new AgGridModule({
                    columnDefs: pjmColumnDefs(),
                    rowData: [],
                    fileName: 'power-peaks-pjm',
                    screenTitle: this.title + ' - PJM Peaks',
                    pagination: 'hidden',
                    allowMultipleSelection: false,
                    suppressRowClickSelection: true,
                    gridOptions: gridOptions,
                });
                this.grids.aep = new AgGridModule({
                    columnDefs: aepColumnDefs(),
                    rowData: [],
                    fileName: 'power-peaks-aep',
                    screenTitle: this.title + ' - AEP Peak',
                    pagination: 'hidden',
                    allowMultipleSelection: false,
                    suppressRowClickSelection: true,
                    gridOptions: gridOptions,
                });

                // Kick off the first SP call in parallel with template+i18n rendering.
                this._preloadPendingSets = null;
                this._preload();
            },

            _preload: function () {
                var that = this;
                this.isFetching = true;
                this.model.set('isLoading', true);

                var qp = new Core.Database.QueryParameters();
                Core.Json.CallProcedure(
                    app.DatabaseNames.MES + '.PWR.GetPeaksWeb',
                    qp,
                    {
                        onSuccess: function (resp) {
                            var sets = {
                                pjm:  (resp && resp.Table)  ? resp.Table  : [],
                                aep:  (resp && resp.Table1) ? resp.Table1 : [],
                                meta: (resp && resp.Table2) ? resp.Table2 : [],
                            };
                            that._applyOrStashSets(sets);
                        },
                        onFailure: function (resp) {
                            console.error(resp);
                            that.isFetching = false;
                            that.model.set('isLoading', false);
                        },
                        Secured: true,
                        Async: true,
                    },
                    app.ConnectionStrings.app
                );
            },

            _applyOrStashSets: function (sets) {
                if (this.isRendered) {
                    this.processResults(sets);
                    this.finishFetch();
                } else {
                    this._preloadPendingSets = sets;
                }
            },

            // -------------------------------------------------------------
            // Render
            // -------------------------------------------------------------
            render: function (container, viewParams) {
                var that = this;

                this.viewParams = viewParams;

                var thatContainer = (this.options.container) ? this.options.container : container;
                this.options.container = thatContainer;

                var customPath = '/app/pages/mes/' + this.template + '/';

                T.render.call(
                    this,
                    this.template,
                    function (tmp) {
                        if (!that.options.i18n) that.options.i18n = {};

                        app.getI18NJed(
                            that,
                            that.template,
                            function (i18nJED) {
                                that.options.i18n[that.template] = i18nJED;
                                that.$el.html(tmp());
                                that.applyBindings();

                                that.grids.pjm.render();
                                that.$el.find('#grid-pjm').append(that.grids.pjm.$el);

                                that.grids.aep.render();
                                that.$el.find('#grid-aep').append(that.grids.aep.$el);

                                that.append(thatContainer, that.$el);
                                that.isRendered = true;

                                if (that._preloadPendingSets) {
                                    var sets = that._preloadPendingSets;
                                    that._preloadPendingSets = null;
                                    that.processResults(sets);
                                    that.finishFetch();
                                } else if (!that.isFetching) {
                                    that._refresh();
                                }

                                that.startAutoRefreshTick();
                            },
                            true,
                            customPath
                        );
                    },
                    customPath
                );
            },

            // -------------------------------------------------------------
            // Data fetch
            // -------------------------------------------------------------
            _refresh: function () {
                var that = this;

                if (this.isFetching) return;
                this.isFetching = true;

                var isFirstLoad = !this.model.get('hasData');
                this.model.set('isLoading', true);

                if (isFirstLoad) {
                    _.each(this.grids, function (g) { if (g.showLoadingOverlay) g.showLoadingOverlay(); });
                }

                var qp = new Core.Database.QueryParameters();

                Core.Json.CallProcedure(
                    app.DatabaseNames.MES + '.PWR.GetPeaksWeb',
                    qp,
                    {
                        onSuccess: function (resp) {
                            try {
                                var sets = {
                                    pjm:  (resp && resp.Table)  ? resp.Table  : [],
                                    aep:  (resp && resp.Table1) ? resp.Table1 : [],
                                    meta: (resp && resp.Table2) ? resp.Table2 : [],
                                };
                                that.processResults(sets);
                            } catch (e) {
                                console.error((e.stack) ? e.stack : new Error(e).stack);
                            } finally {
                                that.finishFetch();
                            }
                        },
                        onFailure: function (resp) {
                            console.error(resp);
                            app.views.topMessages.showMessage('CALL TO DATABASE FAILED', { stay: 5000 });
                            that.finishFetch();
                        },
                        Secured: true,
                        Async: true,
                    },
                    app.ConnectionStrings.app
                );
            },

            finishFetch: function () {
                this.isFetching = false;
                this.model.set('isLoading', false);
                _.each(this.grids, function (g) { if (g.hideOverlay) g.hideOverlay(); });

                this.autoRefresh.remaining = AUTO_REFRESH_INTERVAL_SECONDS;
                this.model.set('countdown', AUTO_REFRESH_INTERVAL_SECONDS);
            },

            // -------------------------------------------------------------
            // Process result sets → push to grids, compute KPIs
            // -------------------------------------------------------------
            processResults: function (sets) {
                var pjmRows = sets.pjm || [];
                var aepRows = sets.aep || [];
                var meta    = sets.meta || [];

                var that = this;

                this.grids.pjm.gridReadyPromise.then(function () {
                    that.grids.pjm.setRowData(pjmRows);
                }).catch(function () {});

                this.grids.aep.gridReadyPromise.then(function () {
                    that.grids.aep.setRowData(aepRows);
                }).catch(function () {});

                var modelUpdate = {
                    hasData: true,
                    pjmCount: pjmRows.length + (pjmRows.length === 1 ? ' peak' : ' peaks'),
                    aepCount: aepRows.length + (aepRows.length === 1 ? ' peak' : ' peaks'),
                };

                // KPI: top PJM peak (rn=1) — fall back to first row if rn missing
                var topPjm = _.findWhere(pjmRows, { rn: 1 }) || pjmRows[0];
                if (topPjm) {
                    modelUpdate.topPjmLoad = (topPjm.RTOMeteredLoad != null)
                        ? Number(topPjm.RTOMeteredLoad).toLocaleString(undefined, { maximumFractionDigits: 0 }) + ' MW'
                        : '-';
                    modelUpdate.topPjmWhen = topPjm.EventTime || '-';
                }

                var topAep = _.findWhere(aepRows, { rn: 1 }) || aepRows[0];
                if (topAep) {
                    modelUpdate.topAepLoad = (topAep.AEPMeteredLoad != null)
                        ? Number(topAep.AEPMeteredLoad).toLocaleString(undefined, { maximumFractionDigits: 0 }) + ' MW'
                        : '-';
                    modelUpdate.topAepWhen = topAep.EventTime || '-';
                }

                // Last metered update — from result set 3 (PWR.MeteredLoad MAX(StartDateTime))
                if (meta.length && meta[0].LastUpdated != null) {
                    modelUpdate.lastMeteredUpdate = new moment(meta[0].LastUpdated).format('MM/DD/YYYY HH:mm:ss');
                } else {
                    modelUpdate.lastMeteredUpdate = '-';
                }

                this.model.set(modelUpdate);
            },

            // -------------------------------------------------------------
            // Auto-refresh ticker
            // -------------------------------------------------------------
            startAutoRefreshTick: function () {
                var that = this;
                this.stopAutoRefreshTick();
                this.autoRefresh.remaining = AUTO_REFRESH_INTERVAL_SECONDS;
                this.model.set('countdown', AUTO_REFRESH_INTERVAL_SECONDS);

                this.autoRefresh.tickId = setInterval(function () {
                    if (!that.model.get('autoRefreshEnabled')) return;
                    if (that.isFetching) return;

                    that.autoRefresh.remaining -= 1;
                    if (that.autoRefresh.remaining <= 0) {
                        that.autoRefresh.remaining = AUTO_REFRESH_INTERVAL_SECONDS;
                        that.model.set('countdown', AUTO_REFRESH_INTERVAL_SECONDS);
                        that._refresh();
                    } else {
                        that.model.set('countdown', that.autoRefresh.remaining);
                    }
                }, 1000);
            },
            stopAutoRefreshTick: function () {
                if (this.autoRefresh && this.autoRefresh.tickId != null) {
                    clearInterval(this.autoRefresh.tickId);
                    this.autoRefresh.tickId = null;
                }
            },
            autoRefreshToggle_click: function () {
                var enabled = !this.model.get('autoRefreshEnabled');
                this.model.set('autoRefreshEnabled', enabled);
                try { localStorage.setItem(AUTO_REFRESH_STORAGE_KEY, String(enabled)); } catch (e) {}

                this.autoRefresh.remaining = AUTO_REFRESH_INTERVAL_SECONDS;
                this.model.set('countdown', AUTO_REFRESH_INTERVAL_SECONDS);
            },

            refreshBtn_click: function () {
                this._refresh();
                window.scrollTo(0, 0);
            },

            // -------------------------------------------------------------
            // View boilerplate
            // -------------------------------------------------------------
            append: function (container, el) {
                el = (el != null && el != undefined) ? el : this.$el;

                if (this.options.state == app.view_states.loading
                    || this.options.state == app.view_states.shown) {
                    this.options.state = app.view_states.shown;
                    container.append(el);
                    this.options.onappend(this);
                }
                if (this.options.state == app.view_states.hidden) container.append(el);
                if (this.options.state == app.view_states.closed) return;
            },
            bindViewScopedEvents: function () { },
            unbindViewScopedEvents: function () { },
            close: function () {
                this.options.state = app.view_states.closed;
                this.stopAutoRefreshTick();
                _.each(this.grids, function (g) { if (g && g.destroy) g.destroy(); });
                this.closeSubviews();
                this.remove();
                this.unbindViewScopedEvents();
                this.unbind();
            },
            closeSubviews: function () {
                _.each(this.subviews, function (sview) { sview.close(); });
            },
            show: function () {
                this.options.state = app.view_states.shown;
                this.showSubviews();
                this.$el.show();
            },
            showSubviews: function () { _.each(this.subviews, function (s) { s.show(); }); },
            hide: function () {
                this.options.state = app.view_states.hidden;
                this.stopAutoRefreshTick();
                this.hideSubviews();
                this.$el.hide();
                this.unbind();
                this.stopListening();
            },
            hideSubviews: function () { _.each(this.subviews, function (s) { s.hide(); }); },
            preRender: function () { app.models.subnavbar.set('subnavbar', false); },
            reRender: function () {
                try { this._refresh(); } catch (Error) { }
            },
        });

        // Required, return the module for AMD compliance.
        return Screen;
    });
