import { IRefPhaserGame, PhaserGame } from './game/PhaserGame';
import "./styles.css";
import styles from './App.module.css';
import { useCallback, useEffect, useRef, useState } from 'react';
import { EventBus } from './game/EventBus';
import PlayScene from './game/scenes/PlayScene';
import { Sky } from './game/entities/Sky';
import { ReactComponent as StarTarget } from './assets/star-target.svg';
import { raftDisconnectedSubscriptionHelper } from './utils/raft-subscription-helpers';
import RAFT from '@robotical/webapp-types/dist-types/src/application/RAFTs/RAFT';
import { RaftTypeE } from '@robotical/webapp-types/dist-types/src/types/raft';
import OverlayingTutorial, { TutorialSelections } from './overlaying-tutorial';
import WonOverlay from './WonOverlay';
import { ReactComponent as StarIcon } from './assets/star.svg';
import { PosterItem } from './types';

import { ReactComponent as OnTouchCogIcon } from "./assets/blocks/ontouchcog.svg";
import { ReactComponent as OnNoTouchCogIcon } from "./assets/blocks/onnotouchcog.svg";

import { ReactComponent as UpIcon } from "./assets/blocks/up.svg";
import { ReactComponent as DownIcon } from "./assets/blocks/down.svg";
import { ReactComponent as NowhereIcon } from "./assets/blocks/nowhere.svg";
import BlockSelector4 from './block-selector-4';
import { selectedBlockFromTutorialForClick, selectedBlockFromTutorialForNoClick } from './utils/selected-blocks-from-tutorial';
import ShouldIStayOrShouldIGo from './ShouldIStayOrShouldIGo';
import { hasMartyWebAppHost } from './utils/CogManager';
import { FiInfo, FiX } from 'react-icons/fi';

const posterItemsNoClick: PosterItem[] = [
    { icon: UpIcon, block: "moveup", execute: async () => true },
    { icon: NowhereIcon, block: "dontmove", execute: async () => true },
    { icon: DownIcon, block: "movedown", execute: async () => true },
];

const posterItemsClick: PosterItem[] = [
    { icon: UpIcon, block: "moveup", execute: async () => true },
    { icon: NowhereIcon, block: "dontmove", execute: async () => true },
    { icon: DownIcon, block: "movedown", execute: async () => true },
];

const staticBlockItemsUp: PosterItem[] = [
    { icon: OnTouchCogIcon, block: "ontouchcog", execute: async () => true },
];

const staticBlockItemsDown: PosterItem[] = [
    { icon: OnNoTouchCogIcon, block: "onnotouchcog", execute: async () => true },
];

function arrangeSelectedBlock(items: PosterItem[], selectedBlock: PosterItem) {
    const index = items.findIndex(item => item.block === selectedBlock.block);
    if (index === -1) return items;

    const selectedItem = items[index];
    const middleIndex = Math.floor(items.length / 2);
    const nextItems = items.filter(item => item.block !== selectedItem.block);
    nextItems.splice(middleIndex, 0, selectedItem);
    return nextItems;
}

