import { LoaderFunctionArgs, redirect, useLoaderData } from "react-router";
import { createDiscordServerPageURL, createProfilePageURL } from "#lib/urls";
import { parseOffset } from "#lib/pagination";
import { ElementType } from "#lib/types";
import { fetchProfilePosts } from "#api/profiles";
import { FooterAd, SliderAd } from "#components/advs";
import { Paginator } from "#components/pagination";
import { CardList, PostCard } from "#components/cards";
import { ProfilePageSkeleton } from "#components/pages";
import { ButtonSubmit, FormRouter } from "#components/forms";
import {
  ProfileHeader,
  Tabs,
  IArtistDetails,
  getArtist,
} from "#entities/profiles";
import { paysites } from "#entities/paysites";
import { IPost } from "#entities/posts";
import { findFavouritePosts } from "#entities/account";
import { useRef, useState } from "react";

interface IProps {
  profile: IArtistDetails;
  postsData?: {
    count: number;
    offset?: number;
    posts: (IPost & { isFavourite: boolean })[];
  };

  query?: string;
  tags?: string[];
  dmCount?: number;
  hasLinks?: boolean;
}

export function ProfilePage() {
  const { profile, postsData, query, tags, dmCount, hasLinks } =
    useLoaderData() as IProps;
  const [isLoading, setIsLoading] = useState(false);
  const { service, id, name } = profile;
  const paysite = paysites[service];
  const title = `Posts of "${name}" from "${paysite.title}"`;

  return (
    <ProfilePageSkeleton name="user" title={title} profile={profile}>
      <SliderAd />

      <ProfileHeader service={service} profileID={id} profileName={name} />

      <div className="paginator" id="paginator-top">
        <Tabs
          currentPage="posts"
          service={service}
          artistID={id}
          dmCount={dmCount}
          hasLinks={hasLinks}
        />

        {!(postsData && (postsData?.count !== 0 || query)) ? undefined : (
          <>
            <SearchForm
              query={query}
              onLoadingChange={(loading) => setIsLoading(loading)}
            />
            <Paginator
              offset={postsData.offset}
              count={postsData.count}
              constructURL={(offset) =>
                String(
                  createProfilePageURL({
                    service,
                    profileID: id,
                    offset,
                    query,
                    tags,
                  })
                )
              }
            />
          </>
        )}
      </div>

      {!postsData ? (
        <div className="no-results">
          <h2 className="site-section__subheading">
            Nobody here but us chickens!
          </h2>
          <p className="subtitle">There are no posts for your query.</p>
        </div>
      ) : (
        <>
          <CardList className={isLoading ? "card-list--loading" : ""}>
            {postsData.posts.map((post) => (
              <PostCard
                key={`${post.id}-${post.service}-${post.user}`}
                post={post}
                isServiceIconsDisabled={true}
                isFavourite={post.isFavourite}
              />
            ))}
          </CardList>

          <FooterAd />

          <div className="paginator" id="paginator-bottom">
            <Paginator
              offset={postsData.offset}
              count={postsData.count}
              constructURL={(offset) =>
                String(
                  createProfilePageURL({
                    service,
                    profileID: id,
                    offset,
                    query,
                    tags,
                  })
                )
              }
            />
          </div>
        </>
      )}
    </ProfilePageSkeleton>
  );
}

interface ISearchFormProps
  extends Pick<IProps, "query"> {
  onLoadingChange: (loading: boolean) => void;
}

function SearchForm({ query, onLoadingChange }: ISearchFormProps) {
  const timeoutRef = useRef<NodeJS.Timeout | null>(null);

  const onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (timeoutRef.current) clearTimeout(timeoutRef.current);

    const target = e.currentTarget as HTMLInputElement;

    onLoadingChange(true);

    timeoutRef.current = setTimeout(() => {
      if (target.form) target.form.requestSubmit();
      onLoadingChange(false);
    }, 1000);
  };

  return (
    <FormRouter
      id="search-form"
      className="search-form"
      method="GET"
      autoComplete="off"
      noValidate={true}
      acceptCharset="UTF-8"
      statusSection={null}
      submitButton={undefined}
      style={{ maxWidth: "fit-content" }}
    >
      {(state) => (
        <>
          <div className="wrapper">
            <input
              type="text"
              name="q"
              id="q"
              autoComplete="off"
              defaultValue={query}
              placeholder="Search..."
              onChange={onInputChange}
            />
            <ButtonSubmit
              disabled={state === "loading" || state === "submitting"}
              className="search-button"
              onClick={() => {
                if (timeoutRef.current) clearTimeout(timeoutRef.current);
                onLoadingChange(false);
              }}
            >
              <img src='/static/menu/search.svg' />
            </ButtonSubmit>
          </div>
        </>
      )}
    </FormRouter>
  );
}

export async function loader({
  params,
  request,
}: LoaderFunctionArgs): Promise<IProps | Response> {
  const searchParams = new URL(request.url).searchParams;
  const service = params.service?.trim() || "";
  const profileID = params.creator_id?.trim() || "";

  if (service === "discord") {
    return redirect(String(createDiscordServerPageURL(profileID)));
  }

  const offsetParam = searchParams.get("o")?.trim();
  const offset = offsetParam ? parseOffset(offsetParam) : undefined;
  const query = searchParams.get("q")?.trim();
  const tags = searchParams.getAll("tag");

  const profile = await getArtist(service, profileID);

  if (profileID == profile.public_id && profile.public_id != profile.id) {
    return redirect(String(createProfilePageURL({ service, profileID: profile.id })));
  }

  const { props, results: posts } = await fetchProfilePosts(
    service,
    profileID,
    offset,
    query,
    tags
  );
  const { count, dm_count, has_links } = props;
  const hasLinks = !has_links || has_links === "0" ? false : true;
  const favPostData = await findFavouritePosts(
    posts.map(({ service, user, id }) => {
      return {
        service,
        user,
        id,
      };
    })
  );
  const finalPosts = posts.map<
    ElementType<Required<IProps>["postsData"]["posts"]>
  >((post) => {
    const match = favPostData.find(
      ({ service, user, id }) =>
        service === post.service && user === post.user && id === post.id
    );

    return { ...post, isFavourite: !match ? false : true };
  });

  return {
    profile,
    query,
    tags,
    postsData: {
      count,
      offset,
      posts: finalPosts,
    },
    dmCount: dm_count,
    hasLinks,
  };
}
