import {
	DndContext,
	DragOverlay,
	KeyboardSensor,
	PointerSensor,
	pointerWithin,
	TouchSensor,
	useSensor,
	useSensors,
} from "@dnd-kit/core";
import { sortableKeyboardCoordinates } from "@dnd-kit/sortable";
import clsx from "clsx";
import { HardDriveDownload, Plus, RefreshCcw } from "lucide-react";
import { useRef } from "react";
import { flushSync } from "react-dom";
import { useTranslation } from "react-i18next";
import type { MetaFunction } from "react-router";
import { Avatar } from "~/components/Avatar";
import { SendouButton } from "~/components/elements/Button";
import {
	SendouChipRadio,
	SendouChipRadioGroup,
} from "~/components/elements/ChipRadio";
import { SendouPopover } from "~/components/elements/Popover";
import { SendouSwitch } from "~/components/elements/Switch";
import {
	SendouTab,
	SendouTabList,
	SendouTabPanel,
	SendouTabs,
} from "~/components/elements/Tabs";
import { ModeImage } from "~/components/Image";
import { Main } from "~/components/Main";
import { Placeholder } from "~/components/Placeholder";
import { useUser } from "~/features/auth/core/user";
import { useHydrated } from "~/hooks/useHydrated";
import { modesShort } from "~/modules/in-game-lists/modes";
import { metaTags } from "~/utils/remix";
import type { SendouRouteHandle } from "~/utils/remix.server";
import { navIconUrl, TIER_LIST_MAKER_URL } from "~/utils/urls";
import { ItemDragPreview } from "../components/ItemDragPreview";
import { ItemPool } from "../components/ItemPool";
import { TierRow } from "../components/TierRow";
import {
	TierListProvider,
	useTierListState,
} from "../contexts/TierListContext";
import type { TierListPlacementMode } from "../hooks/useTierList";
import type { TierListItem } from "../tier-list-maker-schemas";
import styles from "./tier-list-maker.module.css";

const PLACEMENT_MODES: TierListPlacementMode[] = ["click", "track"];

export const meta: MetaFunction = (args) => {
	return metaTags({
		title: "Tier List Maker",
		ogTitle: "Splatoon 3 tier list maker",
		description:
			"Generate Splatoon tier lists featuring main weapons, sub weapons, special weapons or stages.",
		location: args.location,
	});
};

export const handle: SendouRouteHandle = {
	i18n: "tier-list-maker",
	breadcrumb: () => ({
		imgPath: navIconUrl("tier-list-maker"),
		href: TIER_LIST_MAKER_URL,
		type: "IMAGE",
	}),
};

export default function TierListMakerPage() {
	const isHydrated = useHydrated();

	if (!isHydrated)
		return (
			<Main bigger>
				<Placeholder />
			</Main>
		);

	return (
		<TierListProvider>
			<TierListMakerContent />
		</TierListProvider>
	);
}

