/* eslint-disable react/button-has-type */
import { IconLookup, faAdd, faArrowDown, faArrowLeft, faArrowsRotate, faBicycle, faCalendarDays, faCar, faDiamondTurnRight, faEdit, faPersonWalking, faRoute } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/material';
import { IconButton } from 'browndash-components';
import { Position } from 'geojson';
import { IReactionDisposer, ObservableMap, action, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { CirclePicker, ColorResult } from 'react-color';
import { returnFalse, setupMoveUpEvents } from '../../../../ClientUtils';
import { unimplementedFunction } from '../../../../Utils';
import { Doc, Opt } from '../../../../fields/Doc';
import { NumCast, StrCast } from '../../../../fields/Types';
import { CalendarManager } from '../../../util/CalendarManager';
import { SelectionManager } from '../../../util/SelectionManager';
import { SettingsManager } from '../../../util/SettingsManager';
import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu';
import './MapAnchorMenu.scss';
import { MapboxApiUtility, TransportationType } from './MapboxApiUtility';
import { MarkerIcons } from './MarkerIcons';
// import { GPTPopup, GPTPopupMode } from './../../GPTPopup/GPTPopup';

type MapAnchorMenuType = 'standard' | 'routeCreation' | 'calendar' | 'customize' | 'route';

@observer
export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
    // eslint-disable-next-line no-use-before-define
    static Instance: MapAnchorMenu;

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

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

    public Center: () => void = unimplementedFunction;
    public OnClick: (e: PointerEvent) => void = unimplementedFunction;
    // public OnAudio: (e: PointerEvent) => void = unimplementedFunction;
    public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
    public Highlight: (color: string, isTargetToggler: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>, addAsAnnotation?: boolean) => Opt<Doc> = () => undefined;
    public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined;
    public Delete: () => void = unimplementedFunction;
    // public MakeTargetToggle: () => void = unimplementedFunction;
    // public ShowTargetTrail: () => void = unimplementedFunction;
    public IsTargetToggler: () => boolean = returnFalse;

    public DisplayRoute: (routeInfoMap: Record<TransportationType, any> | undefined, type: TransportationType) => void = unimplementedFunction;
    public AddNewRouteToMap: (coordinates: Position[], origin: string, destination: any, createPinForDestination: boolean) => void = unimplementedFunction;
    public CreatePin: (feature: any) => void = unimplementedFunction;

    public UpdateMarkerColor: (color: string) => void = unimplementedFunction;
    public UpdateMarkerIcon: (iconKey: string) => void = unimplementedFunction;

    public Hide: () => void = unimplementedFunction;

    public OpenAnimationPanel: (routeDoc: Doc | undefined) => void = unimplementedFunction;

    @observable
    menuType: MapAnchorMenuType = 'standard';

    @action
    public setMenuType = (menuType: MapAnchorMenuType) => {
        this.menuType = menuType;
    };

    private allMapPinDocs: Doc[] = [];

    private pinDoc: Doc | undefined = undefined;

    private routeDoc: Doc | undefined = undefined;

    private title: string | undefined = undefined;

    public setPinDoc(pinDoc: Doc | undefined) {
        if (pinDoc) {
            this.pinDoc = pinDoc;
            this.title = StrCast(pinDoc.title ? pinDoc.title : `${NumCast(pinDoc.longitude)}, ${NumCast(pinDoc.latitude)}`);
        }
    }

    public setRouteDoc(routeDoc: Doc | undefined) {
        if (routeDoc) {
            this.routeDoc = routeDoc;
            this.title = StrCast(routeDoc.title ?? 'Map route');
        }
    }

    @action
    public Reset() {
        this.destinationSelected = false;
        this.currentRouteInfoMap = undefined;
        this.destinationFeatures = [];
        this.selectedDestinationFeature = undefined;
        this.allMapPinDocs = [];
        this.title = undefined;
        this.routeDoc = undefined;
        this.pinDoc = undefined;
    }

    public setAllMapboxPins(pinDocs: Doc[]) {
        this.allMapPinDocs = pinDocs;
        pinDocs.forEach((p, idx) => {
            console.log(`Pin ${idx}: ${p.title}`);
        });
    }

    public get Active() {
        return this._left > 0;
    }

    constructor(props: any) {
        super(props);
        makeObservable(this);
        MapAnchorMenu.Instance = this;
        MapAnchorMenu.Instance._canFade = false;
    }

    componentWillUnmount() {
        this.destinationFeatures = [];
        this.destinationSelected = false;
        this.selectedDestinationFeature = undefined;
        this.currentRouteInfoMap = undefined;
        this._disposer?.();
    }

    componentDidMount() {
        this._disposer = reaction(
            () => SelectionManager.Views.slice(),
            () => MapAnchorMenu.Instance.fadeOut(true)
        );
    }
    // 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._commentCont.current!);
    //             return true;
    //         },
    //         returnFalse,
    //         e => this.OnCrop?.(e)
    //     );
    // };
    notePointerDown = (e: React.PointerEvent) => {
        setupMoveUpEvents(
            this,
            e,
            moveEv => {
                this.StartDrag(moveEv, this._commentRef.current!);
                return true;
            },
            returnFalse,
            clickEv => this.OnClick(clickEv)
        );
    };

    static top = React.createRef<HTMLDivElement>();

    // public get Top(){
    //     return this.top
    // }

    @action
    DirectionsClick = () => {
        this.menuType = 'routeCreation';
    };

    @action
    CustomizeClick = () => {
        this.currentRouteInfoMap = undefined;
        this.menuType = 'customize';
    };

    @action
    BackClick = () => {
        this.currentRouteInfoMap = undefined;
        this.menuType = 'standard';
    };

    @action
    TriggerFileInputClick = () => {
        if (this._fileInputRef) {
            this._fileInputRef.current?.click(); // Trigger the file input click event
        }
    };

    @action
    onMarkerColorChange = (color: ColorResult) => {
        if (this.pinDoc) {
            this.pinDoc.markerColor = color.hex;
        }
    };

    revertToOriginalMarker = () => {
        if (this.pinDoc) {
            this.pinDoc.markerType = 'MAP_PIN';
            this.pinDoc.markerColor = '#ff5722';
        }
    };

    onMarkerIconChange = (iconKey: string) => {
        if (this.pinDoc) {
            this.pinDoc.markerType = iconKey;
        }
    };

    @observable
    destinationFeatures: any[] = [];

    @observable
    destinationSelected: boolean = false;

    @observable
    selectedDestinationFeature: any = undefined;

    @observable
    createPinForDestination: boolean = true;

    @observable
    currentRouteInfoMap: Record<TransportationType, any> | undefined = undefined;

    @observable
    selectedTransportationType: TransportationType = 'driving';

    @action
    handleTransportationTypeChange = (newType: TransportationType) => {
        if (newType !== this.selectedTransportationType) {
            this.selectedTransportationType = newType;
            this.DisplayRoute(this.currentRouteInfoMap, newType);
        }
    };

    @action
    handleSelectedDestinationFeature = (destinationFeature: any) => {
        this.selectedDestinationFeature = destinationFeature;
    };

    @action
    toggleCreatePinForDestinationCheckbox = () => {
        this.createPinForDestination = !this.createPinForDestination;
    };

    @action
    handleDestinationSearchChange = async (searchText: string) => {
        if (this.selectedDestinationFeature !== undefined) this.selectedDestinationFeature = undefined;
        const features = await MapboxApiUtility.forwardGeocodeForFeatures(searchText);
        if (features) {
            runInAction(() => {
                this.destinationFeatures = features;
            });
        }
    };

    getRoutes = async (destinationFeature: any) => {
        const currentPinLong: number = NumCast(this.pinDoc?.longitude);
        const currentPinLat: number = NumCast(this.pinDoc?.latitude);

        if (currentPinLong && currentPinLat && destinationFeature.center) {
            const routeInfoMap = await MapboxApiUtility.getDirections([currentPinLong, currentPinLat], destinationFeature.center);
            if (routeInfoMap) {
                runInAction(() => {
                    this.currentRouteInfoMap = routeInfoMap;
                });
                this.DisplayRoute(routeInfoMap, 'driving');
            }
        }

        // get route menu, set it equal to here
        // create a temporary route
        // create pin if createPinForDestination was clicked
    };

    HandleAddRouteClick = () => {
        if (this.currentRouteInfoMap && this.selectedTransportationType && this.selectedDestinationFeature) {
            const { coordinates } = this.currentRouteInfoMap[this.selectedTransportationType];
            console.log(coordinates);
            console.log(this.selectedDestinationFeature);
            this.AddNewRouteToMap(coordinates, this.title ?? '', this.selectedDestinationFeature, this.createPinForDestination);
        }
    };

    getMarkerIcon = (): JSX.Element | undefined => {
        if (this.pinDoc) {
            const markerType = StrCast(this.pinDoc.markerType);
            const markerColor = StrCast(this.pinDoc.markerColor);

            return MarkerIcons.getFontAwesomeIcon(markerType, '2x', markerColor);
        }
        return undefined;
    };

    getDirectionsButton: JSX.Element = (<IconButton tooltip="Get directions" onPointerDown={this.DirectionsClick} icon={<FontAwesomeIcon icon={faDiamondTurnRight as IconLookup} />} color={SettingsManager.userColor} />);

    getAddToCalendarButton = (docType: string): JSX.Element => (
        <IconButton
            tooltip="Add to calendar"
            onPointerDown={() => {
                CalendarManager.Instance.open(undefined, docType === 'pin' ? this.pinDoc : this.routeDoc);
            }}
            icon={<FontAwesomeIcon icon={faCalendarDays as IconLookup} />}
            color={SettingsManager.userColor}
        />
    );
    addToCalendarButton: JSX.Element = (
        <IconButton tooltip="Add to calendar" onPointerDown={() => CalendarManager.Instance.open(undefined, this.pinDoc)} icon={<FontAwesomeIcon icon={faCalendarDays as IconLookup} />} color={SettingsManager.userColor} />
    );

    getLinkNoteToDocButton = (docType: string): JSX.Element => (
        <div ref={this._commentRef}>
            <IconButton
                tooltip={`Link Note to ${docType === 'pin' ? 'Pin' : 'Route'}`} //
                onPointerDown={this.notePointerDown}
                icon={<FontAwesomeIcon icon="sticky-note" />}
                color={SettingsManager.userColor}
            />
        </div>
    );

    linkNoteToPinOrRoutenButton: JSX.Element = (
        <div ref={this._commentRef}>
            <IconButton
                tooltip="Link Note to Pin" //
                onPointerDown={this.notePointerDown}
                icon={<FontAwesomeIcon icon="sticky-note" />}
                color={SettingsManager.userColor}
            />
        </div>
    );

    customizePinButton: JSX.Element = (<IconButton tooltip="Customize pin" onPointerDown={this.CustomizeClick} icon={<FontAwesomeIcon icon={faEdit as IconLookup} />} color={SettingsManager.userColor} />);

    centerOnPinButton: JSX.Element = (
        <IconButton
            tooltip="Center on pin" //
            onPointerDown={this.Center}
            icon={<FontAwesomeIcon icon="compress-arrows-alt" />}
            color={SettingsManager.userColor}
        />
    );

    backButton: JSX.Element = (
        <IconButton
            tooltip="Go back" //
            onPointerDown={this.BackClick}
            icon={<FontAwesomeIcon icon={faArrowLeft as IconLookup} />}
            color={SettingsManager.userColor}
        />
    );

    addRouteButton: JSX.Element = (
        <IconButton
            tooltip="Add route" //
            onPointerDown={this.HandleAddRouteClick}
            icon={<FontAwesomeIcon icon={faAdd as IconLookup} />}
            color={SettingsManager.userColor}
        />
    );

    getDeleteButton = (type: string) => (
        <IconButton
            tooltip={`Delete ${type === 'pin' ? 'Pin' : 'Route'}`} //
            onPointerDown={this.Delete}
            icon={<FontAwesomeIcon icon="trash-alt" />}
            color={SettingsManager.userColor}
        />
    );

    animateRouteButton: JSX.Element = (<IconButton tooltip="Animate route" onPointerDown={() => this.OpenAnimationPanel(this.routeDoc)} icon={<FontAwesomeIcon icon={faRoute as IconLookup} />} color={SettingsManager.userColor} />);

    revertToOriginalMarkerButton = (
        <IconButton
            tooltip="Revert to original" //
            onPointerDown={() => this.revertToOriginalMarker()}
            icon={<FontAwesomeIcon icon={faArrowsRotate as IconLookup} />}
            color={SettingsManager.userColor}
        />
    );

    render() {
        const buttons = (
            <div className="menu-buttons" style={{ display: 'flex' }}>
                {this.menuType === 'standard' && (
                    <>
                        {this.getDeleteButton('pin')}
                        {this.getDirectionsButton}
                        {this.getAddToCalendarButton('pin')}
                        {this.getLinkNoteToDocButton('pin')}
                        {this.customizePinButton}
                        {this.centerOnPinButton}
                    </>
                )}
                {this.menuType === 'routeCreation' && (
                    <>
                        {this.backButton}
                        {this.addRouteButton}
                    </>
                )}
                {this.menuType === 'route' && (
                    <>
                        {this.getDeleteButton('route')}
                        {this.animateRouteButton}
                        {this.getAddToCalendarButton('route')}
                        {this.getLinkNoteToDocButton('route')}
                    </>
                )}
                {this.menuType === 'customize' && (
                    <>
                        {this.backButton}
                        {this.revertToOriginalMarkerButton}
                    </>
                )}

                {/* {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}
                        />
                    )} */}
            </div>
        );

        return this.getElement(
            <div ref={MapAnchorMenu.top} className="map-anchor-menu-container">
                {this.menuType === 'standard' && <div>{this.title}</div>}
                {this.menuType === 'routeCreation' && (
                    <div className="direction-inputs" style={{ display: 'flex', flexDirection: 'column' }}>
                        <TextField fullWidth disabled value={this.title} />
                        <FontAwesomeIcon icon={faArrowDown as IconLookup} size="xs" />
                        <Autocomplete
                            fullWidth
                            id="route-destination-searcher"
                            onInputChange={(e: any, searchText: any) => this.handleDestinationSearchChange(searchText)}
                            onChange={(e: any, feature: any, reason: any) => {
                                if (reason === 'clear') {
                                    this.handleSelectedDestinationFeature(undefined);
                                } else if (reason === 'selectOption') {
                                    this.handleSelectedDestinationFeature(feature);
                                }
                            }}
                            options={this.destinationFeatures.filter(feature => feature.place_name).map(feature => feature)}
                            getOptionLabel={(feature: any) => feature.place_name}
                            // eslint-disable-next-line react/jsx-props-no-spreading
                            renderInput={(params: any) => <TextField {...params} placeholder="Enter a destination" />}
                        />
                        {!this.selectedDestinationFeature
                            ? null
                            : !this.allMapPinDocs.some(pinDoc => pinDoc.title === this.selectedDestinationFeature.place_name) && (
                                  <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '5px' }}>
                                      <FormControlLabel label="Create pin for destination?" control={<Checkbox color="success" checked={this.createPinForDestination} onChange={this.toggleCreatePinForDestinationCheckbox} />} />
                                  </div>
                              )}
                        <button id="get-routes-button" disabled={!this.selectedDestinationFeature} onClick={() => this.getRoutes(this.selectedDestinationFeature)}>
                            Get routes
                        </button>

                        {/* <input
                            placeholder="Origin"
                        /> */}
                    </div>
                )}
                {this.currentRouteInfoMap && (
                    <div className="current-route-info-container">
                        <div className="transportation-icons-container">
                            <IconButton
                                tooltip="Driving route"
                                onPointerDown={() => this.handleTransportationTypeChange('driving')}
                                icon={<FontAwesomeIcon icon={faCar as IconLookup} />}
                                color={this.selectedTransportationType === 'driving' ? 'lightblue' : 'grey'}
                            />
                            <IconButton
                                tooltip="Cycling route"
                                onPointerDown={() => this.handleTransportationTypeChange('cycling')}
                                icon={<FontAwesomeIcon icon={faBicycle as IconLookup} />}
                                color={this.selectedTransportationType === 'cycling' ? 'lightblue' : 'grey'}
                            />
                            <IconButton
                                tooltip="Walking route"
                                onPointerDown={() => this.handleTransportationTypeChange('walking')}
                                icon={<FontAwesomeIcon icon={faPersonWalking as IconLookup} />}
                                color={this.selectedTransportationType === 'walking' ? 'lightblue' : 'grey'}
                            />
                        </div>
                        <div className="selected-route-details-container">
                            <div>Duration: {this.currentRouteInfoMap[this.selectedTransportationType].duration}</div>
                            <div>Distance: {this.currentRouteInfoMap[this.selectedTransportationType].distance}</div>
                        </div>
                    </div>
                )}
                {this.menuType === 'customize' && (
                    <div className="customized-marker-container">
                        <div className="current-marker-container">
                            <div>Current Marker: </div>
                            <div>{this.getMarkerIcon()}</div>
                        </div>
                        <div className="color-picker-container" style={{ marginBottom: '10px' }}>
                            <CirclePicker circleSize={15} circleSpacing={7} width="100%" onChange={color => this.onMarkerColorChange(color)} />
                        </div>
                        <div className="all-markers-container">
                            {Object.keys(MarkerIcons.FAMarkerIconsMap).map(iconKey => (
                                <div key={iconKey} className="marker-icon">
                                    <IconButton onPointerDown={() => this.onMarkerIconChange(iconKey)} icon={MarkerIcons.getFontAwesomeIcon(iconKey, '1x', 'white')} />
                                </div>
                            ))}
                        </div>
                        <div style={{ width: '100%', height: '3px', color: 'white' }} />
                    </div>
                )}
                {this.menuType === 'route' && this.routeDoc && <div>{StrCast(this.routeDoc.title)}</div>}
                {buttons}
            </div>,
            true
        );
    }
}
