/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import { DateRangePicker, Provider, defaultTheme } from '@adobe/react-spectrum';
import { IconLookup, faPlus } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { TextField } from '@mui/material';
import { Button } from 'browndash-components';
import { action, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import Select from 'react-select';
import { Doc, DocListCast } from '../../fields/Doc';
import { DocData } from '../../fields/DocSymbols';
import { StrCast } from '../../fields/Types';
import { Docs } from '../documents/Documents';
import { MainViewModal } from '../views/MainViewModal';
import { ObservableReactComponent } from '../views/ObservableReactComponent';
import { DocumentView } from '../views/nodes/DocumentView';
import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox';
import './CalendarManager.scss';
import { SnappingManager } from './SnappingManager';
// 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 formatCalendarDateToString = (calendarDate: any) => {
    console.log('Formatting the following date: ', calendarDate);
    const date = new Date(calendarDate.year, calendarDate.month - 1, calendarDate.day);
    console.log(typeof 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<{}> {
    // eslint-disable-next-line no-use-before-define
    public static Instance: CalendarManager;
    @observable private isOpen = false;
    @observable private targetDoc: Doc | undefined = undefined; // the target document
    @observable private targetDocView: DocumentView | undefined = undefined; // the DocumentView of the target doc
    @observable private dialogueBoxOpacity = 1; // 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, targetDoc?: Doc) => {
        runInAction(() => {
            this.targetDoc = targetDoc || target?.Document;
            this.targetDocView = target;
            this.isOpen = this.targetDoc !== undefined;
        });
    };

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

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

    componentDidMount(): void {}

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

    @action
    handleCalendarTitleChange = (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
        console.log('Existing calendars: ', this.existingCalendars);
        this.calendarName = event.target.value;
    };

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

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

        console.log(targetDoc);
        if (targetDoc) {
            let calendar: Doc;
            if (this.creationType === 'new-calendar') {
                if (!this.existingCalendars.find(doc => StrCast(doc.title) === this.calendarName)) {
                    console.log('creating...');
                    calendar = Docs.Create.CalendarDocument(
                        {
                            title: this.calendarName,
                            description: this.calendarDescription,
                        },
                        []
                    );
                    console.log('successful calendar creation');
                } 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(findCal => StrCast(findCal.title) === this.calendarName);
                if (existingCalendar) calendar = existingCalendar;
                else {
                    this.errorMessage = 'Must select an existing calendar';
                    return;
                }
            }
            // Get start and end date strings
            const startDateStr = formatCalendarDateToString(this.selectedDateRange.start);
            const endDateStr = formatCalendarDateToString(this.selectedDateRange.end);

            console.log('start date: ', startDateStr);
            console.log('end date: ', endDateStr);

            const subDocEmbedding = Doc.MakeEmbedding(targetDoc); // embedding
            console.log('subdoc embedding', subDocEmbedding);
            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

            console.log('my calendars: ', Doc.MyCalendars);
            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 = DocumentView.Selected().length > 1 ? DocumentView.Selected().map(docView => docView.Document) : [this.targetDoc];
        return (
            <span
                className="focus-span"
                title={title}
                onClick={() => {
                    if (this.targetDoc && this.targetDocView && docs.length === 1) {
                        DocumentView.showDocument(this.targetDoc, { willZoomCentered: true });
                    }
                }}
                onPointerEnter={action(() => {
                    if (docs.length) {
                        docs.forEach(doc => doc && Doc.BrushDoc(doc));
                        this.dialogueBoxOpacity = 0.1;
                    }
                })}
                onPointerLeave={action(() => {
                    if (docs.length) {
                        docs.forEach(doc => doc && Doc.UnBrushDoc(doc));
                        this.dialogueBoxOpacity = 1;
                    }
                })}>
                {contents}
            </span>
        );
    };

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

    @action
    setSelectedDateRange = (range: any) => {
        console.log('Range: ', range);
        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.start;
            endDate = this.selectedDateRange.end;
            console.log(startDate);
            console.log(endDate);
        } catch (e: any) {
            console.log(e);
            return false; // disabled
        }
        if (!startDate || !endDate) return false; // disabled if any is undefined
        return true;
    }

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

        return (
            <div
                className="calendar-interface"
                style={{
                    background: SnappingManager.userBackgroundColor,
                    color: StrCast(Doc.UserDoc().userColor),
                }}>
                <p className="selected-doc-title" style={{ color: SnappingManager.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={() => this.setInterationType('new-calendar')}>
                        Add to New Calendar
                    </div>
                    <div className={`calendar-creation ${this.creationType === 'existing-calendar' ? 'calendar-creation-selected' : ''}`} onClick={() => this.setInterationType('existing-calendar')}>
                        Add to Existing calendar
                    </div>
                </div>
                <div className="choose-calendar-container">
                    {this.creationType === 'new-calendar' ? (
                        <TextField
                            fullWidth
                            onChange={this.handleCalendarTitleChange}
                            label="Calendar name"
                            placeholder="Enter a 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%',
                                }),
                            }}
                        />
                    )}
                </div>
                <div className="description-container">
                    <TextField
                        fullWidth
                        multiline
                        label="Calendar description"
                        placeholder="Enter a description (optional)..."
                        onChange={this.handleCalendarDescriptionChange}
                        variant="filled"
                        style={{
                            backgroundColor: 'white',
                            color: 'black',
                            borderRadius: '5px',
                        }}
                    />
                </div>
                <div className="date-range-picker-container">
                    <div>Select a date range: </div>
                    <Provider theme={defaultTheme}>
                        <DateRangePicker aria-label="Select a date range" value={this.selectedDateRange} onChange={v => this.setSelectedDateRange(v)} />
                    </Provider>
                </div>
                {this.createButtonActive && (
                    <div className="create-button-container">
                        <Button onClick={() => this.addToCalendar()} text="Add to Calendar" iconPlacement="right" icon={<FontAwesomeIcon icon={faPlus as IconLookup} />} />
                    </div>
                )}
            </div>
        );
    }

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