import clsx from "clsx";
import Link from "next/link";
import { useRouter } from "next/router";
import { GetServerSideProps } from "next";
import { ReactElement, useEffect, useMemo, useState } from "react";

import { get } from "libs/http";
import useGet from "libs/hooks/useGet";
import useStore from "libs/hooks/useStore";
import errorProps from "libs/errorProps";

import Error from "pages/_error";
import Toc from "components/novel/Toc";
import Toolbar from "components/novel/Toolbar";
import Settings from "components/novel/Settings";
import { SeoHead, SeoHeadConfig } from "components/SeoHead";

import type { NextPageWithLayout } from "pages/_app";

import { isServer } from "libs/config";
import { useHistory } from "libs/hooks/useDbItem";

import styles from "styles/chapter.module.scss";

const Chapter: NextPageWithLayout<NovelPageProps> = (props) => {
  const { statusCode } = props;
  const { siteConfig } = useStore();

  const { query } = useRouter();

  const [history, putHistoryItem] = useHistory(query.slug as string);

  const { data: { data: detail } = { data: null } } = useGet<Detail>(
    `/api/novel/${query.slug}`
  );

  const { data: { data: chapterData } = { data: null } } = useGet<ChapterData>(
    `/api/novel/chapter/${query.slug}/${query.chapter}`
  );

  const { data: { data: chapters } = { data: null } } = useGet<ChapterListData>(
    `/api/novel/${query.slug}/chapters`
  );

  const [open, setOpen] = useState(false);
  const [menu, setMenu] = useState("");
  const [isSerif, setIsSerif] = useState(false);

  const [fontSize, setFontSize] = useState(16);

  const seoConfig: SeoHeadConfig = useMemo(() => {
    const url = `https://${siteConfig.host}/novel/${query.slug}/${query.chapter}`;
    return {
      title: `${chapterData?.title} - ${chapterData?.chapter} - ${siteConfig.siteName}`,
      // TODO: 作者
      description: `Read ${chapterData?.title} ${chapterData?.chapter} on ${
        siteConfig.siteName
      }. ${chapterData?.title} novel written by ${"作者"}.`,
      keywords: `${[
        chapterData?.title,
        chapterData?.chapter,
        siteConfig.keywords,
        siteConfig.siteName,
      ]
        .filter((item) => item)
        .join(", ")}`,
      url,
      canonical: url,
      pre: chapterData?.pre
        ? `https://${siteConfig.host}/novel/${chapterData.pre}`
        : "",
      next: chapterData?.next
        ? `https://${siteConfig.host}/novel/${chapterData.next}`
        : "",
      siteName: siteConfig.siteName,
      // TODO: 图片
      img: "",
      jsonLd: chapterData
        ? JSON.stringify([
            {
              "@context": "https://schema.org",
              "@type": "Article",
              url: `https://${siteConfig.host}/novel/${query.slug}/${query.chapter}`,
              headline: `${chapterData?.title || ""} - ${
                chapterData?.chapter || ""
              }`,
              // TODO: 更新时间
              datePublished: "2018-03-16T02:13:00.000Z",
              publisher: {
                "@type": "Organization",
                name: siteConfig.siteName,
                url: `https://${siteConfig.host}/`,
              },
              isAccessibleForFree: true,
              hasPart: {
                "@type": "WebPageElement",
                isAccessibleForFree: true,
                cssSelector: styles["novel"],
              },
              // TODO: 作者
              author: { "@type": "Person", name: "作者" },
            },
            {
              "@context": "https://schema.org",
              "@type": "BreadcrumbList",
              itemListElement: [
                {
                  "@type": "ListItem",
                  position: 1,
                  name: "Home",
                  item: `https://${siteConfig.host}`,
                },
                {
                  "@type": "ListItem",
                  position: 2,
                  name: `${chapterData?.title || ""}`,
                  item: `https://${siteConfig.host}/novel/${query.slug}`,
                },
                {
                  "@type": "ListItem",
                  position: 3,
                  name: `${chapterData?.title || ""} - ${
                    chapterData?.chapter || ""
                  }`,
                  item: `https://${siteConfig.host}/novel/${query.slug}/${query.chapter}`,
                },
              ],
            },
            ...siteConfig.jsonLd,
          ])
        : "",
    };
  }, [
    chapterData,
    query.chapter,
    query.slug,
    siteConfig.host,
    siteConfig.jsonLd,
    siteConfig.keywords,
    siteConfig.siteName,
  ]);

  const handleOpenToolbar = () => {
    if (open) {
      setOpen(false);
      setMenu("");
    } else {
      setOpen(true);
    }
  };

  const handleChangeSettings = (type = "") => {
    if (menu === type) {
      setMenu("");
    } else {
      setOpen(true);
      setMenu(type);
    }
  };

  const handleStopPropagation = (e: React.MouseEvent) => {
    e.stopPropagation();
  };

  const handleSetIsSerif = (isSerif: boolean) => {
    localStorage.setItem("novelIsSerif", JSON.stringify(isSerif));
    setIsSerif(isSerif);
  };

  const handleSetFontSize = (size: number) => {
    localStorage.setItem("novelFontSize", `${size}`);
    setFontSize(size);
  };

  useEffect(() => {
    if (typeof localStorage !== "undefined") {
      const fs = localStorage.getItem("novelFontSize");
      const isSerif = localStorage.getItem("novelIsSerif");
      if (fs) {
        setFontSize(Number(fs));
      }
      if (isSerif) {
        setIsSerif(JSON.parse(isSerif));
      }
    }
  }, []);

  useEffect(() => {
    if (!isServer && detail && chapterData && chapters) {
      putHistoryItem({
        readTime: new Date(),
        chapterUri: `${query.slug}/${query.chapter}` as string,
        chapterName: chapterData.chapter,
        chapterCount: chapters.chapters.length,
        chapterIndex:
          chapters.chapters.findIndex(
            (item) => item.uri === `${query.slug}/${query.chapter}`
          ) + 1,
        img: detail.img,
        name: detail.name,
        uri: query.slug as string,
        status: detail.status,
        isReading: 1,
        isFavorite: history?.isFavorite ?? 0,
      });
    }
  }, [
    chapterData,
    chapters,
    detail,
    history?.isFavorite,
    putHistoryItem,
    query.chapter,
    query.slug,
  ]);

  if (statusCode) {
    return <Error statusCode={statusCode} />;
  }

  if (!chapterData) {
    return null;
  }

  return (
    <>
      <SeoHead seoConfig={seoConfig} />
      <header
        className={clsx("header", styles["chapter-header"], {
          [styles["open"]]: open,
        })}
      >
        <Link href="/" className="logo mr-2" title="NovelDit">
          {/* eslint-disable-next-line @next/next/no-img-element */}
          <img src="/logo.svg" alt="NovelDit" />
        </Link>
        <div className="flex-1 w-0">
          <div className="text-base breadcrumbs">
            <ul>
              <li>
                <Link href={`/novel/${query.slug}`}>{chapterData.title}</Link>
              </li>
              <li>{chapterData.chapter}</li>
            </ul>
          </div>
        </div>
      </header>
      <main
        className={styles["chapter-main"]}
        onClick={handleOpenToolbar}
        aria-hidden="true"
      >
        <div className={clsx(styles["chapter-page"])}>
          <article className={styles["novel"]}>
            <header
              className={clsx({
                ["font-serif"]: isSerif,
              })}
            >
              <h1>{chapterData.title}</h1>
              <h2>{chapterData.chapter}</h2>
            </header>
            <div
              className={clsx("content", {
                ["font-serif"]: isSerif,
                "text-xs": fontSize === 12,
                "text-sm": fontSize === 14,
                "text-base": fontSize === 16,
                "text-lg": fontSize === 18,
                "text-xl": fontSize === 20,
                "text-2xl": fontSize === 24,
              })}
              dangerouslySetInnerHTML={{ __html: chapterData.content }}
            />
            <footer className="text-center py-5">
              {chapterData.next ? (
                <div>
                  <Link
                    className="btn btn-primary uppercase"
                    href={`/novel${chapterData.next}`}
                    onClick={handleStopPropagation}
                  >
                    Next Chapter
                  </Link>
                </div>
              ) : null}
              {chapterData.pre ? (
                <div className="mt-5">
                  <Link
                    className="underline uppercase"
                    href={`/novel${chapterData.pre}`}
                    onClick={handleStopPropagation}
                  >
                    Previous Chapter
                  </Link>
                </div>
              ) : null}
            </footer>
          </article>
        </div>
        {menu ? (
          <div
            className={styles["toolbar-display"]}
            onClick={handleStopPropagation}
            aria-hidden="true"
          >
            {menu === "settings" ? (
              <Settings
                isSerif={isSerif}
                fontSize={fontSize}
                changeIsSerif={handleSetIsSerif}
                changeFontSize={handleSetFontSize}
                onChangeSettings={handleChangeSettings}
              />
            ) : null}
            {menu === "toc" ? (
              <Toc
                currentUri={`${query.slug}/${query.chapter}`}
                chapters={chapters ? chapters.chapters : []}
                onChangeSettings={handleChangeSettings}
              />
            ) : null}
          </div>
        ) : null}
      </main>
      <Toolbar
        open={open}
        type={menu}
        onChangeSettings={handleChangeSettings}
      />
    </>
  );
};

Chapter.getLayout = (page: ReactElement) => page;

export const getServerSideProps: GetServerSideProps<
  Docs,
  { slug: string; chapter: string }
> = async (context) => {
  if (!context.params) {
    return errorProps(context);
  }
  try {
    const { slug, chapter } = context.params;
    const [detail, chapterData] = await Promise.all([
      get<Detail>(`/api/novel/${slug}`),
      get<ChapterData>(`/api/novel/chapter/${slug}/${chapter}`),
    ]);

    if (!chapterData.data.content) {
      return errorProps(context);
    }

    return {
      props: {
        fallback: {
          [`/api/novel/${slug}`]: detail,
          [`/api/novel/chapter/${slug}/${chapter}`]: chapterData,
        },
      },
    };
  } catch (e) {
    return errorProps(context, 500);
  }
};

export default Chapter;