function TierListMakerContent() {
	const { t } = useTranslation(["tier-list-maker"]);
	const user = useUser();

	const {
		itemType,
		setItemType,
		state,
		activeItem,
		handleDragStart,
		handleDragOver,
		handleDragEnd,
		handleAddTier,
		handleReset,
		hideAltKits,
		setHideAltKits,
		hideAltSkins,
		setHideAltSkins,
		canAddDuplicates,
		setCanAddDuplicates,
		showTierHeaders,
		setShowTierHeaders,
		title,
		setTitle,
		screenshotMode,
		setScreenshotMode,
		selectedModes,
		setSelectedModes,
		placementMode,
		setPlacementMode,
	} = useTierListState();

	const sensors = useSensors(
		useSensor(PointerSensor),
		useSensor(TouchSensor, {
			activationConstraint: {
				delay: 200,
				tolerance: 5,
			},
		}),
		useSensor(KeyboardSensor, {
			coordinateGetter: sortableKeyboardCoordinates,
		}),
	);

	const tierListRef = useRef<HTMLDivElement>(null);

	const handleDownload = async () => {
		if (!tierListRef.current) return;

		const { snapdom } = await import("@zumer/snapdom");

		flushSync(() => setScreenshotMode(true));

		await snapdom.download(tierListRef.current, {
			type: "png",
			filename: "tier-list",
			quality: 1,
			scale: 1.75,
			embedFonts: true,
			backgroundColor: getComputedStyle(document.body).backgroundColor,
		});

		setScreenshotMode(false);
	};

	return (
		<Main bigger className={clsx(styles.container, "stack lg")}>
			<div className={styles.header}>
				<div className="stack horizontal md">
					<SendouButton onPress={handleAddTier} size="small" icon={<Plus />}>
						{t("tier-list-maker:addTier")}
					</SendouButton>
					<SendouButton
						onPress={handleDownload}
						size="small"
						icon={<HardDriveDownload />}
					>
						{t("tier-list-maker:download")}
					</SendouButton>
				</div>
				<ResetPopover key={state.tierItems.size} handleReset={handleReset} />
			</div>

			<DndContext
				key={itemType}
				sensors={sensors}
				collisionDetection={pointerWithin}
				onDragStart={handleDragStart}
				onDragOver={handleDragOver}
				onDragEnd={handleDragEnd}
			>
				<div className="stack">
					<div
						className={clsx(styles.tierList, {
							[styles.tierListScreenshotMode]: screenshotMode,
						})}
						ref={tierListRef}
					>
						{title || !screenshotMode ? (
							<input
								type="text"
								value={title}
								onChange={(e) => setTitle(e.target.value)}
								placeholder={t("tier-list-maker:titlePlaceholder")}
								className={clsx(styles.titleInput, "plain")}
							/>
						) : null}
						{screenshotMode && title && user ? (
							<div className={styles.authorSection}>
								<div className={styles.authorBy}>{t("tier-list-maker:by")}</div>
								<div className={styles.authorInfo}>
									<Avatar user={user} size="xxxs" alt={user.username} />
									<span className={styles.authorUsername}>{user.username}</span>
								</div>
							</div>
						) : null}
						{state.tiers.map((tier) => (
							<TierRow key={tier.id} tier={tier} />
						))}
					</div>

					<div className="stack horizontal md flex-wrap items-center">
						<SendouChipRadioGroup>
							{PLACEMENT_MODES.map((mode) => (
								<SendouChipRadio
									key={mode}
									name="tier-list-placement-mode"
									value={mode}
									checked={placementMode === mode}
									onChange={(value) =>
										setPlacementMode(value as TierListPlacementMode)
									}
								>
									{t(
										`tier-list-maker:placementMode${mode === "track" ? "Track" : "Click"}`,
									)}
								</SendouChipRadio>
							))}
						</SendouChipRadioGroup>
						<SendouSwitch
							isSelected={!canAddDuplicates}
							onChange={(value) => setCanAddDuplicates(!value)}
						>
							{t("tier-list-maker:noDuplicates")}
						</SendouSwitch>
						<SendouSwitch
							isSelected={showTierHeaders}
							onChange={setShowTierHeaders}
						>
							{t("tier-list-maker:showTierHeaders")}
						</SendouSwitch>
					</div>
				</div>

				<SendouTabs
					selectedKey={itemType}
					onSelectionChange={(key) => setItemType(key as TierListItem["type"])}
				>
					<SendouTabList>
						<SendouTab id="main-weapon">
							{t("tier-list-maker:mainWeapons")}
						</SendouTab>
						<SendouTab id="sub-weapon">
							{t("tier-list-maker:subWeapons")}
						</SendouTab>
						<SendouTab id="special-weapon">
							{t("tier-list-maker:specialWeapons")}
						</SendouTab>
						<SendouTab id="stage">{t("tier-list-maker:stages")}</SendouTab>
						<SendouTab id="mode">{t("tier-list-maker:modes")}</SendouTab>
						<SendouTab id="stage-mode">
							{t("tier-list-maker:stageModes")}
						</SendouTab>
						<SendouTab id="ability">{t("tier-list-maker:abilities")}</SendouTab>
					</SendouTabList>

					<SendouTabPanel id="main-weapon">
						<div className="stack md">
							<ItemPool />
							<div className={styles.filters}>
								<SendouSwitch
									isSelected={hideAltKits}
									onChange={setHideAltKits}
								>
									{t("tier-list-maker:hideAltKits")}
								</SendouSwitch>
								<SendouSwitch
									isSelected={hideAltSkins}
									onChange={setHideAltSkins}
								>
									{t("tier-list-maker:hideAltSkins")}
								</SendouSwitch>
							</div>
						</div>
					</SendouTabPanel>

					<SendouTabPanel id="sub-weapon">
						<ItemPool />
					</SendouTabPanel>

					<SendouTabPanel id="special-weapon">
						<ItemPool />
					</SendouTabPanel>

					<SendouTabPanel id="stage">
						<ItemPool />
					</SendouTabPanel>

					<SendouTabPanel id="mode">
						<ItemPool />
					</SendouTabPanel>

					<SendouTabPanel id="stage-mode">
						<div className="stack md">
							<ItemPool />
							<div className={clsx(styles.filters, styles.modeFilters)}>
								{modesShort.map((mode) => {
									const isSelected = selectedModes.includes(mode);
									return (
										<SendouSwitch
											key={mode}
											isSelected={isSelected}
											onChange={(selected) => {
												if (selected) {
													setSelectedModes([...selectedModes, mode]);
												} else {
													setSelectedModes(
														selectedModes.filter((m) => m !== mode),
													);
												}
											}}
										>
											<ModeImage mode={mode} size={32} />
										</SendouSwitch>
									);
								})}
							</div>
						</div>
					</SendouTabPanel>

					<SendouTabPanel id="ability">
						<ItemPool />
					</SendouTabPanel>
				</SendouTabs>

				<DragOverlay>
					{activeItem ? <ItemDragPreview item={activeItem} /> : null}
				</DragOverlay>
			</DndContext>
		</Main>
	);
}

function ResetPopover({ handleReset }: { handleReset: () => void }) {
	const { t } = useTranslation(["tier-list-maker", "common"]);

	return (
		<SendouPopover
			trigger={
				<SendouButton
					size="small"
					icon={<RefreshCcw />}
					variant="minimal-destructive"
				>
					{t("common:actions.reset")}
				</SendouButton>
			}
		>
			<div className="stack sm items-center">
				<div>{t("tier-list-maker:resetConfirmation")}</div>
				<div className="stack horizontal sm">
					<SendouButton
						size="miniscule"
						variant="destructive"
						onPress={() => {
							handleReset();
						}}
					>
						{t("common:actions.reset")}
					</SendouButton>
				</div>
			</div>
		</SendouPopover>
	);
}
