import React = require('react');
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components';
import { action, computed, IReactionDisposer, observable, ObservableMap, reaction } from 'mobx';
import { observer } from 'mobx-react';
import { ColorState } from 'react-color';
import { Doc, Opt } from '../../../fields/Doc';
import { returnFalse, setupMoveUpEvents, unimplementedFunction, Utils } from '../../../Utils';
import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT';
import { DocumentType } from '../../documents/DocumentTypes';
import { SelectionManager } from '../../util/SelectionManager';
import { SettingsManager } from '../../util/SettingsManager';
import { AntimodeMenu, AntimodeMenuProps } from '../AntimodeMenu';
import { LinkPopup } from '../linking/LinkPopup';
import './AnchorMenu.scss';
import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup';

@observer
export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
    static Instance: AnchorMenu;

    private _disposer: IReactionDisposer | undefined;
    private _commentRef = React.createRef<HTMLDivElement>();
    private _cropRef = React.createRef<HTMLDivElement>();

    @observable private highlightColor: string = 'rgba(245, 230, 95, 0.616)';

    @observable public Status: 'marquee' | 'annotation' | '' = '';

    // GPT additions
    @observable private selectedText: string = '';
    @action
    public setSelectedText = (txt: string) => (this.selectedText = txt);

    public onMakeAnchor: () => Opt<Doc> = () => undefined; // Method to get anchor from text search

    public OnCrop: (e: PointerEvent) => void = unimplementedFunction;
    public OnClick: (e: PointerEvent) => void = unimplementedFunction;
    public OnAudio: (e: PointerEvent) => void = unimplementedFunction;
    public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
    public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
    public Highlight: (color: string, isTargetToggler: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>, addAsAnnotation?: boolean) => Opt<Doc> = (color: string, isTargetToggler: boolean) => undefined;
    public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => undefined;
    public Delete: () => void = unimplementedFunction;
    public PinToPres: () => void = unimplementedFunction;
    public MakeTargetToggle: () => void = unimplementedFunction;
    public ShowTargetTrail: () => void = unimplementedFunction;
    public IsTargetToggler: () => boolean = returnFalse;
    public get Active() {
        return this._left > 0;
    }

    constructor(props: Readonly<{}>) {
        super(props);

        AnchorMenu.Instance = this;
        AnchorMenu.Instance._canFade = false;
    }

    componentWillUnmount() {
        this._disposer?.();
    }

    componentDidMount() {
        this._disposer = reaction(
            () => SelectionManager.Views().slice(),
            selected => AnchorMenu.Instance.fadeOut(true)
        );
    }

    /**
     * Invokes the API with the selected text and stores it in the summarized text.
     * @param e pointer down event
     */
    gptSummarize = async (e: React.PointerEvent) => {
        // move this logic to gptpopup, need to implement generate again
        GPTPopup.Instance.setVisible(true);
        GPTPopup.Instance.setMode(GPTPopupMode.SUMMARY);
        GPTPopup.Instance.setLoading(true);

        try {
            const res = await gptAPICall(this.selectedText, GPTCallType.SUMMARY);
            GPTPopup.Instance.setText(res || 'Something went wrong.');
        } catch (err) {
            console.error(err);
        }
        GPTPopup.Instance.setLoading(false);
    };

    pointerDown = (e: React.PointerEvent) => {
        setupMoveUpEvents(
            this,
            e,
            (e: PointerEvent) => {
                this.StartDrag(e, this._commentRef.current!);
                return true;
            },
            returnFalse,
            e => this.OnClick?.(e)
        );
    };

    audioDown = (e: React.PointerEvent) => {
        setupMoveUpEvents(this, e, returnFalse, returnFalse, e => this.OnAudio?.(e));
    };

    cropDown = (e: React.PointerEvent) => {
        setupMoveUpEvents(
            this,
            e,
            (e: PointerEvent) => {
                this.StartCropDrag(e, this._cropRef.current!);
                return true;
            },
            returnFalse,
            e => this.OnCrop?.(e)
        );
    };

    @action
    highlightClicked = (e: React.MouseEvent) => {
        this.Highlight(this.highlightColor, false, undefined, true);
        AnchorMenu.Instance.fadeOut(true);
    };

    @computed get highlighter() {
        return (
            <Group>
                <IconButton
                    icon={<FontAwesomeIcon icon="highlighter" style={{ transition: 'transform 0.1s', transform: 'rotate(-45deg)' }} />}
                    tooltip={'Click to Highlight'}
                    onClick={this.highlightClicked}
                    colorPicker={this.highlightColor}
                    color={SettingsManager.userColor}
                />
                <ColorPicker selectedColor={this.highlightColor} setFinalColor={this.changeHighlightColor} setSelectedColor={this.changeHighlightColor} size={Size.XSMALL} />
            </Group>
        );
    }

    @action changeHighlightColor = (color: string) => {
        const col: ColorState = {
            hex: color,
            hsl: { a: 0, h: 0, s: 0, l: 0, source: '' },
            hsv: { a: 0, h: 0, s: 0, v: 0, source: '' },
            rgb: { a: 0, r: 0, b: 0, g: 0, source: '' },
            oldHue: 0,
            source: '',
        };
        this.highlightColor = Utils.colorString(col);
    };

    /**
     * Returns whether the selected text can be summarized. The goal is to have
     * all selected text available to summarize but its only supported for pdf and web ATM.
     * @returns Whether the GPT icon for summarization should appear
     */
    canSummarize = () => SelectionManager.Docs().some(doc => [DocumentType.PDF, DocumentType.WEB].includes(doc.type as any));

    render() {
        const buttons =
            this.Status === 'marquee' ? (
                <>
                    {this.highlighter}
                    <div ref={this._commentRef}>
                        <IconButton
                            tooltip="Drag to Place Annotation" //
                            onPointerDown={this.pointerDown}
                            icon={<FontAwesomeIcon icon="comment-alt" />}
                            color={SettingsManager.userColor}
                        />
                    </div>
                    {/* GPT Summarize icon only shows up when text is highlighted, not on marquee selection*/}
                    {AnchorMenu.Instance.StartCropDrag === unimplementedFunction && this.canSummarize() && (
                        <IconButton
                            tooltip="Summarize with AI" //
                            onPointerDown={this.gptSummarize}
                            icon={<FontAwesomeIcon icon="comment-dots" size="lg" />}
                            color={SettingsManager.userColor}
                        />
                    )}
                    {AnchorMenu.Instance.OnAudio === unimplementedFunction ? null : (
                        <IconButton
                            tooltip="Click to Record Annotation" //
                            onPointerDown={this.audioDown}
                            icon={<FontAwesomeIcon icon="microphone" />}
                            color={SettingsManager.userColor}
                        />
                    )}
                    <Popup
                        tooltip="Find document to link to selected text" //
                        type={Type.PRIM}
                        icon={<FontAwesomeIcon icon={'search'} />}
                        popup={<LinkPopup key="popup" linkCreateAnchor={this.onMakeAnchor} />}
                        color={SettingsManager.userColor}
                    />
                    {AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? null : (
                        <div ref={this._cropRef}>
                            <IconButton
                                tooltip="Click/Drag to create cropped image" //
                                onPointerDown={this.cropDown}
                                icon={<FontAwesomeIcon icon="image" />}
                                color={SettingsManager.userColor}
                            />
                        </div>
                    )}
                </>
            ) : (
                <>
                    {this.Delete !== returnFalse && (
                        <IconButton
                            tooltip="Remove Link Anchor" //
                            onPointerDown={this.Delete}
                            icon={<FontAwesomeIcon icon="trash-alt" />}
                            color={SettingsManager.userColor}
                        />
                    )}
                    {this.PinToPres !== returnFalse && (
                        <IconButton
                            tooltip="Pin to Presentation" //
                            onPointerDown={this.PinToPres}
                            icon={<FontAwesomeIcon icon="map-pin" />}
                            color={SettingsManager.userColor}
                        />
                    )}
                    {this.ShowTargetTrail !== returnFalse && (
                        <IconButton
                            tooltip="Show Linked Trail" //
                            onPointerDown={this.ShowTargetTrail}
                            icon={<FontAwesomeIcon icon="taxi" />}
                            color={SettingsManager.userColor}
                        />
                    )}
                    {this.IsTargetToggler !== returnFalse && (
                        <Toggle
                            tooltip={'Make target visibility toggle on click'}
                            type={Type.PRIM}
                            toggleType={ToggleType.BUTTON}
                            toggleStatus={this.IsTargetToggler()}
                            onClick={this.MakeTargetToggle}
                            icon={<FontAwesomeIcon icon="thumbtack" />}
                            color={SettingsManager.userColor}
                        />
                    )}
                </>
            );

        return this.getElement(buttons);
    }
}
