import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button, ColorPicker, EditableText, Size, Type } from 'browndash-components';
import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { FaPlus } from 'react-icons/fa';
import { Doc, DocListCast } from '../../fields/Doc';
import { AclPrivate, DocAcl } from '../../fields/DocSymbols';
import { Id } from '../../fields/FieldSymbols';
import { List } from '../../fields/List';
import { PrefetchProxy } from '../../fields/Proxy';
import { listSpec } from '../../fields/Schema';
import { ScriptField } from '../../fields/ScriptField';
import { Cast, ImageCast, StrCast } from '../../fields/Types';
import { normalizeEmail } from '../../fields/util';
import { DocServer } from '../DocServer';
import { Docs, DocumentOptions, DocUtils } from '../documents/Documents';
import { HistoryUtil } from '../util/History';
import { ScriptingGlobals } from '../util/ScriptingGlobals';
import { SettingsManager } from '../util/SettingsManager';
import { SharingManager } from '../util/SharingManager';
import { undoable, undoBatch, UndoManager } from '../util/UndoManager';
import { CollectionDockingView } from './collections/CollectionDockingView';
import { CollectionView } from './collections/CollectionView';
import { ContextMenu } from './ContextMenu';
import './DashboardView.scss';
import { Colors } from './global/globalEnums';
import { MainViewModal } from './MainViewModal';
import { ButtonType } from './nodes/FontIconBox/FontIconBox';
enum DashboardGroup {
    MyDashboards,
    SharedDashboards,
}
// DashboardView is the view with the dashboard previews, rendered when the app first loads
@observer
export class DashboardView extends React.Component {
    public static _urlState: HistoryUtil.DocUrl;
    @observable private openModal = false;
    @observable private selectedDashboardGroup = DashboardGroup.MyDashboards;
    @observable private newDashboardName = '';
    @observable private newDashboardColor = '#AFAFAF';
    @action abortCreateNewDashboard = () => (this.openModal = false);
    @action setNewDashboardName = (name: string) => (this.newDashboardName = name);
    @action setNewDashboardColor = (color: string) => (this.newDashboardColor = color);
    @action selectDashboardGroup = (group: DashboardGroup) => (this.selectedDashboardGroup = group);
    clickDashboard = (e: React.MouseEvent, dashboard: Doc) => {
        if (this.selectedDashboardGroup === DashboardGroup.SharedDashboards) {
            DashboardView.openSharedDashboard(dashboard);
        } else {
            Doc.ActiveDashboard = dashboard;
        }
        Doc.ActivePage = 'dashboard';
    };
    getDashboards = (whichGroup: DashboardGroup) => {
        if (whichGroup === DashboardGroup.MyDashboards) {
            return DocListCast(Doc.MyDashboards.data).filter(dashboard => Doc.GetProto(dashboard).author === Doc.CurrentUserEmail);
        }
        return DocListCast(Doc.MySharedDocs.data_dashboards).filter(doc => doc.dockingConfig);
    };
    isUnviewedSharedDashboard = (dashboard: Doc) => !DocListCast(Doc.MySharedDocs.viewed).includes(dashboard);
    @undoBatch
    createNewDashboard = (name: string, background?: string) => {
        DashboardView.createNewDashboard(undefined, name, background);
        this.abortCreateNewDashboard();
    };
    @computed
    get namingInterface() {
        return (
            
                Create New Dashboard
                 this.setNewDashboardName(val as string)} fillWidth />
                
                
                    
                    
             
        );
    }
    @action
    openNewDashboardModal = () => {
        this.openModal = true;
        this.setNewDashboardName(`Dashboard ${DocListCast(Doc.MyDashboards.data).length + 1}`);
    };
    _downX: number = 0;
    _downY: number = 0;
    onContextMenu = (dashboard: Doc, e: React.MouseEvent) => {
        // the touch onContextMenu is button 0, the pointer onContextMenu is button 2
        if (navigator.userAgent.includes('Mozilla') || (Math.abs(this._downX - e.clientX) < 3 && Math.abs(this._downY - e.clientY) < 3)) {
            e.preventDefault();
            e.stopPropagation();
            ContextMenu.Instance.addItem({
                description: `Share Dashboard`,
                event: () => SharingManager.Instance.open(undefined, dashboard),
                icon: 'edit',
            });
            ContextMenu.Instance.addItem({
                description: `Delete Dashboard ${Doc.noviceMode ? '(disabled)' : ''}`,
                event: () => !Doc.noviceMode && DashboardView.removeDashboard(dashboard),
                icon: 'trash',
            });
            ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
        }
    };
    render() {
        const color = SettingsManager.userColor;
        const variant = SettingsManager.userVariantColor;
        return (
            <>
                
                    
                        
                    
                        {this.selectedDashboardGroup === DashboardGroup.SharedDashboards && !this.getDashboards(this.selectedDashboardGroup).length
                            ? 'No one has shared a dashboard with you'
                            : this.getDashboards(this.selectedDashboardGroup).map(dashboard => {
                                  const href = ImageCast(dashboard.thumb)?.url?.href;
                                  const shared = Object.keys(dashboard[DocAcl])
                                      .filter(key => key !== `acl-${normalizeEmail(Doc.CurrentUserEmail)}` && !['acl-Me', 'acl-Guest'].includes(key))
                                      .some(key => dashboard[DocAcl][key] !== AclPrivate);
                                  return (
                                      
 this.onContextMenu(dashboard, e)}
                                          onClick={e => this.clickDashboard(e, dashboard)}>
                                          
 
                                          
                                               (Doc.GetProto(dashboard).title = val)} />
                                              {this.selectedDashboardGroup === DashboardGroup.SharedDashboards && this.isUnviewedSharedDashboard(dashboard) ? unviewed
 : }
                                               {
                                                      this._downX = e.clientX;
                                                      this._downY = e.clientY;
                                                  }}
                                                  onClick={e => this.onContextMenu(dashboard, e)}>
                                                  } />
                                              
                                           
                                          
                                          {shared ? 'shared' : ''}
                                      
                                  );
                              })}
                        {this.selectedDashboardGroup === DashboardGroup.SharedDashboards ? null : (
                            
                        )}
                    
 
                
            >
        );
    }
    public static closeActiveDashboard() {
        Doc.ActiveDashboard = undefined;
    }
    public static snapshotDashboard() {
        return CollectionDockingView.TakeSnapshot(Doc.ActiveDashboard);
    }
    public static openSharedDashboard = (dashboard: Doc) => {
        Doc.AddDocToList(Doc.MySharedDocs, 'viewed', dashboard);
        DashboardView.openDashboard(Doc.BestEmbedding(dashboard));
    };
    /// opens a dashboard as the ActiveDashboard (and adds the dashboard to the users list of dashboards if it's not already there).
    /// this also sets the readonly state of the dashboard based on the current mode of dash (from its url)
    public static openDashboard = (doc: Doc | undefined, fromHistory = false) => {
        if (!doc) return false;
        Doc.AddDocToList(Doc.MyDashboards, 'data', doc);
        Doc.RemoveDocFromList(Doc.MyRecentlyClosed, 'data', doc);
        // this has the side-effect of setting the main container since we're assigning the active/guest dashboard
        Doc.UserDoc() ? (Doc.ActiveDashboard = doc) : (Doc.GuestDashboard = doc);
        const state = DashboardView._urlState;
        if (state.sharing === true && !Doc.UserDoc()) {
            DocServer.Control.makeReadOnly();
        } else {
            fromHistory ||
                HistoryUtil.pushState({
                    type: 'doc',
                    docId: doc[Id],
                    readonly: state.readonly,
                    nro: state.nro,
                    sharing: false,
                });
            if (state.readonly === true || state.readonly === null) {
                DocServer.Control.makeReadOnly();
            } else if (state.safe) {
                if (!state.nro) {
                    DocServer.Control.makeReadOnly();
                }
                CollectionView.SetSafeMode(true);
            } else if (state.nro || state.nro === null || state.readonly === false) {
            } else if (doc.readOnly) {
                DocServer.Control.makeReadOnly();
            } else {
                Doc.CurrentUserEmail !== 'guest' && DocServer.Control.makeEditable();
            }
        }
        return true;
    };
    public static removeDashboard = (dashboard: Doc) => {
        const dashboards = DocListCast(Doc.MyDashboards.data).filter(dash => dash !== dashboard);
        undoable(() => {
            if (dashboard === Doc.ActiveDashboard) DashboardView.openDashboard(dashboards.lastElement());
            Doc.RemoveDocFromList(Doc.MyDashboards, 'data', dashboard);
            Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', dashboard, undefined, true, true);
            if (!dashboards.length) Doc.ActivePage = 'home';
        }, 'remove dashboard')();
    };
    public static resetDashboard = (dashboard: Doc) => {
        const config = StrCast(dashboard.dockingConfig);
        const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g);
        const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) ?? [];
        const components =
            docids.map(docid => ({
                type: 'component',
                component: 'DocumentFrameRenderer',
                title: 'Untitled Tab 1',
                width: 600,
                props: {
                    documentId: docid,
                },
                componentName: 'lm-react-component',
                isClosable: true,
                reorderEnabled: true,
                componentState: null,
            })) ?? [];
        const reset = {
            isClosable: true,
            reorderEnabled: true,
            title: '',
            openPopouts: [],
            maximisedItemId: null,
            settings: {
                hasHeaders: true,
                constrainDragToContainer: true,
                reorderEnabled: true,
                selectionEnabled: false,
                popoutWholeStack: false,
                blockedPopoutsThrowError: true,
                closePopoutsOnUnload: true,
                showPopoutIcon: true,
                showMaximiseIcon: true,
                showCloseIcon: true,
                responsiveMode: 'onload',
                tabOverlapAllowance: 0,
                reorderOnTabMenuClick: false,
                tabControlOffset: 10,
            },
            dimensions: {
                borderWidth: 3,
                borderGrabWidth: 5,
                minItemHeight: 10,
                minItemWidth: 20,
                headerHeight: 27,
                dragProxyWidth: 300,
                dragProxyHeight: 200,
            },
            labels: {
                close: 'close',
                maximise: 'maximise',
                minimise: 'minimise',
                popout: 'new tab',
                popin: 'pop in',
                tabDropdown: 'additional tabs',
            },
            content: [
                {
                    type: 'row',
                    isClosable: true,
                    reorderEnabled: true,
                    title: '',
                    content: [
                        {
                            type: 'stack',
                            width: 100,
                            isClosable: true,
                            reorderEnabled: true,
                            title: '',
                            activeItemIndex: 0,
                            content: components,
                        },
                    ],
                },
            ],
        };
        if (dashboard.dockingConfig && dashboard.dockingConfig !== Doc.GetProto(dashboard).dockingConfig) dashboard.dockingConfig = JSON.stringify(reset);
        else Doc.SetInPlace(dashboard, 'dockingConfig', JSON.stringify(reset), true);
        return reset;
    };
    public static createNewDashboard = (id?: string, name?: string, background?: string) => {
        const dashboardCount = DocListCast(Doc.MyDashboards.data).length + 1;
        const freeformOptions: DocumentOptions = {
            x: 0,
            y: 400,
            _width: 1500,
            _height: 1000,
            _layout_fitWidth: true,
            _freeform_backgroundGrid: true,
            backgroundColor: background,
            title: `Untitled Tab 1`,
        };
        const title = name ? name : `Dashboard ${dashboardCount}`;
        const freeformDoc = Doc.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions);
        const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: title }, id, 'row');
        Doc.AddDocToList(Doc.MyHeaderBar, 'data', freeformDoc, undefined, undefined, true);
        dashboardDoc['pane-count'] = 1;
        freeformDoc.embedContainer = dashboardDoc;
        dashboardDoc.myOverlayDocs = new List();
        dashboardDoc.myPublishedDocs = new List();
        Doc.AddDocToList(Doc.MyDashboards, 'data', dashboardDoc);
        DashboardView.SetupDashboardTrails(dashboardDoc);
        // open this new dashboard
        Doc.ActiveDashboard = dashboardDoc;
        Doc.ActivePage = 'dashboard';
        Doc.ActivePresentation = undefined;
    };
    public static SetupDashboardTrails(dashboardDoc: Doc) {
        // this section is creating the button document itself  ===  myTrails = new Button
        const reqdBtnOpts: DocumentOptions = {
            _forceActive: true,
            _width: 30,
            _height: 30,
            _dragOnlyWithinContainer: true,
            _layout_hideContextMenu: true,
            title: 'New trail',
            toolTip: 'Create new trail',
            color: Colors.BLACK,
            btnType: ButtonType.ClickButton,
            buttonText: 'New trail',
            icon: 'plus',
            isSystem: true,
        };
        const reqdBtnScript = { onClick: `createNewPresentation()` };
        const myTrailsBtn = DocUtils.AssignScripts(Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript);
        //  createa a list of presentations (as a tree view collection) and store it on the new dashboard
        // instead of assigning Doc.UserDoc().myrails we want to assign Doc.AxtiveDashboard.myTrails
        // but we don't want to create the list of trails here-- but rather in createDashboard
        const reqdOpts: DocumentOptions = {
            title: 'My Trails',
            _layout_showTitle: 'title',
            _height: 100,
            treeView_HideTitle: true,
            _layout_fitWidth: true,
            _gridGap: 5,
            _forceActive: true,
            childDragAction: 'embed',
            treeView_TruncateTitleWidth: 150,
            ignoreClick: true,
            layout_headerButton: myTrailsBtn,
            contextMenuIcons: new List(['plus']),
            contextMenuLabels: new List(['Create New Trail']),
            _lockedPosition: true,
            layout_boxShadow: '0 0',
            childDontRegisterViews: true,
            dropAction: 'same',
            isSystem: true,
            layout_explainer: 'All of the trails that you have created will appear here.',
        };
        const myTrails = DocUtils.AssignScripts(Docs.Create.TreeDocument([], reqdOpts), { treeView_ChildDoubleClick: 'openPresentation(documentView.Document)' });
        dashboardDoc.myTrails = new PrefetchProxy(myTrails);
        const contextMenuScripts = [reqdBtnScript.onClick];
        if (Cast(myTrails.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) {
            myTrails.contextMenuScripts = new List(contextMenuScripts.map(script => ScriptField.MakeFunction(script)!));
        }
    }
}
ScriptingGlobals.add(function createNewDashboard() {
    return DashboardView.createNewDashboard();
}, 'creates a new dashboard when called');
ScriptingGlobals.add(function shareDashboard(dashboard: Doc) {
    SharingManager.Instance.open(undefined, dashboard);
}, 'opens sharing dialog for Dashboard');
ScriptingGlobals.add(function removeDashboard(dashboard: Doc) {
    DashboardView.removeDashboard(dashboard);
}, 'Remove Dashboard from Dashboards');
ScriptingGlobals.add(function resetDashboard(dashboard: Doc) {
    DashboardView.resetDashboard(dashboard);
}, 'move all dashboard tabs to single stack');
ScriptingGlobals.add(function addToDashboards(dashboard: Doc) {
    DashboardView.openDashboard(Doc.MakeEmbedding(dashboard));
}, 'adds Dashboard to set of Dashboards');
ScriptingGlobals.add(async function snapshotDashboard() {
    const batch = UndoManager.StartBatch('snapshot');
    await DashboardView.snapshotDashboard();
    batch.end();
}, 'creates a snapshot copy of a dashboard');