import React from "react";
import { Box, Center, DarkMode } from "@chakra-ui/react";
import gql from "graphql-tag";
import { useQuery } from "@apollo/client";
import * as Sentry from "@sentry/react";

import OutfitThumbnail from "../components/OutfitThumbnail";
import { useOutfitPreview } from "../components/OutfitPreview";
import { loadable, MajorErrorMessage, TestErrorSender } from "../util";

const OutfitControls = loadable(() => import("./OutfitControls"));

function WardrobePreviewAndControls({
	isLoading,
	outfitState,
	dispatchToOutfit,
}) {
	// Whether the current outfit preview has animations. Determines whether we
	// show the play/pause button.
	const [hasAnimations, setHasAnimations] = React.useState(false);

	const { appearance, preview } = useOutfitPreview({
		isLoading: isLoading,
		speciesId: outfitState.speciesId,
		colorId: outfitState.colorId,
		pose: outfitState.pose,
		altStyleId: outfitState.altStyleId,
		appearanceId: outfitState.appearanceId,
		wornItemIds: outfitState.wornItemIds,
		onChangeHasAnimations: setHasAnimations,
		placeholder: <OutfitThumbnailIfCached outfitId={outfitState.id} />,
		"data-test-id": "wardrobe-outfit-preview",
	});

	return (
		<Sentry.ErrorBoundary fallback={MajorErrorMessage}>
			<TestErrorSender />
			<Center position="absolute" top="0" bottom="0" left="0" right="0">
				<DarkMode>{preview}</DarkMode>
			</Center>
			<Box position="absolute" top="0" bottom="0" left="0" right="0">
				<OutfitControls
					outfitState={outfitState}
					dispatchToOutfit={dispatchToOutfit}
					showAnimationControls={hasAnimations}
					appearance={appearance}
				/>
			</Box>
		</Sentry.ErrorBoundary>
	);
}

/**
 * OutfitThumbnailIfCached will render an OutfitThumbnail as a placeholder for
 * the outfit preview... but only if we already have the data to generate the
 * thumbnail stored in our local Apollo GraphQL cache.
 *
 * This means that, when you come from the Your Outfits page, we can show the
 * outfit thumbnail instantly while everything else loads. But on direct
 * navigation, this does nothing, and we just wait for the preview to load in
 * like usual!
 */
function OutfitThumbnailIfCached({ outfitId }) {
	const { data } = useQuery(
		gql`
			query OutfitThumbnailIfCached($outfitId: ID!) {
				outfit(id: $outfitId) {
					id
					updatedAt
				}
			}
		`,
		{
			variables: {
				outfitId,
			},
			skip: outfitId == null,
			fetchPolicy: "cache-only",
			onError: (e) => console.error(e),
		},
	);

	if (!data?.outfit) {
		return null;
	}

	return (
		<OutfitThumbnail
			outfitId={data.outfit.id}
			updatedAt={data.outfit.updatedAt}
			alt=""
			objectFit="contain"
			width="100%"
			height="100%"
			filter="blur(2px)"
		/>
	);
}

export default WardrobePreviewAndControls;