import { IRefPhaserGame, PhaserGame } from './game/PhaserGame';
import "./styles.css";
import styles from './App.module.css';
import { useEffect, useRef, useState } from 'react';
import { EventBus } from './game/EventBus';
import PlayScene from './game/scenes/PlayScene';
import { Mountain } from './game/entities/Mountain';
import { ReactComponent as FlagsTarget } from './assets/flags-target-small.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 from './overlaying-tutorial';
import WonOverlay from './WonOverlay';
import { ReactComponent as FlagsIcon } from './assets/flags.svg';
import { PosterItem } from './types';

import { ReactComponent as OnTiltLeft } from "./assets/blocks/ontiltleft.svg";
import { ReactComponent as OnTiltRight } from "./assets/blocks/ontiltright.svg";
import { ReactComponent as ForwardIcon } from "./assets/blocks/forward.svg";
import { ReactComponent as BackwardIcon } from "./assets/blocks/backward.svg";
import { ReactComponent as NowhereIcon } from "./assets/blocks/nowhere.svg";

import BlockSelector4 from "./block-selector-4";
import { selectedBlockFromTutorialForLeft, selectedBlockFromTutorialForRight } from './utils/selected-blocks-from-tutorial';
import ShouldIStayOrShouldIGo from './ShouldIStayOrShouldIGo';
import { hasMartyWebAppHost } from './utils/CogManager';
import { FiInfo, FiX } from 'react-icons/fi';

const staticBlockItemLeft: PosterItem = { icon: OnTiltLeft, block: "ontiltleft", execute: async () => true };
const staticBlockItemRight: PosterItem = { icon: OnTiltRight, block: "ontiltright", execute: async () => true };

const posterItems: PosterItem[] = [
    { icon: ForwardIcon, block: "moveright", execute: async () => true },
    { icon: NowhereIcon, block: "dontmove", execute: async () => true },
    { icon: BackwardIcon, block: "moveleft", execute: async () => true },
];

const defaultLeftAction = posterItems[2];
const defaultRightAction = posterItems[0];
const MOUNTAIN_ASPECT_RATIO = 2500 / 2003;

