import { useCallback, useEffect, useRef, useState } from "react";
import { ReactComponent as TickIcon } from "../assets/green-tick.svg";
import styles from "./styles.module.css";
import { getConnectedCog, hasMartyWebAppHost } from "../utils/CogManager";
import Cog from "@robotical/webapp-types/dist-types/src/application/RAFTs/Cog/Cog";
import { PosterItem } from "../types";
import TiltGauge, { TiltGaugeHandle } from "../TiltGauge";
import { FallbackTiltButton, SuccessBadge, TutorialFrame } from "./TutorialFrame";

type Props = {
    nextPhase: () => void;
    BlocksConnectedIcon: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
    initialBlock: PosterItem;
    blocksGif: string;
    stepIndex: number;
    title: string;
    hint: string;
    fallbackLabel: string;
    fallbackKey: "ArrowLeft" | "ArrowRight";
};

export function GaugePhase({
    nextPhase,
    BlocksConnectedIcon,
    initialBlock,
    blocksGif,
    stepIndex,
    title,
    hint,
    fallbackLabel,
    fallbackKey,
}: Props) {
    const tiltGaugeRef = useRef<TiltGaugeHandle>(null);
    const [blocksIconState, setBlocksIconState] = useState<"visible" | "animation">("visible");
    const [isComplete, setIsComplete] = useState(false);
    const [shouldShowFallbackButton] = useState(() => !hasMartyWebAppHost() && !getConnectedCog());
    const completionStarted = useRef(false);
    const nextPhaseTimeoutRef = useRef<number | undefined>();

    const completeStep = useCallback(() => {
        if (completionStarted.current) return;
        completionStarted.current = true;
        tiltGaugeRef.current?.setScore(1);
        setBlocksIconState("animation");
        setIsComplete(true);
        nextPhaseTimeoutRef.current = window.setTimeout(nextPhase, 900);
    }, [nextPhase]);

    const runFallbackTilt = useCallback(() => {
        completeStep();
    }, [completeStep]);

    useEffect(() => {
        if (blocksIconState !== "visible") {
            return;
        }

        const intervalId = window.setInterval(() => {
            const connectedCog = getConnectedCog();
            if (!connectedCog) return;

            const cog = connectedCog as Cog;
            const { ay, ax } = cog.raftStateInfo.accelerometer;
            const rawTilt = Math.atan2(ay, -ax) - Math.PI / 2;
            const normalisedTilt = normaliseTiltScore(rawTilt, initialBlock.block);

            tiltGaugeRef.current?.setScore(normalisedTilt);

            if (normalisedTilt > 0.95) {
                completeStep();
            }
        }, 200);

        return () => window.clearInterval(intervalId);
    }, [blocksIconState, completeStep, initialBlock.block]);

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

        const handleKeyDown = (event: KeyboardEvent) => {
            if (event.key === fallbackKey) {
                runFallbackTilt();
            }
        };

        window.addEventListener("keydown", handleKeyDown);
        return () => window.removeEventListener("keydown", handleKeyDown);
    }, [fallbackKey, runFallbackTilt, shouldShowFallbackButton]);

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

    const blocksIconContainerClasses = [
        styles.tiltPracticeContainer,
        blocksIconState === "animation" ? styles.fadeOutAnimation : "",
    ].join(" ");

    return (
        <TutorialFrame
            stepIndex={stepIndex}
            title={title}
            hint={hint}
            controls={
                shouldShowFallbackButton
                    ? <FallbackTiltButton onPress={runFallbackTilt} disabled={isComplete} label={fallbackLabel} />
                    : null
            }
            badge={isComplete ? <SuccessBadge TickIcon={TickIcon} /> : null}
        >
            <div className={blocksIconContainerClasses}>
                <div className={styles.tiltVisualFocus}>
                    <img src={blocksGif} alt="" className={styles.blocksGif} />
                </div>
                <div className={styles.gaugeContainer} aria-hidden="true">
                    <BlocksConnectedIcon className={styles.commandIcon} />
                    <TiltGauge ref={tiltGaugeRef} title="" />
                </div>
            </div>
        </TutorialFrame>
    );
}

function normaliseTiltScore(rawTilt: number, block: PosterItem["block"]) {
    const clampedTilt = Math.max(-1.4, Math.min(1.4, rawTilt));

    if (block === "tiltleft") {
        if (clampedTilt >= 0) {
            return 0;
        }
        return Math.min(1, Math.abs(clampedTilt) / 1.4);
    }

    if (block === "tiltright") {
        if (clampedTilt <= 0) {
            return 0;
        }
        return Math.min(1, clampedTilt / 1.4);
    }

    return 0;
}
