import { Fragment, useCallback, useMemo } from "react";
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { useRouter } from "next/router";
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
import { Chip } from "components/Chip";
import { Img } from "components/Img";
import { Button } from "components/Inputs/Button";
import { Switch } from "components/Inputs/Switch";
import { InsetBox } from "components/InsetBox";
import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
import { NavOption } from "components/PanelComponents/NavOption";
import {
  ReturnButton,
  ReturnButtonType,
} from "components/PanelComponents/ReturnButton";
import {
  ContentPanel,
  ContentPanelWidthSizes,
} from "components/Panels/ContentPanel";
import { SubPanel } from "components/Panels/SubPanel";
import { PreviewCard } from "components/PreviewCard";
import { useAppLayout } from "contexts/AppLayoutContext";
import {
  Enum_Componentmetadatabooks_Binding_Type,
  Enum_Componentmetadatabooks_Page_Order,
  GetLibraryItemQuery,
} from "graphql/generated";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getReadySdk } from "graphql/sdk";
import {
  prettyDate,
  prettyInlineTitle,
  prettyItemSubType,
  prettyItemType,
  prettyPrice,
  prettySlug,
  prettyURL,
} from "helpers/formatters";
import { getAssetURL, ImageQuality } from "helpers/img";
import { convertMmToInch } from "helpers/numbers";
import {
  filterDefined,
  filterHasAttributes,
  isDefined,
  isDefinedAndNotEmpty,
  sortRangedContent,
} from "helpers/others";
import { useLightBox } from "hooks/useLightBox";
import { AnchorIds, useScrollTopOnChange } from "hooks/useScrollTopOnChange";
import { isUntangibleGroupItem } from "helpers/libraryItem";
import { useMediaHoverable } from "hooks/useMediaQuery";
import { WithLabel } from "components/Inputs/WithLabel";
import { Ico, Icon } from "components/Ico";
import { cJoin, cIf } from "helpers/className";
import { useSmartLanguage } from "hooks/useSmartLanguage";
import { useBoolean } from "hooks/useBoolean";
import { getOpenGraph } from "helpers/openGraph";
import { getDescription } from "helpers/description";

/*
 *                                           ╭────────╮
 * ──────────────────────────────────────────╯  PAGE  ╰─────────────────────────────────────────────
 */

interface Props extends AppStaticProps, AppLayoutRequired {
  item: NonNullable<
    NonNullable<
      GetLibraryItemQuery["libraryItems"]
    >["data"][number]["attributes"]
  >;
  itemId: NonNullable<
    GetLibraryItemQuery["libraryItems"]
  >["data"][number]["id"];
}

