import { action, makeObservable, observable } from 'mobx';
import * as React from 'react';
import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc';
import { List } from '../../../../fields/List';
import { emptyFunction } from '../../../../Utils';
import { Docs } from '../../../documents/Documents';
import { DocumentType } from '../../../documents/DocumentTypes';
import { CollectionView } from '../../collections/CollectionView';
import { ViewBoxAnnotatableComponent } from '../../DocComponent';
import { DocumentView } from '../DocumentView';
import { FieldView, FieldViewProps } from '../FieldView';
import { DragManager } from '../../../util/DragManager';
import { RTFCast, StrCast, toList } from '../../../../fields/Types';
import { undoable } from '../../../util/UndoManager';
// Scrapbook view: a container that lays out its child items in a grid/template
export class ScrapbookBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
    @observable createdDate: string;

    constructor(props: FieldViewProps) {
        super(props);
        makeObservable(this);
        this.createdDate = this.getFormattedDate();

        // ensure we always have a List<Doc> in dataDoc['items']
        if (!this.dataDoc[this.fieldKey]) {
            this.dataDoc[this.fieldKey] = new List<Doc>();
        }
        this.createdDate = this.getFormattedDate();
        this.setTitle();
    }

    public static LayoutString(fieldStr: string) {
        return FieldView.LayoutString(ScrapbookBox, fieldStr);
    }

    getFormattedDate(): string {
        return new Date().toLocaleDateString(undefined, {
            year: 'numeric',
            month: 'short',
            day: 'numeric',
        });
    }

    @action
    setTitle() {
        const title = `Scrapbook - ${this.createdDate}`;
        if (this.dataDoc.title !== title) {
            this.dataDoc.title = title;

            const image = Docs.Create.TextDocument('image');
            image.accepts_docType = DocumentType.IMG;
            image.accepts_tagType = 'LANDSCAPE' //should i be writing fields on this doc? clarify diff between this and proto, original
            const placeholder = new Doc();
            placeholder.proto = image;
            placeholder.original = image;
            placeholder._width = 250;
            placeholder._height = 200;
            placeholder.x = 0;
            placeholder.y = -100;
            //placeholder.overrideFields = new List<string>(['x', 'y']);  // shouldn't need to do this for layout fields since the placeholder already overrides its protos
            
            const summary = Docs.Create.TextDocument('summary');
            summary.accepts_docType = DocumentType.RTF;
            summary.accepts_tagType = 'caption';
            //summary.$tags_chat = new List<string>(['lengthy description']); //we need to go back and set this
            const placeholder2 = new Doc();
            placeholder2.proto = summary;
            placeholder2.original = summary;
            placeholder2.x = 0;
            placeholder2.y = 200;
            placeholder2._width = 250;
            //placeholder2.overrideFields = new List<string>(['x', 'y', '_width']); // shouldn't need to do this for layout fields since the placeholder already overrides its protos
            
            const sidebar = Docs.Create.TextDocument('sidebar');
            sidebar.accepts_docType = DocumentType.RTF;
            sidebar.accepts_tagType = 'lengthy description'; //accepts_textType = 'lengthy description'
            const placeholder3 = new Doc();
            placeholder3.proto = sidebar;
            placeholder3.original = sidebar;
            placeholder3.x = 280;
            placeholder3.y = -50;
            placeholder3._width = 50; 
            placeholder3._height = 200;

          

            const internalImg = Docs.Create.TextDocument('image internal');
            internalImg.accepts_docType = DocumentType.IMG;
            internalImg.accepts_tagType = 'PERSON' //should i be writing fields on this doc? clarify diff between this and proto, original
            const placeholder5 = new Doc();
            placeholder5.proto = image;
            placeholder5.original = image;
            placeholder5._width = 50;
            placeholder5._height = 100;
            placeholder5.x = 0;
            placeholder5.y = -100;

            const collection = Docs.Create.StackingDocument([placeholder5], { _width: 300, _height: 300, title: "internal coll" });
            //collection.accepts_docType = DocumentType.COL; don't mark this field
            const placeholder4 = new Doc();
            placeholder4.proto = collection;
            placeholder4.original = collection;
            placeholder4.x = -200;
            placeholder4.y = -100;
            placeholder4._width = 100;
            placeholder4._height = 200;
            /*note-to-self
            would doing:

            const collection = Docs.Create.ScrapbookDocument([placeholder, placeholder2, placeholder3]);
            create issues with references to the same object?*/

            /*note-to-self
            Should we consider that there are more collections than just COL type collections?
            when spreading*/



           /*note-to-self
           difference between passing a new List<Doc> versus just the raw array?
           */

            this.dataDoc[this.fieldKey] = new List<Doc>([placeholder, placeholder2, placeholder3, placeholder4]);

          
        }
    }

    componentDidMount() {
        this.setTitle();
    }

    childRejectDrop = (de: DragManager.DropEvent, subView?: DocumentView) => {
        return true; // disable dropping documents onto any child of the scrapbook.
    };
    rejectDrop = (de: DragManager.DropEvent, subView?: DocumentView) => {
        // Test to see if the dropped doc is dropped on an acceptable location (anywerhe? on a specific box).
        // const draggedDocs = de.complete.docDragData?.draggedDocuments;
        return false; // allow all Docs to be dropped onto scrapbook -- let filterAddDocument make the final decision.
    };

    filterAddDocument = (docIn: Doc | Doc[]) => {
        const docs = toList(docIn); //The docs being added to the scrapbook

        // 1) Grab all template slots:
        const slots = DocListCast(this.dataDoc[this.fieldKey]);

        // 2) recursive unwrap:
        const unwrap = (items: Doc[]): Doc[] =>
            items.flatMap(d =>
            d.$type === DocumentType.COL
                ? unwrap(DocListCast(d[Doc.LayoutDataKey(d)]))
                : [d]
            );

        // 3) produce a flat list of every doc, unwrapping any number of nested COLs
        const allDocs: Doc[] = unwrap(slots);
     

        if (docs?.length === 1) {
            const placeholder = allDocs.filter(d =>

                 (d.accepts_docType === docs[0].$type ||   // match fields based on type, or by analyzing content .. simple example of matching text in placeholder to dropped doc's type
                  RTFCast(d[Doc.LayoutDataKey(d)])?.Text.includes(StrCast(docs[0].$type)))
            ); // prettier-ignore

            //DocListCast(this.Document.items).map(doc => DocListCast(doc[Doc.LayoutDataKey(doc)])

            if (placeholder) {
                /**Look at the autotags and see what matches*RTFCast(d[Doc.LayoutDataKey(d)])?.Text*/
                // ugh.  we have to tell the underlying view not to add the Doc so that we can add it where we want it.
                // However, returning 'false' triggers an undo. so this settimeout is needed to make the assignment happen after the undo.
                setTimeout(
                    undoable(() => {

                        const slotTagsList: Set<string>[] = placeholder.map(doc =>
                            new Set<string>(StrListCast(doc.$tags_chat))
                          );
                          // turn docs[0].$tags_chat into a Set
                        const targetTags = new Set(StrListCast(docs[0].$tags_chat));

                        //StrListCast(placeholder.overrideFields).map(field => (docs[0][field] = placeholder[field])); // // shouldn't need to do this for layout fields since the placeholder already overrides its protos
                        
                            // find the first placeholder that shares *any* tag
                        const match = placeholder.find(ph =>
                            ph.accepts_tagType != null &&          // make sure it actually has one
                            targetTags.has(StrCast(ph.accepts_tagType))     // test membership in the Set
                            //StrListCast(ph.$tags_chat).some(tag => targetTags.has(tag))
                        );
                        if (match) {
                            match.proto = docs[0];
                          }

                        /*const chosenPlaceholder = placeholder.find(d => 
                            pl = new Set<string>(StrListCast(d.$tags_chat)
                            
                            d.$tags_chat && d.$tags_chat[0].equals(docs[0].$tags_chat)); //why [0]
                        if (chosenPlaceholder){
                            chosenPlaceholder.proto = docs[0];}*/
                         //excess if statement??   
                    }, 'Scrapbook add')
                );
                return false;
            }
        }
        return false;
    };

    render() {
        return (
            <div style={{ background: 'beige', width: '100%', height: '100%' }}>
                <CollectionView
                    {...this._props} //
                    setContentViewBox={emptyFunction}
                    rejectDrop={this.rejectDrop}
                    childRejectDrop={this.childRejectDrop}
                    filterAddDocument={this.filterAddDocument}
                />
                {/* <div style={{ border: '1px black', borderStyle: 'dotted', position: 'absolute', top: '50%', width: '100%', textAlign: 'center' }}>Drop an image here</div> */}
            </div>
        );
    }
}

// Register scrapbook
Docs.Prototypes.TemplateMap.set(DocumentType.SCRAPBOOK, {
    layout: { view: ScrapbookBox, dataField: 'items' },
    options: {
        acl: '',
        _height: 200,
        _xMargin: 10,
        _yMargin: 10,
        _layout_fitWidth: false,
        _layout_autoHeight: true,
        _layout_reflowVertical: true,
        _layout_reflowHorizontal: true,
        _freeform_fitContentsToBox: true,
        defaultDoubleClick: 'ignore',
        systemIcon: 'BsImages',
    },
});
