import clsx from "clsx";
import { add, sub } from "date-fns";
import React from "react";
import { useTranslation } from "react-i18next";
import type { MetaFunction } from "react-router";
import { useFetcher, useLoaderData } from "react-router";
import { AddNewButton } from "~/components/AddNewButton";
import { Alert } from "~/components/Alert";
import { Main } from "~/components/Main";
import { SubmitButton } from "~/components/SubmitButton";
import { useUser } from "~/features/auth/core/user";
import { useSearchParamStateEncoder } from "~/hooks/useSearchParamState";
import { databaseTimestampToDate } from "~/utils/dates";
import { metaTags, type SerializeFrom } from "~/utils/remix";
import type { SendouRouteHandle } from "~/utils/remix.server";
import type { Unpacked } from "~/utils/types";
import { LFG_PAGE, lfgNewPostPage, navIconUrl } from "~/utils/urls";
import { action } from "../actions/lfg.server";
import { LFGAddFilterButton } from "../components/LFGAddFilterButton";
import { LFGFilters } from "../components/LFGFilters";
import { LFGPost } from "../components/LFGPost";
import { filterPosts } from "../core/filtering";
import { LFG } from "../lfg-constants";
import {
	filterToSmallStr,
	type LFGFilter,
	smallStrToFilter,
} from "../lfg-types";
import { loader } from "../loaders/lfg.server";
import styles from "./lfg.module.css";
export { loader, action };

export const handle: SendouRouteHandle = {
	i18n: ["lfg"],
	breadcrumb: () => ({
		imgPath: navIconUrl("lfg"),
		href: LFG_PAGE,
		type: "IMAGE",
	}),
};

export const meta: MetaFunction = (args) => {
	return metaTags({
		title: "LFG",
		ogTitle: "Splatoon LFG (looking for players, teams & coaches)",
		description:
			"Find people to play Splatoon with. Create a post or browse existing ones. For looking players, teams, scrim partners and coaches alike.",
		location: args.location,
	});
};

export type LFGLoaderData = SerializeFrom<typeof loader>;
export type LFGLoaderPost = Unpacked<LFGLoaderData["posts"]>;
export type TiersMap = ReturnType<typeof unserializeTiers>;

const unserializeTiers = (data: SerializeFrom<typeof loader>) =>
	new Map(data.tiersMap);

function decodeURLQuery(queryString: string): LFGFilter[] {
	if (queryString === "") {
		return [];
	}
	return queryString
		.split("-")
		.map(smallStrToFilter)
		.filter((x) => x !== null);
}

function encodeURLQuery(filters: LFGFilter[]): string {
	return filters.map(filterToSmallStr).join("-");
}

export default function LFGPage() {
	const { t } = useTranslation(["common", "lfg"]);
	const user = useUser();
	const data = useLoaderData<typeof loader>();
	const [filterFromSearch, setTilterFromSearch] = useSearchParamStateEncoder({
		defaultValue: [],
		name: "q",
		revive: decodeURLQuery,
		encode: encodeURLQuery,
	});
	const [filters, _setFilters] = React.useState<LFGFilter[]>(filterFromSearch);
	const setFilters = (x: LFGFilter[]) => {
		setTilterFromSearch(x);
		_setFilters(x);
	};

	const tiersMap = React.useMemo(() => unserializeTiers(data), [data]);

	const filteredPosts = filterPosts(data.posts, filters, tiersMap);

	const showExpiryAlert = (post: Unpacked<LFGLoaderData["posts"]>) => {
		if (post.author.id !== user?.id) return false;

		const expiryDate = add(databaseTimestampToDate(post.updatedAt), {
			days: LFG.POST_FRESHNESS_DAYS,
		});
		const expiryCloseDate = sub(expiryDate, { days: 7 });

		if (new Date() < expiryCloseDate) return false;

		return true;
	};

	return (
		<Main className="stack xl">
			<div className="stack sm horizontal justify-end">
				<LFGAddFilterButton
					addFilter={(newFilter) => setFilters([...filters, newFilter])}
					filters={filters}
				/>
				<AddNewButton navIcon="lfg" to={lfgNewPostPage()} />
			</div>
			<LFGFilters
				filters={filters}
				changeFilter={(newFilter) =>
					setFilters(
						filters.map((filter) =>
							filter._tag === newFilter._tag ? newFilter : filter,
						),
					)
				}
				removeFilterByTag={(tag) =>
					setFilters(filters.filter((filter) => filter._tag !== tag))
				}
			/>
			{filteredPosts.map((post) => (
				<div
					key={post.id}
					id={String(post.id)}
					className={clsx("stack sm", styles.post)}
				>
					{showExpiryAlert(post) ? <PostExpiryAlert postId={post.id} /> : null}
					<LFGPost post={post} tiersMap={tiersMap} />
				</div>
			))}
			{filteredPosts.length === 0 ? (
				<div className="text-lighter text-lg font-semi-bold text-center mt-6">
					{t("lfg:noPosts")}
				</div>
			) : null}
		</Main>
	);
}

function PostExpiryAlert({ postId }: { postId: number }) {
	const { t } = useTranslation(["common", "lfg"]);
	const fetcher = useFetcher();

	return (
		<Alert variation="WARNING">
			<fetcher.Form method="post" className="stack md horizontal items-center">
				<input type="hidden" name="id" value={postId} />
				{t("lfg:expiring")}{" "}
				<SubmitButton _action="BUMP_POST" variant="outlined" size="small">
					{t("common:actions.clickHere")}
				</SubmitButton>
			</fetcher.Form>
		</Alert>
	);
}