const LibrarySlug = ({
  item,
  itemId,
  langui,
  currencies,
  languages,
  ...otherProps
}: Props): JSX.Element => {
  const { currency } = useAppLayout();
  const hoverable = useMediaHoverable();
  const router = useRouter();
  const [openLightBox, LightBox] = useLightBox();
  const { state: keepInfoVisible, toggleState: toggleKeepInfoVisible } =
    useBoolean(false);

  useScrollTopOnChange(AnchorIds.ContentPanel, [item]);

  const isVariantSet = useMemo(
    () =>
      item.metadata?.[0]?.__typename === "ComponentMetadataGroup" &&
      item.metadata[0].subtype?.data?.attributes?.slug === "variant-set",
    [item.metadata]
  );

  const displayOpenScans = useMemo(
    () =>
      item.contents?.data.some(
        (content) =>
          content.attributes?.scan_set && content.attributes.scan_set.length > 0
      ),
    [item.contents?.data]
  );

  const subPanel = useMemo(
    () => (
      <SubPanel>
        <ReturnButton
          href="/library/"
          title={langui.library}
          langui={langui}
          displayOn={ReturnButtonType.Desktop}
          horizontalLine
        />

        <div className="grid gap-4">
          <NavOption title={langui.summary} url="#summary" border />

          {item.gallery && item.gallery.data.length > 0 && (
            <NavOption title={langui.gallery} url="#gallery" border />
          )}

          <NavOption title={langui.details} url="#details" border />

          {item.subitems && item.subitems.data.length > 0 && (
            <NavOption
              title={isVariantSet ? langui.variants : langui.subitems}
              url={isVariantSet ? "#variants" : "#subitems"}
              border
            />
          )}

          {item.contents && item.contents.data.length > 0 && (
            <NavOption title={langui.contents} url="#contents" border />
          )}
        </div>
      </SubPanel>
    ),
    [isVariantSet, item.contents, item.gallery, item.subitems, langui]
  );

  const contentPanel = useMemo(
    () => (
      <ContentPanel width={ContentPanelWidthSizes.Full}>
        <LightBox />

        <ReturnButton
          href="/library/"
          title={langui.library}
          langui={langui}
          displayOn={ReturnButtonType.Mobile}
          className="mb-10"
        />
        <div className="grid place-items-center gap-12">
          <div
            className="relative h-[50vh] w-full
          cursor-pointer drop-shadow-shade-xl desktop:mb-16 mobile:h-[60vh]"
            onClick={() => {
              if (item.thumbnail?.data?.attributes) {
                openLightBox([
                  getAssetURL(
                    item.thumbnail.data.attributes.url,
                    ImageQuality.Large
                  ),
                ]);
              }
            }}
          >
            {item.thumbnail?.data?.attributes ? (
              <Img
                image={item.thumbnail.data.attributes}
                quality={ImageQuality.Large}
                className="h-full w-full object-contain"
              />
            ) : (
              <div className="aspect-[21/29.7] w-full rounded-xl bg-light"></div>
            )}
          </div>

          <InsetBox id="summary" className="grid place-items-center">
            <div className="grid w-[clamp(0px,100%,42rem)] place-items-center gap-8">
              {item.subitem_of?.data[0]?.attributes && (
                <div className="grid place-items-center">
                  <p>{langui.subitem_of}</p>
                  <Button
                    href={`/library/${item.subitem_of.data[0].attributes.slug}`}
                    text={prettyInlineTitle(
                      "",
                      item.subitem_of.data[0].attributes.title,
                      item.subitem_of.data[0].attributes.subtitle
                    )}
                  />
                </div>
              )}
              <div className="grid place-items-center text-center">
                <h1 className="text-3xl">{item.title}</h1>
                {isDefinedAndNotEmpty(item.subtitle) && (
                  <h2 className="text-2xl">{item.subtitle}</h2>
                )}
              </div>

              {!isUntangibleGroupItem(item.metadata?.[0]) &&
                isDefinedAndNotEmpty(itemId) && (
                  <PreviewCardCTAs id={itemId} langui={langui} expand />
                )}

              {item.descriptions?.[0] && (
                <p className="text-justify">
                  {item.descriptions[0].description}
                </p>
              )}
              {!(
                item.metadata &&
                item.metadata[0]?.__typename === "ComponentMetadataGroup" &&
                (item.metadata[0].subtype?.data?.attributes?.slug ===
                  "variant-set" ||
                  item.metadata[0].subtype?.data?.attributes?.slug ===
                    "relation-set")
              ) && (
                <>
                  {item.urls?.length ? (
                    <div className="flex flex-row place-items-center gap-3">
                      <p>{langui.available_at}</p>
                      {filterHasAttributes(item.urls, ["url"] as const).map(
                        (url, index) => (
                          <Fragment key={index}>
                            <Button
                              href={url.url}
                              target={"_blank"}
                              text={prettyURL(url.url)}
                            />
                          </Fragment>
                        )
                      )}
                    </div>
                  ) : (
                    <p>{langui.item_not_available}</p>
                  )}
                </>
              )}
            </div>
          </InsetBox>

          {item.gallery && item.gallery.data.length > 0 && (
            <div id="gallery" className="grid w-full place-items-center  gap-8">
              <h2 className="text-2xl">{langui.gallery}</h2>
              <div
                className="grid w-full grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))] items-end
              gap-8"
              >
                {filterHasAttributes(item.gallery.data, [
                  "id",
                  "attributes",
                ] as const).map((galleryItem, index) => (
                  <Fragment key={galleryItem.id}>
                    <div
                      className="relative aspect-square cursor-pointer
                      transition-transform hover:scale-[1.02]"
                      onClick={() => {
                        const images: string[] = filterHasAttributes(
                          item.gallery?.data,
                          ["attributes"] as const
                        ).map((image) =>
                          getAssetURL(image.attributes.url, ImageQuality.Large)
                        );
                        openLightBox(images, index);
                      }}
                    >
                      <Img
                        className="h-full w-full rounded-lg
                        bg-light object-cover drop-shadow-shade-md"
                        image={galleryItem.attributes}
                      />
                    </div>
                  </Fragment>
                ))}
              </div>
            </div>
          )}

          <InsetBox id="details" className="grid place-items-center">
            <div className="place-items grid w-[clamp(0px,100%,42rem)] gap-8">
              <h2 className="text-center text-2xl">{langui.details}</h2>
              <div
                className="grid place-items-center gap-y-8
              desktop:grid-flow-col desktop:place-content-between"
              >
                {item.metadata?.[0] && (
                  <div className="grid place-content-start place-items-center">
                    <h3 className="text-xl">{langui.type}</h3>
                    <div className="grid grid-flow-col gap-1">
                      <Chip text={prettyItemType(item.metadata[0], langui)} />
                      {"›"}
                      <Chip text={prettyItemSubType(item.metadata[0])} />
                    </div>
                  </div>
                )}

                {item.release_date && (
                  <div className="grid place-content-start place-items-center">
                    <h3 className="text-xl">{langui.release_date}</h3>
                    <p>{prettyDate(item.release_date, router.locale)}</p>
                  </div>
                )}

                {item.price && (
                  <div className="grid place-content-start place-items-center text-center">
                    <h3 className="text-xl">{langui.price}</h3>
                    <p>
                      {prettyPrice(
                        item.price,
                        currencies,
                        item.price.currency?.data?.attributes?.code
                      )}
                    </p>
                    {item.price.currency?.data?.attributes?.code !==
                      currency && (
                      <p>
                        {prettyPrice(item.price, currencies, currency)} <br />(
                        {langui.calculated?.toLowerCase()})
                      </p>
                    )}
                  </div>
                )}
              </div>

              {item.categories && item.categories.data.length > 0 && (
                <div className="flex flex-col place-items-center gap-2">
                  <h3 className="text-xl">{langui.categories}</h3>
                  <div className="flex flex-row flex-wrap place-content-center gap-2">
                    {filterHasAttributes(item.categories.data, [
                      "attributes",
                    ] as const).map((category) => (
                      <Chip key={category.id} text={category.attributes.name} />
                    ))}
                  </div>
                </div>
              )}

              {item.size && (
                <div className="grid gap-8 mobile:place-items-center">
                  <h3 className="text-xl">{langui.size}</h3>
                  <div
                    className="grid w-full grid-flow-col place-content-between thin:grid-flow-row
                  thin:place-content-center thin:gap-8"
                  >
                    <div
                      className="grid place-items-center gap-x-4 desktop:grid-flow-col 
                    desktop:place-items-start"
                    >
                      <p className="font-bold">{langui.width}:</p>
                      <div>
                        <p>{item.size.width} mm</p>
                        <p>{convertMmToInch(item.size.width)} in</p>
                      </div>
                    </div>
                    <div
                      className="grid place-items-center gap-x-4 desktop:grid-flow-col
                    desktop:place-items-start"
                    >
                      <p className="font-bold">{langui.height}:</p>
                      <div>
                        <p>{item.size.height} mm</p>
                        <p>{convertMmToInch(item.size.height)} in</p>
                      </div>
                    </div>
                    {isDefined(item.size.thickness) && (
                      <div
                        className="grid place-items-center gap-x-4 desktop:grid-flow-col
                      desktop:place-items-start"
                      >
                        <p className="font-bold">{langui.thickness}:</p>
                        <div>
                          <p>{item.size.thickness} mm</p>
                          <p>{convertMmToInch(item.size.thickness)} in</p>
                        </div>
                      </div>
                    )}
                  </div>
                </div>
              )}

              {item.metadata?.[0]?.__typename !== "ComponentMetadataGroup" &&
                item.metadata?.[0]?.__typename !== "ComponentMetadataOther" && (
                  <>
                    <h3 className="text-xl">{langui.type_information}</h3>
                    <div className="grid w-full grid-cols-2 place-content-between">
                      {item.metadata?.[0]?.__typename ===
                        "ComponentMetadataBooks" && (
                        <>
                          <div className="flex flex-row place-content-start gap-4">
                            <p className="font-bold">{langui.pages}:</p>
                            <p>{item.metadata[0].page_count}</p>
                          </div>

                          <div className="flex flex-row place-content-start gap-4">
                            <p className="font-bold">{langui.binding}:</p>
                            <p>
                              {item.metadata[0].binding_type ===
                              Enum_Componentmetadatabooks_Binding_Type.Paperback
                                ? langui.paperback
                                : item.metadata[0].binding_type ===
                                  Enum_Componentmetadatabooks_Binding_Type.Hardcover
                                ? langui.hardcover
                                : ""}
                            </p>
                          </div>

                          <div className="flex flex-row place-content-start gap-4">
                            <p className="font-bold">{langui.page_order}:</p>
                            <p>
                              {item.metadata[0].page_order ===
                              Enum_Componentmetadatabooks_Page_Order.LeftToRight
                                ? langui.left_to_right
                                : langui.right_to_left}
                            </p>
                          </div>

                          <div className="flex flex-row place-content-start gap-4">
                            <p className="font-bold">{langui.languages}:</p>
                            {item.metadata[0]?.languages?.data.map((lang) => (
                              <p key={lang.attributes?.code}>
                                {lang.attributes?.name}
                              </p>
                            ))}
                          </div>
                        </>
                      )}
                    </div>
                  </>
                )}
            </div>
          </InsetBox>

          {item.subitems && item.subitems.data.length > 0 && (
            <div
              id={isVariantSet ? "variants" : "subitems"}
              className="grid w-full place-items-center gap-8"
            >
              <h2 className="text-2xl">
                {isVariantSet ? langui.variants : langui.subitems}
              </h2>

              {hoverable && (
                <WithLabel
                  label={langui.always_show_info}
                  input={
                    <Switch
                      onClick={toggleKeepInfoVisible}
                      value={keepInfoVisible}
                    />
                  }
                />
              )}

              <div
                className="grid w-full grid-cols-[repeat(auto-fill,minmax(15rem,1fr))]
              items-end gap-8 mobile:grid-cols-2 thin:grid-cols-1"
              >
                {filterHasAttributes(item.subitems.data, [
                  "id",
                  "attributes",
                ] as const).map((subitem) => (
                  <Fragment key={subitem.id}>
                    <PreviewCard
                      href={`/library/${subitem.attributes.slug}`}
                      title={subitem.attributes.title}
                      subtitle={subitem.attributes.subtitle}
                      thumbnail={subitem.attributes.thumbnail?.data?.attributes}
                      thumbnailAspectRatio="21/29.7"
                      thumbnailRounded={false}
                      keepInfoVisible={keepInfoVisible}
                      topChips={
                        subitem.attributes.metadata &&
                        subitem.attributes.metadata.length > 0 &&
                        subitem.attributes.metadata[0]
                          ? [prettyItemSubType(subitem.attributes.metadata[0])]
                          : []
                      }
                      bottomChips={subitem.attributes.categories?.data.map(
                        (category) => category.attributes?.short ?? ""
                      )}
                      metadata={{
                        currencies: currencies,
                        releaseDate: subitem.attributes.release_date,
                        price: subitem.attributes.price,
                        position: "Bottom",
                      }}
                      infoAppend={
                        !isUntangibleGroupItem(
                          subitem.attributes.metadata?.[0]
                        ) && <PreviewCardCTAs id={subitem.id} langui={langui} />
                      }
                    />
                  </Fragment>
                ))}
              </div>
            </div>
          )}

          {item.contents && item.contents.data.length > 0 && (
            <div id="contents" className="grid w-full place-items-center gap-8">
              <h2 className="-mb-6 text-2xl">{langui.contents}</h2>
              {displayOpenScans && (
                <Button
                  href={`/library/${item.slug}/scans`}
                  text={langui.view_scans}
                />
              )}
              <div className="grid w-full gap-4">
                {filterHasAttributes(item.contents.data, [
                  "attributes",
                ] as const).map((rangedContent) => (
                  <ContentLine
                    content={
                      rangedContent.attributes.content?.data?.attributes
                        ? {
                            translations: filterDefined(
                              rangedContent.attributes.content.data.attributes
                                .translations
                            ).map((translation) => ({
                              pre_title: translation.pre_title,
                              title: translation.title,
                              subtitle: translation.subtitle,
                              language:
                                translation.language?.data?.attributes?.code,
                            })),
                            categories: filterHasAttributes(
                              rangedContent.attributes.content.data.attributes
                                .categories?.data,
                              ["attributes"]
                            ).map((category) => category.attributes.short),
                            type:
                              rangedContent.attributes.content.data.attributes
                                .type?.data?.attributes?.titles?.[0]?.title ??
                              prettySlug(
                                rangedContent.attributes.content.data.attributes
                                  .type?.data?.attributes?.slug
                              ),
                            slug: rangedContent.attributes.content.data
                              .attributes.slug,
                          }
                        : undefined
                    }
                    langui={langui}
                    rangeStart={
                      rangedContent.attributes.range[0]?.__typename ===
                      "ComponentRangePageRange"
                        ? `${rangedContent.attributes.range[0].starting_page}`
                        : ""
                    }
                    slug={rangedContent.attributes.slug}
                    parentSlug={item.slug}
                    key={rangedContent.id}
                    languages={languages}
                    hasScanSet={
                      isDefined(rangedContent.attributes.scan_set) &&
                      rangedContent.attributes.scan_set.length > 0
                    }
                  />
                ))}
              </div>
            </div>
          )}
        </div>
      </ContentPanel>
    ),
    [
      LightBox,
      langui,
      item.thumbnail?.data?.attributes,
      item.subitem_of?.data,
      item.title,
      item.subtitle,
      item.metadata,
      item.descriptions,
      item.urls,
      item.gallery,
      item.release_date,
      item.price,
      item.categories,
      item.size,
      item.subitems,
      item.contents,
      item.slug,
      itemId,
      router.locale,
      currencies,
      currency,
      isVariantSet,
      hoverable,
      toggleKeepInfoVisible,
      keepInfoVisible,
      displayOpenScans,
      openLightBox,
      languages,
    ]
  );

  return (
    <AppLayout
      contentPanel={contentPanel}
      subPanel={subPanel}
      currencies={currencies}
      languages={languages}
      langui={langui}
      {...otherProps}
    />
  );
};
export default LibrarySlug;