function Skiing() {
    const [gameContainerDimensions, setGameContainerDimensions] = useState({ width: "70vw", height: "80vh" });
    const [collectedFlags, setCollectedFlags] = useState(0);
    const [isZooming, setIsZooming] = useState(false);
    const [flagFeedbackId, setFlagFeedbackId] = useState(0);
    const [flagFeedbackText, setFlagFeedbackText] = useState("+1");
    const phaserGameRef = useRef<IRefPhaserGame>(null);
    const [connectedCog, setConnectedCog] = useState<RAFT | null>(null);
    const [isWinningFlagVisible, setIsWinningFlagVisible] = useState(false);
    const [posterItemsLeftState, setPosterItemsLeftState] = useState<PosterItem[]>([]);
    const [posterItemsRightState, setPosterItemsRightState] = useState<PosterItem[]>([]);
    const [selectedLeftAction, setSelectedLeftAction] = useState<PosterItem>(defaultLeftAction);
    const [selectedRightAction, setSelectedRightAction] = useState<PosterItem>(defaultRightAction);
    const [tutorialPhase, setTutorialPhase] = useState<undefined | number>(1);
    const [shouldIStayOrShouldIGoVisible, setShouldIStayOrShouldIGoVisible] = useState(false);
    const [isInfoModalOpen, setIsInfoModalOpen] = useState(false);
    const [isMainGameRunning, setIsMainGameRunning] = useState(false);
    const [hasHostApp] = useState(() => hasMartyWebAppHost());

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

    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 handleMountainReady = (mountain: Mountain) => {
            const mountainHeightScaled = mountain.height * mountain.scaleFactors.height;
            const mountainWidthScaled = mountain.width * mountain.scaleFactors.width;
            setGameContainerDimensions({
                width: mountainWidthScaled + "px",
                height: mountainHeightScaled + "px"
            });
        };

        const handleFlagsCollected = (sceneInstance: PlayScene) => {
            setCollectedFlags(sceneInstance.collectedFlags);
            setFlagFeedbackText("+1");
            setFlagFeedbackId(feedbackId => feedbackId + 1);
        };

        const handleFlagsLost = (sceneInstance: PlayScene) => {
            setCollectedFlags(sceneInstance.collectedFlags);
            setFlagFeedbackText("-1");
            setFlagFeedbackId(feedbackId => feedbackId + 1);
        };

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

        const handleDie = () => {
            setCollectedFlags(0);
            setIsInfoModalOpen(false);
        };

        const handleGameRunningChanged = (sceneInstance: PlayScene) => {
            setIsMainGameRunning(sceneInstance.isGameRunning);
        };

        EventBus.on('mountain-ready', handleMountainReady);
        EventBus.on('flags-collected', handleFlagsCollected);
        EventBus.on('flags-lost', handleFlagsLost);
        EventBus.on('target-achieved', handleTargetAchieved);
        EventBus.on('die', handleDie);
        EventBus.on('game-running-changed', handleGameRunningChanged);

        return () => {
            EventBus.removeListener('mountain-ready', handleMountainReady);
            EventBus.removeListener('flags-collected', handleFlagsCollected);
            EventBus.removeListener('flags-lost', handleFlagsLost);
            EventBus.removeListener('target-achieved', handleTargetAchieved);
            EventBus.removeListener('die', handleDie);
            EventBus.removeListener('game-running-changed', handleGameRunningChanged);
            if (targetAchievedTimeoutRef.current) {
                window.clearTimeout(targetAchievedTimeoutRef.current);
            }
        }
    }, []);

    useEffect(() => {
        if (collectedFlags <= 0) return;

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

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

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

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

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

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

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

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

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

    const applyMissionSelection = (leftAction: PosterItem, rightAction: PosterItem) => {
        setPosterItemsLeftState(posterItems);
        setPosterItemsRightState(posterItems);
        setSelectedLeftAction(leftAction);
        setSelectedRightAction(rightAction);

        const scene = phaserGameRef.current?.scene;
        if (scene) {
            scene.selectedCogTiltLeftBlock = leftAction;
            scene.selectedCogTiltRightBlock = rightAction;
        }
    };

    const onTutorialFinished = () => {
        const selectedLeft = resolvePosterItem(selectedBlockFromTutorialForLeft, defaultLeftAction);
        const selectedRight = resolvePosterItem(selectedBlockFromTutorialForRight, defaultRightAction);

        applyMissionSelection(selectedLeft, selectedRight);
        setTutorialPhase(undefined);
        EventBus.emit('tutorial-finished');

        window.setTimeout(() => {
            if (phaserGameRef.current?.scene && !phaserGameRef.current.scene.isGameRunning) {
                phaserGameRef.current.scene.handleGameRestart();
            }
        }, 150);
    };

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

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

    const handleFallbackTilt = (direction: "left" | "right") => {
        const scene = phaserGameRef.current?.scene;
        if (!scene?.player) return;
        if (!scene.isGameRunning && !scene.isGameOverVisible) {
            scene.handleGameRestart();
        }
        if (!scene.isGameRunning) return;

        scene.selectedCogTiltLeftBlock = selectedLeftAction;
        scene.selectedCogTiltRightBlock = selectedRightAction;
        scene.player.actionDecider(direction, "fallback-button");
    };

    const LeftActionIcon = selectedLeftAction.icon;
    const RightActionIcon = selectedRightAction.icon;
    const isMissionReady = tutorialPhase === undefined && posterItemsLeftState.length > 0 && posterItemsRightState.length > 0;
    const shouldShowFallbackTilt = !hasHostApp && !connectedCog && isMissionReady;
    const playAreaClasses = [
        styles.playArea,
        isMissionReady ? styles.playAreaWithSelector : ""
    ].join(" ");
    const gameContainerStyle: React.CSSProperties = isMissionReady
        ? {
            width: `min(${gameContainerDimensions.width}, 100%, calc((100vh - 28px) * ${MOUNTAIN_ASPECT_RATIO}))`,
            height: "auto",
            aspectRatio: `${MOUNTAIN_ASPECT_RATIO}`,
        }
        : gameContainerDimensions;

    return (
        <div className={styles.App}>
            {isWinningFlagVisible && <WonOverlay />}
            {shouldIStayOrShouldIGoVisible && <ShouldIStayOrShouldIGo keepPlaying={onKeepPlaying} goNext={onGoNext} />}
            <OverlayingTutorial tutorialPhase={tutorialPhase} setTutorialPhase={setTutorialPhase} onTutorialFinished={onTutorialFinished} />
            <div className={playAreaClasses}>
                {isMissionReady && (
                    <div className={styles.selectorPanel}>
                        <BlockSelector4
                            gameRef={phaserGameRef}
                            staticBlock="left"
                            posterItems={posterItemsLeftState}
                            staticBlockItem={staticBlockItemLeft}
                            onSelectedBlockChange={setSelectedLeftAction}
                            initialSelectedIndex={getPosterItemIndex(selectedLeftAction)}
                        />
                        <BlockSelector4
                            gameRef={phaserGameRef}
                            staticBlock="right"
                            posterItems={posterItemsRightState}
                            staticBlockItem={staticBlockItemRight}
                            onSelectedBlockChange={setSelectedRightAction}
                            initialSelectedIndex={getPosterItemIndex(selectedRightAction)}
                        />
                    </div>
                )}
                <div
                    className={styles.gameContainer}
                    style={gameContainerStyle}
                    data-testid="main-game-container"
                    data-main-game-running={isMainGameRunning ? "true" : "false"}
                >
                    <div className={styles.missionHud}>
                        <div className={styles.missionCluster}>
                            <div className={styles.progressPill}>
                                <FlagsIcon className={styles.flagsIcon} />
                                <div className={`${styles.score} ${isZooming ? styles.zoom : ''}`}>
                                    {collectedFlags}<span>/10</span>
                                </div>
                            </div>
                            {isMissionReady && (
                                <div className={styles.commandGroup} aria-hidden="true">
                                    <div className={styles.commandPill}>
                                        <OnTiltLeft className={styles.commandTriggerIcon} />
                                        <span className={styles.commandArrow}>→</span>
                                        <LeftActionIcon className={styles.commandActionIcon} />
                                    </div>
                                    <div className={styles.commandPill}>
                                        <OnTiltRight className={styles.commandTriggerIcon} />
                                        <span className={styles.commandArrow}>→</span>
                                        <RightActionIcon className={styles.commandActionIcon} />
                                    </div>
                                </div>
                            )}
                            {shouldShowFallbackTilt && (
                                <div className={styles.fallbackTiltControls}>
                                    <button className={styles.fallbackTiltButton} type="button" onClick={() => handleFallbackTilt("left")}>
                                        Left
                                    </button>
                                    <button className={styles.fallbackTiltButton} type="button" onClick={() => handleFallbackTilt("right")}>
                                        Right
                                    </button>
                                </div>
                            )}
                        </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">
                                <FlagsTarget className={styles.flagsTargetIcon} />
                            </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="skiing-game-info-title"
                                onClick={(event) => event.stopPropagation()}
                            >
                                <div className={styles.infoModalHeader}>
                                    <h2 id="skiing-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}>
                                            <OnTiltLeft aria-hidden="true" />
                                        </div>
                                        <p>Tilt Cog left or right to run the selected steering action.</p>
                                    </div>
                                    <div className={styles.infoStep}>
                                        <div className={styles.infoStepIcon}>
                                            <RightActionIcon aria-hidden="true" />
                                        </div>
                                        <p>Use the selectors to choose how Marty moves for each tilt.</p>
                                    </div>
                                    <div className={styles.infoStep}>
                                        <div className={styles.infoStepIcon}>
                                            <FlagsIcon aria-hidden="true" />
                                        </div>
                                        <p>Ski through 10 flag gates while avoiding the trees.</p>
                                    </div>
                                </div>
                            </div>
                        </div>
                    )}
                    {flagFeedbackId > 0 && (
                        <div key={flagFeedbackId} className={styles.flagFeedback} aria-hidden="true">
                            {flagFeedbackText}
                        </div>
                    )}
                    <PhaserGame ref={phaserGameRef} />
                </div>
            </div>
        </div>
    )
}

export default Skiing;

function resolvePosterItem(item: PosterItem | undefined, fallback: PosterItem) {
    if (!item) return fallback;
    return posterItems.find(posterItem => posterItem.block === item.block) || fallback;
}

function getPosterItemIndex(item: PosterItem) {
    const index = posterItems.findIndex(posterItem => posterItem.block === item.block);
    return index === -1 ? 1 : index;
}
