import * as React from 'react';
import './CalendarManager.scss';
import { observer } from 'mobx-react';
import { action, computed, observable, runInAction, makeObservable } from 'mobx';
import { Doc, DocListCast } from '../../fields/Doc';
import { DocumentView } from '../views/nodes/DocumentView';
import { DictationOverlay } from '../views/DictationOverlay';
import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox';
import { MainViewModal } from '../views/MainViewModal';
import { TextField } from '@mui/material';
import Select from 'react-select';
import { SettingsManager } from './SettingsManager';
import { DocCast, StrCast } from '../../fields/Types';
import { SelectionManager } from './SelectionManager';
import { DocumentManager } from './DocumentManager';
import { DocData } from '../../fields/DocSymbols';
// import { DateRange, Range, RangeKeyDict } from 'react-date-range';
import { Button } from 'browndash-components';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { DateRangePicker } from '@adobe/react-spectrum';
import { IconLookup, faPlus } from '@fortawesome/free-solid-svg-icons';
import { Docs } from '../documents/Documents';
import { ObservableReactComponent } from '../views/ObservableReactComponent';
// import 'react-date-range/dist/styles.css';
// import 'react-date-range/dist/theme/default.css';

type CreationType = 'new-calendar' | 'existing-calendar' | 'manage-calendars';

interface CalendarSelectOptions {
    label: string;
    value: string;
}

const formatDateToString = (date: Date) => {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');

    return `${year}-${month}-${day}`;
};

// TODO: If doc is already part of a calendar, display that
// TODO: For a doc already in a calendar: give option to edit date range, delete from calendar

@observer
export class CalendarManager extends ObservableReactComponent<{}> {
    public static Instance: CalendarManager;
    @observable private isOpen = false;
    @observable private targetDoc: Doc | undefined; // the target document
    @observable private targetDocView: DocumentView | undefined; // the DocumentView of the target doc
    @observable private dialogueBoxOpacity = 1; // for the modal
    @observable private overlayOpacity = 0.4; // for the modal

    @observable private layoutDocAcls: boolean = false; // whether the layout doc or data doc's acls are to be used

    @observable private creationType: CreationType = 'new-calendar';

    @observable private existingCalendars: Doc[] = DocListCast(Doc.MyCalendars?.data);

    @computed get selectOptions() {
        return this.existingCalendars.map(calendar => ({ label: StrCast(calendar.title), value: StrCast(calendar.title) }));
    }

    @observable
    selectedExistingCalendarOption: CalendarSelectOptions | null = null;

    @observable
    calendarName: string = '';

    @observable
    calendarDescription: string = '';

    @observable
    errorMessage: string = '';

    @action
    setInterationType = (type: CreationType) => {
        this.errorMessage = '';
        this.calendarName = '';
        this.creationType = type;
    };

    public open = (target?: DocumentView, target_doc?: Doc) => {
        console.log('hi');
        runInAction(() => {
            this.targetDoc = target_doc || target?.Document;
            this.targetDocView = target;
            DictationOverlay.Instance.hasActiveModal = true;
            this.isOpen = this.targetDoc !== undefined;
        });
    };

    public close = action(() => {
        this.isOpen = false;
        TaskCompletionBox.taskCompleted = false;
        setTimeout(
            action(() => {
                DictationOverlay.Instance.hasActiveModal = false;
                this.targetDoc = undefined;
            }),
            500
        );
        this.layoutDocAcls = false;
    });

    constructor(props: {}) {
        super(props);
        CalendarManager.Instance = this;
        makeObservable(this);
    }

    componentDidMount(): void {}

    @action
    handleSelectChange = (option: any) => {
        let selectOpt = option as CalendarSelectOptions;
        this.selectedExistingCalendarOption = selectOpt;
        this.calendarName = selectOpt.value; // or label
    };

    @action
    handleTextFieldChange = (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
        this.calendarName = event.target.value;
    };

    // TODO: Make undoable
    private addToCalendar = () => {
        let docs = SelectionManager.Views.length < 2 ? [this.targetDoc] : SelectionManager.Views.map(docView => docView.Document);
        const targetDoc = this.layoutDocAcls ? docs[0] : docs[0]?.[DocData]; // doc to add to calendar

        if (targetDoc) {
            let calendar: Doc;
            if (this.creationType === 'new-calendar') {
                if (!this.existingCalendars.find(doc => StrCast(doc.title) === this.calendarName)) {
                    calendar = Docs.Create.CalendarDocument(
                        {
                            title: this.calendarName,
                            description: this.calendarDescription,
                        },
                        []
                    );
                } else {
                    this.errorMessage = 'Calendar with this name already exists';
                    return;
                }
            } else {
                // find existing calendar based on selected name (should technically always find one)
                const existingCalendar = this.existingCalendars.find(calendar => StrCast(calendar.title) === this.calendarName);
                if (existingCalendar) calendar = existingCalendar;
                else {
                    this.errorMessage = 'Must select an existing calendar';
                    return;
                }
            }
            // Get start and end date strings
            const startDateStr = formatDateToString(this.selectedDateRange.start);
            const endDateStr = formatDateToString(this.selectedDateRange.end);

            const subDocEmbedding = Doc.MakeEmbedding(targetDoc); // embedding
            subDocEmbedding.embedContainer = calendar; // set embed container
            subDocEmbedding.date_range = `${startDateStr}-${endDateStr}`; // set subDoc date range

            Doc.AddDocToList(calendar, 'data', subDocEmbedding); // add embedded subDoc to calendar

            if (this.creationType === 'new-calendar') {
                Doc.AddDocToList(Doc.MyCalendars, 'data', calendar); // add to new calendar to dashboard calendars
            }
        }
    };