/*
 *                                    ╭──────────────────────╮
 * ───────────────────────────────────╯  NEXT DATA FETCHING  ╰──────────────────────────────────────
 */

export const getStaticProps: GetStaticProps = async (context) => {
  const sdk = getReadySdk();
  const item = await sdk.getLibraryItem({
    slug:
      context.params && isDefined(context.params.slug)
        ? context.params.slug.toString()
        : "",
    language_code: context.locale ?? "en",
  });
  if (!item.libraryItems?.data[0]?.attributes) return { notFound: true };
  sortRangedContent(item.libraryItems.data[0].attributes.contents);
  const appStaticProps = await getAppStaticProps(context);

  const { title, thumbnail } = item.libraryItems.data[0].attributes;

  const description = getDescription(
    item.libraryItems.data[0].attributes.descriptions?.[0]?.description,
    {
      [appStaticProps.langui.categories ?? "Categories"]: filterHasAttributes(
        item.libraryItems.data[0].attributes.categories?.data,
        ["attributes.short"]
      ).map((category) => category.attributes.short),
      [appStaticProps.langui.type ?? "Type"]: item.libraryItems.data[0]
        .attributes.metadata?.[0]
        ? [prettyItemSubType(item.libraryItems.data[0].attributes.metadata[0])]
        : [],
      [appStaticProps.langui.release_date ?? "Release date"]: [
        item.libraryItems.data[0].attributes.release_date
          ? prettyDate(
              item.libraryItems.data[0].attributes.release_date,
              context.locale
            )
          : undefined,
      ],
    }
  );

  const props: Props = {
    ...appStaticProps,
    item: item.libraryItems.data[0].attributes,
    itemId: item.libraryItems.data[0].id,
    openGraph: getOpenGraph(
      appStaticProps.langui,
      title,
      description,
      thumbnail?.data?.attributes
    ),
  };
  return {
    props: props,
  };
};

// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─

export const getStaticPaths: GetStaticPaths = async (context) => {
  const sdk = getReadySdk();
  const libraryItems = await sdk.getLibraryItemsSlugs();
  const paths: GetStaticPathsResult["paths"] = [];
  filterHasAttributes(libraryItems.libraryItems?.data, [
    "attributes",
  ] as const).map((item) => {
    context.locales?.map((local) =>
      paths.push({ params: { slug: item.attributes.slug }, locale: local })
    );
  });
  return {
    paths,
    fallback: "blocking",
  };
};

/*
 *                                    ╭──────────────────────╮
 * ───────────────────────────────────╯  PRIVATE COMPONENTS  ╰──────────────────────────────────────
 */

interface ContentLineProps {
  content?: {
    translations: {
      pre_title: string | null | undefined;
      title: string;
      subtitle: string | null | undefined;
      language: string | undefined;
    }[];
    categories?: string[];
    type?: string;
    slug: string;
  };
  rangeStart: string;
  parentSlug: string;
  slug: string;
  langui: AppStaticProps["langui"];
  languages: AppStaticProps["languages"];
  hasScanSet: boolean;
}

const ContentLine = ({
  rangeStart,
  content,
  langui,
  languages,
  hasScanSet,
  slug,
  parentSlug,
}: ContentLineProps): JSX.Element => {
  const { state: isOpened, toggleState: toggleOpened } = useBoolean(false);

  const [selectedTranslation] = useSmartLanguage({
    items: content?.translations ?? [],
    languages: languages,
    languageExtractor: useCallback(
      (
        item: NonNullable<ContentLineProps["content"]>["translations"][number]
      ) => item.language,
      []
    ),
  });

  return (
    <div
      className={cJoin(
        "grid gap-2 rounded-lg px-4",
        cIf(isOpened, "my-2 h-auto bg-mid py-3 shadow-inner-sm shadow-shade")
      )}
    >
      <div
        className="grid grid-cols-[auto_auto_1fr_auto_12ch] place-items-center
        gap-4 thin:grid-cols-[auto_auto_1fr_auto]"
      >
        <a>
          <h3 className="cursor-pointer" onClick={toggleOpened}>
            {selectedTranslation
              ? prettyInlineTitle(
                  selectedTranslation.pre_title,
                  selectedTranslation.title,
                  selectedTranslation.subtitle
                )
              : content
              ? prettySlug(content.slug, parentSlug)
              : prettySlug(slug, parentSlug)}
          </h3>
        </a>
        <div className="flex flex-row flex-wrap gap-1">
          {content?.categories?.map((category, index) => (
            <Chip key={index} text={category} />
          ))}
        </div>
        <p className="h-4 w-full border-b-2 border-dotted border-black opacity-30"></p>
        <p>{rangeStart}</p>
        {content?.type && (
          <Chip className="justify-self-end thin:hidden" text={content.type} />
        )}
      </div>
      <div
        className={`grid-flow-col place-content-start place-items-center gap-2 ${
          isOpened ? "grid" : "hidden"
        }`}
      >
        <Ico icon={Icon.SubdirectoryArrowRight} className="text-dark" />

        {hasScanSet || isDefined(content) ? (
          <>
            {hasScanSet && (
              <Button
                href={`/library/${parentSlug}/scans#${slug}`}
                text={langui.view_scans}
              />
            )}
            {isDefined(content) && (
              <Button
                href={`/contents/${content.slug}`}
                text={langui.open_content}
              />
            )}
          </>
        ) : (
          "The content is not available"
        )}
      </div>
    </div>
  );
};