function RoboFly() {
    const [gameContainerDimensions, setGameContainerDimensions] = useState({ width: "80vw", height: "60vh" });
    const [collectedStars, setCollectedStars] = useState(0);
    const [isZooming, setIsZooming] = useState(false);
    const [starFeedbackId, setStarFeedbackId] = useState(0);
    const phaserGameRef = useRef<IRefPhaserGame>(null);
    const [connectedCog, setConnectedCog] = useState<RAFT | null>(null);
    const [isWinningFlagVisible, setIsWinningFlagVisible] = useState(false);
    const [posterItemsClickState, setPosterItemsClickState] = useState<PosterItem[]>([]);
    const [posterItemsNoClickState, setPosterItemsNoClickState] = useState<PosterItem[]>([]);
    const [selectedClickBlock, setSelectedClickBlock] = useState<PosterItem>(posterItemsClick[0]);
    const [selectedNoClickBlock, setSelectedNoClickBlock] = useState<PosterItem>(posterItemsNoClick[2]);
    const [shouldIStayOrShouldIGoVisible, setShouldIStayOrShouldIGoVisible] = useState(false);
    const [isInfoModalOpen, setIsInfoModalOpen] = useState(false);
    const [hasHostApp] = useState(() => hasMartyWebAppHost());

    const subHelper = useRef<ReturnType<typeof raftDisconnectedSubscriptionHelper> | null>(null);
    const targetAchievedTimeoutRef = useRef<number | undefined>();
    const wasGameRunningBeforeInfoModalRef = useRef(false);
    const fallbackPressIntervalRef = useRef<number | undefined>();

    useEffect(() => {
        const selectedCog = window.applicationManager?.getTheCurrentlySelectedDeviceOrFirstOfItsKind(RaftTypeE.COG);
        if (selectedCog) {
            setConnectedCog(selectedCog);
            subHelper.current = raftDisconnectedSubscriptionHelper(selectedCog);
            subHelper.current.subscribe(() => {
                setConnectedCog(null);
                subHelper.current?.unsubscribe();
            });
        }

        return () => {
            subHelper.current?.unsubscribe();
        }
    }, []);

    useEffect(() => {
        const handleSkyReady = (sky: Sky) => {
            setGameContainerDimensions({
                width: sky.displayWidth + "px",
                height: sky.displayHeight + "px"
            });
        };

        const handleStarCollected = (sceneInstance: PlayScene) => {
            setCollectedStars(sceneInstance.collectedStars);
            setStarFeedbackId(feedbackId => feedbackId + 1);
        };

        const handleTargetAchieved = () => {
            if (!phaserGameRef.current?.scene) return;
            setIsWinningFlagVisible(true);
            targetAchievedTimeoutRef.current = window.setTimeout(() => {
                setIsWinningFlagVisible(false);
                setShouldIStayOrShouldIGoVisible(true);
            }, 2000);
        };

        const handleDie = () => {
            setCollectedStars(0);
        };

        EventBus.on('sky-ready', handleSkyReady);
        EventBus.on('star-collected', handleStarCollected);
        EventBus.on('target-achieved', handleTargetAchieved);
        EventBus.on('die', handleDie);

        return () => {
            EventBus.removeListener('sky-ready', handleSkyReady);
            EventBus.removeListener('die', handleDie);
            EventBus.removeListener('star-collected', handleStarCollected);
            EventBus.removeListener('target-achieved', handleTargetAchieved);
            if (targetAchievedTimeoutRef.current) {
                window.clearTimeout(targetAchievedTimeoutRef.current);
            }
        }
    }, []);

    useEffect(() => {
        if (collectedStars > 0) {
            setIsZooming(true);
            const timeout = window.setTimeout(() => {
                setIsZooming(false);
            }, 300);

            return () => window.clearTimeout(timeout);
        }
    }, [collectedStars]);

    useEffect(() => {
        if (!isInfoModalOpen) return;

        const sceneWhenOpened = phaserGameRef.current?.scene;
        wasGameRunningBeforeInfoModalRef.current = !!sceneWhenOpened?.isGameRunning;

        if (sceneWhenOpened?.sys && sceneWhenOpened.isGameRunning) {
            sceneWhenOpened.isGameRunning = false;
            sceneWhenOpened.physics.pause();
            sceneWhenOpened.anims.pauseAll();
        }

        const handleKeyDown = (event: KeyboardEvent) => {
            if (event.key === "Escape") {
                setIsInfoModalOpen(false);
            }
        };

        window.addEventListener("keydown", handleKeyDown);
        return () => {
            window.removeEventListener("keydown", handleKeyDown);

            const scene = sceneWhenOpened;
            if (wasGameRunningBeforeInfoModalRef.current && scene?.sys && !scene.isGameOverVisible) {
                scene.physics.resume();
                scene.anims.resumeAll();
                scene.isGameRunning = true;
            }

            wasGameRunningBeforeInfoModalRef.current = false;
        };
    }, [isInfoModalOpen]);

    useEffect(() => {
        return () => {
            if (fallbackPressIntervalRef.current) {
                window.clearInterval(fallbackPressIntervalRef.current);
            }
        };
    }, []);

    const applySelectedBlocksToScene = useCallback((scene: PlayScene) => {
        scene.selectedCogClickedBlock = selectedClickBlock;
        scene.selectedCogNoClickBlock = selectedNoClickBlock;
    }, [selectedClickBlock, selectedNoClickBlock]);

    const onTutorialFinished = (tutorialSelections?: TutorialSelections) => {
        const selectedBlockClick = tutorialSelections?.click || selectedBlockFromTutorialForClick || posterItemsClick[0];
        const selectedBlockNoClick = tutorialSelections?.noClick || selectedBlockFromTutorialForNoClick || posterItemsNoClick[2];

        const nextClickItems = arrangeSelectedBlock(posterItemsClick, selectedBlockClick);
        const nextNoClickItems = arrangeSelectedBlock(posterItemsNoClick, selectedBlockNoClick);

        setPosterItemsClickState(nextClickItems);
        setPosterItemsNoClickState(nextNoClickItems);
        setSelectedClickBlock(selectedBlockClick);
        setSelectedNoClickBlock(selectedBlockNoClick);

        if (phaserGameRef.current?.scene) {
            phaserGameRef.current.scene.selectedCogClickedBlock = selectedBlockClick;
            phaserGameRef.current.scene.selectedCogNoClickBlock = selectedBlockNoClick;
            phaserGameRef.current.scene.isTutorialFinished = true;
        }

        EventBus.emit('tutorial-finished');
        window.setTimeout(() => {
            if (phaserGameRef.current?.scene && !phaserGameRef.current.scene.isGameRunning) {
                phaserGameRef.current.scene.handleGameRestart();
            }
        }, 150);
    };

    const runFallbackAction = useCallback((button: "click" | "release") => {
        const scene = phaserGameRef.current?.scene;
        if (!scene) return;
        if (!scene.isGameRunning && !scene.isGameOverVisible) {
            scene.handleGameRestart();
        }
        if (!scene.isGameRunning) return;
        applySelectedBlocksToScene(scene);
        EventBus.emit('input-received', { source: 'fallback-button', state: button });
        scene.player?.actionDecider(button);
    }, [applySelectedBlocksToScene]);

    const startFallbackPress = useCallback((event: React.PointerEvent<HTMLButtonElement>) => {
        event.preventDefault();
        if (fallbackPressIntervalRef.current) {
            window.clearInterval(fallbackPressIntervalRef.current);
        }
        runFallbackAction("click");
        fallbackPressIntervalRef.current = window.setInterval(() => {
            runFallbackAction("click");
        }, 90);
    }, [runFallbackAction]);

    const stopFallbackPress = useCallback((event?: React.PointerEvent<HTMLButtonElement>) => {
        event?.preventDefault();
        if (fallbackPressIntervalRef.current) {
            window.clearInterval(fallbackPressIntervalRef.current);
            fallbackPressIntervalRef.current = undefined;
        }
        runFallbackAction("release");
    }, [runFallbackAction]);

    const onKeepPlaying = () => {
        setShouldIStayOrShouldIGoVisible(false);
        setCollectedStars(0);
        phaserGameRef.current?.scene?.handleGameRestart();
    };

    const onGoNext = () => {
        window.applicationManager?.carouselNavigatorManager.getNavigator("games")?.navigate("/skiing-game");
    };

    const SelectedClickIcon = selectedClickBlock.icon;
    const SelectedNoClickIcon = selectedNoClickBlock.icon;
    const isMissionReady = posterItemsClickState.length > 0 && posterItemsNoClickState.length > 0;
    const shouldShowFallbackPress = !hasHostApp && !connectedCog && isMissionReady;
    const playAreaClasses = [
        styles.playArea,
        isMissionReady ? styles.playAreaWithSelector : ""
    ].join(" ");
    const gameContainerStyle = {
        ...gameContainerDimensions,
        width: isMissionReady ? `min(${gameContainerDimensions.width}, 100%)` : gameContainerDimensions.width,
    };

    return (
        <div className={styles.App}>
            {isWinningFlagVisible && <WonOverlay />}
            {shouldIStayOrShouldIGoVisible && <ShouldIStayOrShouldIGo keepPlaying={onKeepPlaying} goNext={onGoNext} />}
            <OverlayingTutorial onTutorialFinished={onTutorialFinished} />
            <div className={playAreaClasses}>
                {isMissionReady && (
                    <div className={styles.blockSelector3Container}>
                        <BlockSelector4
                            gameRef={phaserGameRef}
                            posterItems={posterItemsClickState}
                            staticBlockItem={staticBlockItemsUp[0]}
                            staticBlock="up"
                            onSelectedBlockChange={setSelectedClickBlock}
                        />
                        <BlockSelector4
                            gameRef={phaserGameRef}
                            posterItems={posterItemsNoClickState}
                            staticBlockItem={staticBlockItemsDown[0]}
                            staticBlock="down"
                            onSelectedBlockChange={setSelectedNoClickBlock}
                        />
                    </div>
                )}
                <div className={styles.gameContainer} style={gameContainerStyle}>
                    <div className={styles.missionHud}>
                        <div className={styles.missionCluster}>
                            <div className={styles.progressPill}>
                                <StarIcon className={styles.starIcon} />
                                <div className={`${styles.score} ${isZooming ? styles.zoom : ''}`}>
                                    {collectedStars}<span>/10</span>
                                </div>
                            </div>
                            {isMissionReady && (
                                <>
                                    <div className={styles.commandPill} aria-hidden="true">
                                        <OnTouchCogIcon className={styles.commandCogIcon} />
                                        <span className={styles.commandArrow}>→</span>
                                        <SelectedClickIcon className={styles.commandActionIcon} />
                                    </div>
                                    <div className={styles.commandPill} aria-hidden="true">
                                        <OnNoTouchCogIcon className={styles.commandCogIcon} />
                                        <span className={styles.commandArrow}>→</span>
                                        <SelectedNoClickIcon className={styles.commandActionIcon} />
                                    </div>
                                </>
                            )}
                            {shouldShowFallbackPress && (
                                <button
                                    className={styles.fallbackPressButton}
                                    type="button"
                                    onPointerDown={startFallbackPress}
                                    onPointerUp={stopFallbackPress}
                                    onPointerCancel={stopFallbackPress}
                                    onPointerLeave={stopFallbackPress}
                                >
                                    Press
                                </button>
                            )}
                        </div>
                        <div className={styles.hudActions}>
                            {isMissionReady && (
                                <button
                                    className={styles.infoButton}
                                    type="button"
                                    aria-label="Game instructions"
                                    title="Game instructions"
                                    onClick={() => setIsInfoModalOpen(true)}
                                >
                                    <FiInfo aria-hidden="true" />
                                </button>
                            )}
                            <div className={styles.targetPill} aria-hidden="true">
                                <StarTarget className={styles.starTargetIcon} />
                            </div>
                        </div>
                    </div>
                    {isMissionReady && isInfoModalOpen && (
                        <div
                            className={styles.infoModalBackdrop}
                            role="presentation"
                            onClick={() => setIsInfoModalOpen(false)}
                        >
                            <div
                                className={styles.infoModalPanel}
                                role="dialog"
                                aria-modal="true"
                                aria-labelledby="robofly-game-info-title"
                                onClick={(event) => event.stopPropagation()}
                            >
                                <div className={styles.infoModalHeader}>
                                    <h2 id="robofly-game-info-title">How To Play</h2>
                                    <button
                                        className={styles.infoCloseButton}
                                        type="button"
                                        aria-label="Close instructions"
                                        onClick={() => setIsInfoModalOpen(false)}
                                    >
                                        <FiX aria-hidden="true" />
                                    </button>
                                </div>
                                <div className={styles.infoModalSteps}>
                                    <div className={styles.infoStep}>
                                        <div className={styles.infoStepIcon}>
                                            <OnTouchCogIcon aria-hidden="true" />
                                        </div>
                                        <p>Press or hold Cog to run the touch action.</p>
                                    </div>
                                    <div className={styles.infoStep}>
                                        <div className={styles.infoStepIcon}>
                                            <OnNoTouchCogIcon aria-hidden="true" />
                                        </div>
                                        <p>Release Cog to run the no-touch action.</p>
                                    </div>
                                    <div className={styles.infoStep}>
                                        <div className={styles.infoStepIcon}>
                                            <StarIcon aria-hidden="true" />
                                        </div>
                                        <p>Collect 10 stars while avoiding the cogs.</p>
                                    </div>
                                </div>
                            </div>
                        </div>
                    )}
                    {starFeedbackId > 0 && (
                        <div key={starFeedbackId} className={styles.starFeedback} aria-hidden="true">
                            +1
                        </div>
                    )}
                    <PhaserGame ref={phaserGameRef} />
                </div>
            </div>
        </div>
    )
}

export default RoboFly;
