import { computed } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, DocListCast, Field, FieldResult, StrListCast } from '../../fields/Doc';
import { Id } from '../../fields/FieldSymbols';
import { List } from '../../fields/List';
import { RichTextField } from '../../fields/RichTextField';
import { DocCast, NumCast, StrCast } from '../../fields/Types';
import { emptyFunction, returnAll, returnFalse, returnOne, returnTrue, returnZero } from '../../Utils';
import { Docs, DocUtils } from '../documents/Documents';
import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
import { LinkManager } from '../util/LinkManager';
import { Transform } from '../util/Transform';
import { CollectionStackingView } from './collections/CollectionStackingView';
import { FieldViewProps } from './nodes/FieldView';
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
import { SearchBox } from './search/SearchBox';
import './SidebarAnnos.scss';
import { StyleProp } from './StyleProvider';
import React = require('react');

interface ExtraProps {
    fieldKey: string;
    layoutDoc: Doc;
    rootDoc: Doc;
    dataDoc: Doc;
    // usePanelWidth: boolean;
    showSidebar: boolean;
    nativeWidth: number;
    usePanelWidth?: boolean;
    whenChildContentsActiveChanged: (isActive: boolean) => void;
    ScreenToLocalTransform: () => Transform;
    sidebarAddDocument: (doc: Doc | Doc[], suffix: string) => boolean;
    removeDocument: (doc: Doc | Doc[], suffix: string) => boolean;
    moveDocument: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean, annotationKey?: string) => boolean;
}
@observer
export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
    constructor(props: Readonly<FieldViewProps & ExtraProps>) {
        super(props);
        // this.props.dataDoc[this.sidebarKey] = new List<Doc>();  // bcz: can't do this here.  it blows away existing things and isn't a robust solution for making sure the field exists -- instead this should happen when the document is created and/or shared
    }
    _stackRef = React.createRef<CollectionStackingView>();
    @computed get allMetadata() {
        const keys = new Map<string, FieldResult<Field>>();
        DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc =>
            SearchBox.documentKeys(doc)
                .filter(key => key[0] && key[0] !== '_' && key[0] === key[0].toUpperCase())
                .map(key => keys.set(key, doc[key]))
        );
        return keys;
    }
    @computed get allHashtags() {
        const keys = new Set<string>();
        DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc => StrListCast(doc.tags).forEach(tag => keys.add(tag)));
        return Array.from(keys.keys())
            .filter(key => key[0])
            .filter(key => !key.startsWith('_') && (key[0] === '#' || key[0] === key[0].toUpperCase()))
            .sort();
    }
    @computed get allUsers() {
        const keys = new Set<string>();
        DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc => keys.add(StrCast(doc.author)));
        return Array.from(keys.keys()).sort();
    }
    get filtersKey() {
        return '_' + this.sidebarKey + '_childFilters';
    }

    anchorMenuClick = (anchor: Doc) => {
        const startup = StrListCast(this.props.rootDoc.childFilters)
            .map(filter => filter.split(':')[0])
            .join(' ');
        const target = Docs.Create.TextDocument(startup, {
            title: '-note-',
            annotationOn: this.props.rootDoc,
            _width: 200,
            _height: 50,
            _layout_fitWidth: true,
            _layout_autoHeight: true,
            _text_fontSize: StrCast(Doc.UserDoc().fontSize),
            _text_fontFamily: StrCast(Doc.UserDoc().fontFamily),
        });
        FormattedTextBox.SelectOnLoad = target[Id];
        FormattedTextBox.DontSelectInitialText = true;
        const link = DocUtils.MakeLink(anchor, target, { link_relationship: 'inline comment:comment on' });
        link && (link.link_displayLine = false);

        const taggedContent = this.childFilters()
            .filter(data => data.split(':')[0])
            .map(data => {
                const key = data.split(':')[0];
                const val = Field.Copy(this.allMetadata.get(key));
                Doc.GetProto(target)[key] = val;
                return {
                    type: 'dashField',
                    attrs: { fieldKey: key, docId: '', hideKey: false, editable: true },
                    marks: [{ type: 'pFontSize', attrs: { fontSize: '12px' } }, { type: 'strong' }, { type: 'user_mark', attrs: { userid: Doc.CurrentUserEmail, modified: 0 } }],
                };
            });

        if (!anchor.text) Doc.GetProto(anchor).text = '-selection-';
        const textLines: any = [
            {
                type: 'paragraph',
                attrs: { align: null, color: null, id: null, indent: null, inset: null, lineSpacing: null, paddingBottom: null, paddingTop: null },
                content: [
                    {
                        type: 'dashField',
                        marks: [
                            {
                                type: 'linkAnchor',
                                attrs: {
                                    allAnchors: [{ href: `/doc/${target[Id]}`, title: 'Anchored Selection', anchorId: `${target[Id]}` }],
                                    location: 'add:right',
                                    title: 'Anchored Selection',
                                    noPreview: true,
                                    docref: false,
                                },
                            },
                            { type: 'pFontSize', attrs: { fontSize: '8px' } },
                            { type: 'em' },
                        ],
                        attrs: { fieldKey: 'text', docId: anchor[Id], hideKey: true, editable: false },
                    },
                ],
            },
            { type: 'paragraph', attrs: { align: null, color: null, id: null, indent: null, inset: null, lineSpacing: null, paddingBottom: null, paddingTop: null } },
        ];
        const metadatatext = {
            type: 'paragraph',
            attrs: { align: null, color: null, id: null, indent: null, inset: null, lineSpacing: null, paddingBottom: null, paddingTop: null },
            content: taggedContent,
        };
        if (taggedContent.length) textLines.push(metadatatext);
        if (textLines.length) {
            Doc.GetProto(target).text = new RichTextField(
                JSON.stringify({
                    doc: {
                        type: 'doc',
                        content: textLines,
                    },
                    selection: { type: 'text', anchor: 4, head: 4 }, // set selection to middle paragraph
                }),
                ''
            );
        }
        this.addDocument(target);
        setTimeout(() => this._stackRef.current?.focusDocument(target, {}));
        return target;
    };
    makeDocUnfiltered = (doc: Doc) => {
        if (DocListCast(this.props.rootDoc[this.sidebarKey]).find(anno => Doc.AreProtosEqual(doc.layout_unrendered ? DocCast(doc.annotationOn) : doc, anno))) {
            if (this.props.layoutDoc[this.filtersKey]) {
                this.props.layoutDoc[this.filtersKey] = new List<string>();
            }
            return true;
        }
        return false;
    };

    get sidebarKey() {
        return this.props.fieldKey + '_sidebar';
    }
    filtersHeight = () => 38;
    screenToLocalTransform = () =>
        this.props
            .ScreenToLocalTransform()
            .translate(Doc.NativeWidth(this.props.dataDoc), 0)
            .scale(this.props.NativeDimScaling?.() || 1);
    panelWidth = () =>
        !this.props.showSidebar
            ? 0
            : this.props.usePanelWidth // [DocumentType.RTF, DocumentType.MAP].includes(this.props.layoutDoc.type as any)
            ? this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1)
            : ((NumCast(this.props.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth()) / NumCast(this.props.nativeWidth);
    panelHeight = () => this.props.PanelHeight() - this.filtersHeight();
    addDocument = (doc: Doc | Doc[]) => this.props.sidebarAddDocument(doc, this.sidebarKey);
    moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument(doc, targetCollection, addDocument, this.sidebarKey);
    removeDocument = (doc: Doc | Doc[]) => this.props.removeDocument(doc, this.sidebarKey);
    childFilters = () => [...StrListCast(this.props.layoutDoc._childFilters), ...StrListCast(this.props.layoutDoc[this.filtersKey])];
    layout_showTitle = () => 'title';
    setHeightCallback = (height: number) => this.props.setHeight?.(height + this.filtersHeight());
    sortByLinkAnchorY = (a: Doc, b: Doc) => {
        const ay = LinkManager.Links(a).length && DocCast(LinkManager.Links(a)[0].link_anchor_1).y;
        const by = LinkManager.Links(b).length && DocCast(LinkManager.Links(b)[0].link_anchor_1).y;
        return NumCast(ay) - NumCast(by);
    };
    render() {
        const renderTag = (tag: string) => {
            const active = StrListCast(this.props.rootDoc[this.filtersKey]).includes(`tags:${tag}:check`);
            return (
                <div key={tag} className={`sidebarAnnos-filterTag${active ? '-active' : ''}`} onClick={e => Doc.setDocFilter(this.props.rootDoc, 'tags', tag, 'check', true, this.sidebarKey, e.shiftKey)}>
                    {tag}
                </div>
            );
        };
        const renderMeta = (tag: string, dflt: FieldResult<Field>) => {
            const active = StrListCast(this.props.rootDoc[this.filtersKey]).includes(`${tag}:${dflt}:exists`);
            return (
                <div key={tag} className={`sidebarAnnos-filterTag${active ? '-active' : ''}`} onClick={e => Doc.setDocFilter(this.props.rootDoc, tag, dflt, 'exists', true, this.sidebarKey, e.shiftKey)}>
                    {tag}
                </div>
            );
        };
        const renderUsers = (user: string) => {
            const active = StrListCast(this.props.rootDoc[this.filtersKey]).includes(`author:${user}:check`);
            return (
                <div key={user} className={`sidebarAnnos-filterUser${active ? '-active' : ''}`} onClick={e => Doc.setDocFilter(this.props.rootDoc, 'author', user, 'check', true, this.sidebarKey, e.shiftKey)}>
                    {user}
                </div>
            );
        };
        // TODO: Calculation of the topbar is hardcoded and different for text nodes - it should all be the same and all be part of SidebarAnnos
        return !this.props.showSidebar ? null : (
            <div
                style={{
                    position: 'absolute',
                    pointerEvents: this.props.isContentActive() ? 'all' : undefined,
                    top: this.props.rootDoc.type !== DocumentType.RTF && StrCast(this.props.rootDoc._layout_showTitle) === 'title' ? 15 : 0,
                    right: 0,
                    background: this.props.styleProvider?.(this.props.rootDoc, this.props, StyleProp.WidgetColor),
                    width: `100%`,
                    height: '100%',
                }}>
                <div className="sidebarAnnos-tagList" style={{ height: this.filtersHeight() }} onWheel={e => e.stopPropagation()}>
                    {this.allUsers.map(renderUsers)}
                    {this.allHashtags.map(renderTag)}
                    {Array.from(this.allMetadata.keys())
                        .sort()
                        .map(key => renderMeta(key, this.allMetadata.get(key)))}
                    Hello
                </div>


                <div style={{ width: '100%', height: `calc(100% - 38px)`, position: 'relative' }}>
                    <CollectionStackingView
                        {...this.props}
                        setContentView={emptyFunction}
                        NativeWidth={returnZero}
                        NativeHeight={returnZero}
                        ref={this._stackRef}
                        PanelHeight={this.panelHeight}
                        PanelWidth={this.panelWidth}
                        childFilters={this.childFilters}
                        sortFunc={this.sortByLinkAnchorY}
                        setHeight={this.setHeightCallback}
                        isAnnotationOverlay={false}
                        select={emptyFunction}
                        NativeDimScaling={returnOne}
                        //childlayout_showTitle={this.layout_showTitle}
                        isAnyChildContentActive={returnFalse}
                        childDocumentsActive={this.props.isContentActive}
                        whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                        childHideDecorationTitle={returnTrue}
                        removeDocument={this.removeDocument}
                        moveDocument={this.moveDocument}
                        addDocument={this.addDocument}
                        ScreenToLocalTransform={this.screenToLocalTransform}
                        renderDepth={this.props.renderDepth + 1}
                        type_collection={CollectionViewType.Stacking}
                        fieldKey={this.sidebarKey}
                        pointerEvents={returnAll}
                    />
                </div>
            </div>
        );
    }
}