    private focusOn = (contents: string) => {
        const title = this.targetDoc ? StrCast(this.targetDoc.title) : '';
        const docs = SelectionManager.Views.length > 1 ? SelectionManager.Views.map(docView => docView.Document) : [this.targetDoc];
        return (
            <span
                className="focus-span"
                title={title}
                onClick={() => {
                    if (this.targetDoc && this.targetDocView && docs.length === 1) {
                        DocumentManager.Instance.showDocument(this.targetDoc, { willZoomCentered: true });
                    }
                }}
                onPointerEnter={action(() => {
                    if (docs.length) {
                        docs.forEach(doc => doc && Doc.BrushDoc(doc));
                        this.dialogueBoxOpacity = 0.1;
                        this.overlayOpacity = 0.1;
                    }
                })}
                onPointerLeave={action(() => {
                    if (docs.length) {
                        docs.forEach(doc => doc && Doc.UnBrushDoc(doc));
                        this.dialogueBoxOpacity = 1;
                        this.overlayOpacity = 0.4;
                    }
                })}>
                {contents}
            </span>
        );
    };

    @observable
    selectedDateRange: any = [
        {
            start: new Date(),
            end: new Date(),
        },
    ];

    @action
    setSelectedDateRange = (range: any) => {
        this.selectedDateRange = range;
    };

    @computed
    get createButtonActive() {
        if (this.calendarName.length === 0 || this.errorMessage.length > 0) return false; // disabled if no calendar name
        let startDate: Date | undefined;
        let endDate: Date | undefined;
        try {
            startDate = this.selectedDateRange[0].startDate;
            endDate = this.selectedDateRange[0].endDate;
        } catch (e: any) {
            return false; // disabled
        }
        if (!startDate || !endDate) return false; // disabled if any is undefined
        return true;
    }

    @computed
    get calendarInterface() {
        let docs = SelectionManager.Views.length < 2 ? [this.targetDoc] : SelectionManager.Views.map(docView => docView.Document);
        const targetDoc = this.layoutDocAcls ? docs[0] : docs[0]?.[DocData];

        const currentDate = new Date();

        return (
            <div
                className="calendar-interface"
                style={{
                    background: SettingsManager.userBackgroundColor,
                    color: StrCast(Doc.UserDoc().userColor),
                }}>
                <p className="selected-doc-title" style={{ color: SettingsManager.userColor }}>
                    <b>{this.focusOn(docs.length < 2 ? StrCast(targetDoc?.title, 'this document') : '-multiple-')}</b>
                </p>
                <div className="creation-type-container">
                    <div className={`calendar-creation ${this.creationType === 'new-calendar' ? 'calendar-creation-selected' : ''}`} onClick={e => this.setInterationType('new-calendar')}>
                        Add to New Calendar
                    </div>
                    <div className={`calendar-creation ${this.creationType === 'existing-calendar' ? 'calendar-creation-selected' : ''}`} onClick={e => this.setInterationType('existing-calendar')}>
                        Add to Existing calendar
                    </div>
                </div>
                <div className="choose-calendar-container">
                    {this.creationType === 'new-calendar' ? (
                        <TextField
                            fullWidth
                            onChange={this.handleTextFieldChange}
                            placeholder="Enter calendar name..."
                            variant="filled"
                            style={{
                                backgroundColor: 'white',
                                color: 'black',
                                borderRadius: '5px',
                            }}
                        />
                    ) : (
                        <Select
                            className="existing-calendar-search"
                            placeholder="Search for existing calendar..."
                            isClearable
                            isSearchable
                            options={this.selectOptions}
                            value={this.selectedExistingCalendarOption}
                            onChange={this.handleSelectChange}
                            styles={{
                                control: () => ({
                                    display: 'inline-flex',
                                    width: '100%',
                                }),
                                indicatorSeparator: () => ({
                                    display: 'inline-flex',
                                    visibility: 'hidden',
                                }),
                                indicatorsContainer: () => ({
                                    display: 'inline-flex',
                                    textDecorationColor: 'black',
                                }),
                                valueContainer: () => ({
                                    display: 'inline-flex',
                                    fontStyle: StrCast(Doc.UserDoc().userColor),
                                    color: StrCast(Doc.UserDoc().userColor),
                                    width: '100%',
                                }),
                            }}></Select>
                    )}
                </div>
                <div className="date-range-picker-container">
                    <DateRangePicker value={this.selectedDateRange} onChange={v => this.setSelectedDateRange(v)} label="Date range" />
                </div>
                <div className="create-button-container">
                    <Button active={this.createButtonActive} onClick={() => {}} text="Add to Calendar" iconPlacement="right" icon={<FontAwesomeIcon icon={faPlus as IconLookup} />} />
                </div>
            </div>
        );
    }

    render() {
        return <MainViewModal contents={this.calendarInterface} isDisplayed={this.isOpen} interactive={true} dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} overlayDisplayedOpacity={this.overlayOpacity} closeOnExternalClick={this.close} />;
    }
}
