//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-curtailment.autoRefresh.enabled';

        // Area metadata — used to set up the 5 grids and to dispatch
        // SP result sets (Table, Table1, ..., Table4) to the right grid.
        var AREAS = [
            { key: 'area1', title: 'Caster 1',   containerId: '#grid-area-1', tableKey: 'Table'  },
            { key: 'area2', title: 'Caster 2',   containerId: '#grid-area-2', tableKey: 'Table1' },
            { key: 'area3', title: 'LMF',        containerId: '#grid-area-3', tableKey: 'Table2' },
            { key: 'area4', title: 'VTD Boiler', containerId: '#grid-area-4', tableKey: 'Table3' },
            { key: 'area5', title: 'Refractory', containerId: '#grid-area-5', tableKey: 'Table4' },
        ];

        // Status-to-class mapping. CASE-SENSITIVE on purpose: the legacy screen
        // relied on case to differentiate meaning — 'MIN USE' (all caps) means
        // "minimal use is OK" (green), while 'Min Use' (title case) means
        // "constrained / not OK" (red). Same for 'Not OK' vs 'NOT OK'. Do not
        // uppercase-normalize or you will flip red rows to green.
        var OK_VALUES     = ['ON', 'OK', 'MIN PUMP', 'MIN USE'];
        var DANGER_VALUES = ['OFF', 'Not OK', 'NOT OK', 'LOW FIRE', 'Min Use'];

        function isOk(v)     { return v != null && OK_VALUES.indexOf(String(v)) !== -1; }
        function isDanger(v) { return v != null && DANGER_VALUES.indexOf(String(v)) !== -1; }

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

                // Auto refresh
                autoRefreshEnabled: true,
                countdown: AUTO_REFRESH_INTERVAL_SECONDS,
                lastUpdatedText: '-',

                // KPI counters
                okCount: 0,
                offCount: 0,
                totalCount: 0,

                // Per-area counts
                area1Count: '0 equipment',
                area2Count: '0 equipment',
                area3Count: '0 equipment',
                area4Count: '0 equipment',
                area5Count: '0 equipment',
            },
        });

        // ---------------------------------------------------------------
        // Column definitions — shared across the 5 area grids.
        // The SP returns fixed columns per result set.
        // ---------------------------------------------------------------
        function buildColumnDefs() {
            var statusCellClassRules = {
                'cell-ok':     function (params) { return isOk(params.value); },
                'cell-danger': function (params) { return isDanger(params.value); },
                'cell-muted':  function (params) { return params.value == null || params.value === ''; },
            };

            function statusCol(field, header, extra) {
                return _.extend({
                    field: field,
                    headerName: header,
                    flex: 1,
                    minWidth: 70,
                    cellClass: 'text-center',
                    headerClass: 'ag-header-cell-center',
                    cellClassRules: statusCellClassRules,
                }, extra || {});
            }

            return [
                {
                    field: 'Equipment',
                    headerName: 'Equipment',
                    flex: 1.3,
                    minWidth: 110,
                    pinned: 'left',
                    cellClass: 'cell-equipment',
                    headerClass: 'ag-header-cell-center',
                },
                statusCol('PJM', 'PJM'),
                statusCol('PJMMaintenance', 'PJM Maint'),
                statusCol('AEP', 'AEP'),
                statusCol('AEPMaintenance', 'AEP Maint'),
                statusCol('Emergency', 'Emergency', { headerClass: 'ag-header-cell-center header-emergency' }),
            ];
        }

        // ---------------------------------------------------------------
        // View
        // ---------------------------------------------------------------
        Screen.Views.Main = Backbone.Epoxy.View.extend({
            template: 'power-curtailment',
            id: 'power-curtailment',
            title: 'Power Curtailment',
            isCacheable: false,
            events: function () {
                return {
                    'click #refreshBtn':        this.refreshBtn_click,
                    'click .btn-export-to-excel': this.exportToExcel,
                    '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,              // 1-second tick interval
                    remaining: AUTO_REFRESH_INTERVAL_SECONDS,
                };

                var columnDefs = buildColumnDefs();
                _.each(AREAS, function (area) {
                    this.grids[area.key] = new AgGridModule({
                        columnDefs: columnDefs,
                        rowData: [],
                        fileName: 'power-curtailment-' + area.key,
                        screenTitle: this.title + ' - ' + area.title,
                        pagination: 'hidden',
                        allowMultipleSelection: false,
                        suppressRowClickSelection: true,
                    });
                }, this);

                // Kick off the first SP call now so it runs in parallel with
                // template+i18n rendering. If the response lands before the
                // grids mount, we stash the sets and flush them on render.
                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 + '.MES.GetPowerCurtailment',
                    qp,
                    {
                        onSuccess: function (resp) {
                            var sets = {};
                            _.each(AREAS, function (area) {
                                sets[area.key] = (resp && resp[area.tableKey]) ? resp[area.tableKey] : [];
                            });
                            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) {
                // Grids exist but may not have gridApi yet. setRowData handles
                // that case by storing the data in gridOptions until the grid
                // is ready, so it's safe to call as long as render() has run.
                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();

                                // Mount the 5 AG Grid wrappers
                                _.each(AREAS, function (area) {
                                    var grid = that.grids[area.key];
                                    grid.render();
                                    that.$el.find(area.containerId).append(grid.$el);
                                });

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

                                // If the preload fetch (started in initialize) already
                                // returned before we got here, flush the data now.
                                // Otherwise it's still in flight and will land via
                                // _applyOrStashSets -> processResults.
                                if (that._preloadPendingSets) {
                                    var sets = that._preloadPendingSets;
                                    that._preloadPendingSets = null;
                                    that.processResults(sets);
                                    that.finishFetch();
                                } else if (!that.isFetching) {
                                    // Preload failed or was never started — fetch now.
                                    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);

                // Only show the overlay on the very first fetch so silent
                // auto-refreshes don't flicker the grids.
                if (isFirstLoad) {
                    _.each(this.grids, function (g) { if (g.showLoadingOverlay) g.showLoadingOverlay(); });
                }

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

                Core.Json.CallProcedure(
                    app.DatabaseNames.MES + '.MES.GetPowerCurtailment',
                    qp,
                    {
                        onSuccess: function (resp) {
                            try {
                                var sets = {};
                                _.each(AREAS, function (area) {
                                    sets[area.key] = (resp && resp[area.tableKey]) ? resp[area.tableKey] : [];
                                });
                                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(); });

                // Reset the auto-refresh countdown so the next tick starts fresh
                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 totalOk = 0, totalDanger = 0, totalRows = 0;
                var modelUpdate = {};

                _.each(AREAS, function (area, idx) {
                    var rows = sets[area.key] || [];
                    var grid = this.grids[area.key];

                    // Gate on gridReadyPromise: AgGridModule.setRowData stashes into
                    // gridOptions.rowData when the grid isn't ready yet, but onGridReady
                    // only re-applies from this.rowData (not gridOptions.rowData), so
                    // early calls silently drop the data. Only Caster 1 happened to win
                    // the race — the rest arrived before their grids were ready.
                    grid.gridReadyPromise.then(function () {
                        grid.setRowData(rows);
                    }).catch(function () {});

                    modelUpdate['area' + (idx + 1) + 'Count'] = rows.length + ' equipment';
                    totalRows += rows.length;

                    // Count OK vs danger across the 5 status columns
                    _.each(rows, function (r) {
                        _.each(['PJM', 'PJMMaintenance', 'AEP', 'AEPMaintenance', 'Emergency'], function (col) {
                            if (isOk(r[col]))          totalOk++;
                            else if (isDanger(r[col])) totalDanger++;
                        });
                    });
                }, this);

                modelUpdate.hasData = true;
                modelUpdate.okCount = totalOk;
                modelUpdate.offCount = totalDanger;
                modelUpdate.totalCount = totalRows;
                modelUpdate.lastUpdatedText = new moment().format('HH:mm:ss');

                this.model.set(modelUpdate);
            },

            // -------------------------------------------------------------
            // Auto-refresh — 1 second tick decrements the countdown; when
            // it reaches 0 we fire _refresh() and reset.
            // -------------------------------------------------------------
            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) {}

                // Reset the countdown whenever the user toggles so they get a full
                // interval before the next refresh (or a clean restart).
                this.autoRefresh.remaining = AUTO_REFRESH_INTERVAL_SECONDS;
                this.model.set('countdown', AUTO_REFRESH_INTERVAL_SECONDS);
            },

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

            // -------------------------------------------------------------
            // Excel export — 5 sheets, one per area
            // -------------------------------------------------------------
            exportToExcel: function () {
                var that = this;

                var QP = new QueryParameters();

                var cellsData = [
                    { Column: 'A', Value: 'Equipment'      },
                    { Column: 'B', Value: 'PJM'            },
                    { Column: 'C', Value: 'PJMMaintenance' },
                    { Column: 'D', Value: 'AEP'            },
                    { Column: 'E', Value: 'AEPMaintenance' },
                    { Column: 'F', Value: 'Emergency'      },
                ];

                var SQLCellsData = [
                    { ExcelColumnName: 'A', SQLDataColumnName: 'Equipment',      DataType: 'String' },
                    { ExcelColumnName: 'B', SQLDataColumnName: 'PJM',            DataType: 'String' },
                    { ExcelColumnName: 'C', SQLDataColumnName: 'PJMMaintenance', DataType: 'String' },
                    { ExcelColumnName: 'D', SQLDataColumnName: 'AEP',            DataType: 'String' },
                    { ExcelColumnName: 'E', SQLDataColumnName: 'AEPMaintenance', DataType: 'String' },
                    { ExcelColumnName: 'F', SQLDataColumnName: 'Emergency',      DataType: 'String' },
                ];

                var data = {
                    Data: [],
                    ConnectionStringName: 'APP',
                    ExportMethod: 3,
                    FileName: 'Power-Curtailment',
                    TemplateFileFullPath: 'generic.xls',
                    SQLDataSources: [
                        {
                            Name: 'data',
                            DatabaseParameters: {
                                DBEngine: 'SQLSERVER',
                                Procedure: app.DatabaseNames.MES + '.MES.GetPowerCurtailment',
                                QueryParameters: QP,
                            },
                        },
                    ],
                };

                _.each(AREAS, function (area, idx) {
                    data.Data.push({ SheetName: area.title, RowsData: [{ CellsData: cellsData }], StartRowIndex: 1 });
                    data.Data.push({
                        SheetName: area.title, RowsData: [], StartRowIndex: 2,
                        DataSourceName: 'data', DataSourceTableIndex: idx,
                        SQLCellsData: SQLCellsData,
                    });
                });

                that.setExportButtonExporting(true);

                Core.Export.Excel(
                    data,
                    function (resp) {
                        try {
                            if (resp && resp.Success === true && resp.Data) {
                                location.href = app.foldersRoot + '/excel/' + resp.Data;
                            } else if (resp && resp.Message) {
                                console.error(resp.Message);
                            } else {
                                console.error('Server response not valid.');
                            }
                        } catch (Error) { console.error(Error); }
                        that.setExportButtonExporting(false);
                    },
                    function (resp) {
                        console.error(resp);
                        that.setExportButtonExporting(false);
                    }
                );
            },

            setExportButtonExporting: function (val) {
                var btn_export = this.$el.find('.btn-export-to-excel');
                var export_state = btn_export.find('.excel-export-state');
                var loading_state = btn_export.find('.loading-state');

                if (val) {
                    export_state.css('display', 'none');
                    loading_state.removeClass('hide');
                    btn_export.attr('disabled', true);
                } else {
                    loading_state.addClass('hide');
                    export_state.css('display', 'inline-block');
                    btn_export.attr('disabled', false);
                }
            },

            // -------------------------------------------------------------
            // 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 (s) { s.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.hideSubviews();
                this.stopAutoRefreshTick();
                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;
    });
