import { action, makeObservable, IReactionDisposer, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Docs } from '../../documents/Documents';
import { DocumentType } from '../../documents/DocumentTypes';
import { FieldView } from './FieldView';
import { DateField } from '../../../fields/DateField';
import { Doc } from '../../../fields/Doc';
import { Networking } from '../../Network';

import './TaskBox.scss';
import { GoogleAuthenticationManager } from '../../apis/GoogleAuthenticationManager';

/**
 * Props (reference to document) for Task Box
 */

interface TaskBoxProps {
    Document: Doc;
}

/**
 * TaskBox class for adding task information + completing tasks
 */
@observer
export class TaskBox extends React.Component<TaskBoxProps> {
    /**
     * Method to reuturn the
     * @param fieldStr
     * @returns
     */
    public static LayoutString(fieldStr: string) {
        return FieldView.LayoutString(TaskBox, fieldStr);
    }

    /**
     * Method to update the task description
     * @param e - event of changing the description box input
     */

    @action
    updateText = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
        this.props.Document.text = e.target.value;
    };

    /**
     * Method to update the task title
     * @param e - event of changing the title box input
     */
    @action
    updateTitle = (e: React.ChangeEvent<HTMLInputElement>) => {
        this.props.Document.title = e.target.value;
    };

    /**
     * Method to update the all day status
     * @param e - event of changing the all day checkbox
     */
    @action
    updateAllDay = (e: React.ChangeEvent<HTMLInputElement>) => {
        this.props.Document.$task_allDay = e.target.checked;

        if (e.target.checked) {
            delete this.props.Document.$task_startTime;
            delete this.props.Document.$task_endTime;
        }

        this.setTaskDateRange();
    };

    /**
     * Method to update the task start time
     * @param e - event of changing the start time input
     */
    @action
    updateStart = (e: React.ChangeEvent<HTMLInputElement>) => {
        const newStart = new Date(e.target.value);

        this.props.Document.$task_startTime = new DateField(newStart);

        const endDate = this.props.Document.$task_endTime instanceof DateField ? this.props.Document.$task_endTime.date : undefined;
        if (endDate && newStart > endDate) {
            // Alert user
            alert('Start time cannot be after end time. End time has been adjusted.');

            // Fix end time
            const adjustedEnd = new Date(newStart.getTime() + 60 * 60 * 1000);
            this.props.Document.$task_endTime = new DateField(adjustedEnd);
        }

        this.setTaskDateRange();
    };

    /**
     * Method to update the task end time
     * @param e - event of changing the end time input
     */
    @action
    updateEnd = (e: React.ChangeEvent<HTMLInputElement>) => {
        const newEnd = new Date(e.target.value);

        this.props.Document.$task_endTime = new DateField(newEnd);

        const startDate = this.props.Document.$task_startTime instanceof DateField ? this.props.Document.$task_startTime.date : undefined;
        if (startDate && newEnd < startDate) {
            // Alert user
            alert('End time cannot be before start time. Start time has been adjusted.');

            // Fix start time
            const adjustedStart = new Date(newEnd.getTime() - 60 * 60 * 1000);
            this.props.Document.$task_startTime = new DateField(adjustedStart);
        }

        this.setTaskDateRange();
    };

    /**
     * Method to update the task date range
     */
    @action
    setTaskDateRange() {
        const doc = this.props.Document;

        if (doc.$task_allDay) {
            const range = typeof doc.$task_dateRange === 'string' ? doc.$task_dateRange.split('|') : [];
            const dateStr = range[0] ?? new Date().toISOString().split('T')[0]; // default to today

            doc.$task_dateRange = `${dateStr}|${dateStr}`;
            doc.$task_allDay = true;
        } else {
            const startField = doc.$task_startTime;
            const endField = doc.$task_endTime;
            const startDate = startField instanceof DateField ? startField.date : null;
            const endDate = endField instanceof DateField ? endField.date : null;

            if (startDate && endDate && !isNaN(startDate.getTime()) && !isNaN(endDate.getTime())) {
                doc.$task_dateRange = `${startDate.toISOString()}|${endDate.toISOString()}`;
                doc.$task_allDay = false;
            }
        }
    }

    /**
     * Method to set task's completion status
     * @param e - event of changing the "completed" input checkbox
     */

    @action
    toggleComplete = (e: React.ChangeEvent<HTMLInputElement>) => {
        this.props.Document.$task_completed = e.target.checked;
    };

    /**
     * Constructor for the task box
     * @param props - props containing the document reference
     */

    constructor(props: TaskBoxProps) {
        super(props);
        makeObservable(this);
    }

    _heightDisposer?: IReactionDisposer;
    _widthDisposer?: IReactionDisposer;

    componentDidMount() {
        this.setTaskDateRange();

        const doc = this.props.Document;
        this._heightDisposer = reaction(
            () => Number(doc._height),
            height => {
                const minHeight = Number(doc.height_min ?? 0);
                if (!isNaN(height) && height < minHeight) {
                    doc._height = minHeight;
                }
            }
        );

        this._widthDisposer = reaction(
            () => Number(doc._width),
            width => {
                const minWidth = Number(doc.width_min ?? 0);
                if (!isNaN(width) && width < minWidth) {
                    doc._width = minWidth;
                }
            }
        );
    }

    componentWillUnmount() {
        this._heightDisposer?.();
        this._widthDisposer?.();
    }

    /**
     * Method to render the task box
     * @returns - HTML with taskbox components
     */

    render() {
        function toLocalDateTimeString(date: Date): string {
            const pad = (n: number) => n.toString().padStart(2, '0');
            return date.getFullYear() + '-' + pad(date.getMonth() + 1) + '-' + pad(date.getDate()) + 'T' + pad(date.getHours()) + ':' + pad(date.getMinutes());
        }

        const doc = this.props.Document;

        const taskDesc = typeof doc.text === 'string' ? doc.text : '';
        const taskTitle = typeof doc.title === 'string' ? doc.title : '';
        const allDay = !!doc.$task_allDay;
        const isCompleted = !!this.props.Document.$task_completed;

        const startTime = doc.$task_startTime instanceof DateField && doc.$task_startTime.date instanceof Date ? toLocalDateTimeString(doc.$task_startTime.date) : '';

        const endTime = doc.$task_endTime instanceof DateField && doc.$task_endTime.date instanceof Date ? toLocalDateTimeString(doc.$task_endTime.date) : '';

        return (
            <div className="task-manager-container">
                <input className="task-manager-title" type="text" placeholder="Task Title" value={taskTitle} onChange={this.updateTitle} disabled={isCompleted} style={{ opacity: isCompleted ? 0.7 : 1 }} />

                <textarea className="task-manager-description" placeholder="What’s your task?" value={taskDesc} onChange={this.updateText} disabled={isCompleted} style={{ opacity: isCompleted ? 0.7 : 1 }} />

                <div className="task-manager-checkboxes">
                    <label className="task-manager-allday" style={{ opacity: isCompleted ? 0.7 : 1 }}>
                        <input type="checkbox" checked={allDay} onChange={this.updateAllDay} disabled={isCompleted} />
                        All day
                        {allDay && (
                            <input
                                type="date"
                                value={(() => {
                                    const rawRange = doc.$task_dateRange;
                                    if (typeof rawRange !== 'string') return '';
                                    const datePart = rawRange.split('|')[0];
                                    if (!datePart) return '';
                                    const d = new Date(datePart);
                                    return !isNaN(d.getTime()) ? d.toISOString().split('T')[0] : '';
                                })()}
                                onChange={e => {
                                    const newDate = new Date(e.target.value);
                                    if (!isNaN(newDate.getTime())) {
                                        const dateStr = e.target.value;
                                        if (dateStr) {
                                            doc.$task_dateRange = `${dateStr}T00:00:00|${dateStr}T00:00:00`;
                                        }
                                    }
                                }}
                                disabled={isCompleted}
                                style={{ marginLeft: '8px' }}
                            />
                        )}
                    </label>

                    <label className="task-manager-complete">
                        <input type="checkbox" checked={isCompleted} onChange={this.toggleComplete} />
                        Complete
                    </label>

                    <button
                        className="task-manager-google"
                        onClick={async event => {
                            event.preventDefault();

                            console.log('GT button clicked');
                            try {
                                const token = await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
                                console.log('Got token', token);

                                const response = await fetch('/googleTasks/create', {
                                    method: 'POST',
                                    credentials: 'include',
                                    headers: {
                                        'Content-Type': 'application/json',
                                        Authorization: `Bearer ${token}`,
                                    },
                                    body: JSON.stringify({
                                        title: taskTitle || 'Untitled Task',
                                        notes: taskDesc,
                                        due: allDay ? new Date(String(doc.$task_dateRange)?.split('|')[0]).toISOString() : (doc.$task_endTime instanceof DateField && doc.$task_endTime.date?.toISOString()) || undefined,
                                        status: doc.$task_completed ? 'completed' : 'needsAction',
                                        completed: doc.$task_completed ? new Date().toISOString() : undefined,
                                    }),
                                });

                                const result = await response.json();
                                console.log('Google Task result:', result);

                                if (result?.id) {
                                    alert('✅ Task sent to Google Tasks!');
                                } else {
                                    alert(`❌ Failed: ${result?.error?.message || 'Unknown error'}`);
                                }
                            } catch (err) {
                                console.error('Fetch error:', err);
                                alert('❌ Task creation failed.');
                            }
                        }}>
                        Add to Google
                    </button>
                </div>

                {!allDay && (
                    <div className="task-manager-times" style={{ opacity: isCompleted ? 0.7 : 1 }}>
                        <label>
                            Start:
                            <input type="datetime-local" value={startTime} onChange={this.updateStart} disabled={isCompleted} />
                        </label>
                        <label>
                            End:
                            <input type="datetime-local" value={endTime} onChange={this.updateEnd} disabled={isCompleted} />
                        </label>
                    </div>
                )}
            </div>
        );
    }
}

Docs.Prototypes.TemplateMap.set(DocumentType.TASK, {
    layout: { view: TaskBox, dataField: 'text' },
    options: {
        acl: '',
        _height: 35,
        _xMargin: 10,
        _yMargin: 10,
        _layout_autoHeight: true,
        _layout_nativeDimEditable: true,
        _layout_reflowVertical: true,
        _layout_reflowHorizontal: true,
        task: '',
        defaultDoubleClick: 'ignore',
        systemIcon: 'BsCheckSquare',
        height_min: 300,
        width_min: 300,
    },
});
