import { useNavigate, useParams } from "react-router";
import "@material/web/chips/assist-chip";
import "@material/web/chips/chip-set";
import ChipSet from "../md-components/ChipSet";
import AssistChip from "../md-components/AssistChip";
import { useEffect, useRef, useState } from "react";
import FilledButton from "../md-components/FilledButton";
import Dialog from "../md-components/Dialog";
import OutlinedButton from "../md-components/OutlinedButton";
import Icon from "../md-components/Icon";
import "./BookPage.css";
import Skeleton from "react-loading-skeleton";
import axios from "axios";
import DOMPurify from "dompurify";
import { Link } from "react-router-dom";
import { getBook } from "../db";
import { translit } from "../translit";
import { toast } from "react-toastify";
import IconButton from "../md-components/IconButton";
import NotFound from "./NotFound";
import MenuItem from "../md-components/MenuItem";
import Menu from "../md-components/Menu";
import List from "../md-components/List";
import ListItem from "../md-components/ListItem";
import TextField from "../md-components/TextField";

const InfoRow = ({ field, name }) => {
  if (!field) return;
  let result = field;
  if (result instanceof Object) {
    result = field.map((obj) => obj.name);
  }
  if (result instanceof Array) {
    result = result.join(", ");
  }
  return (
    <tr>
      <td>{name}</td>
      <td>{result}</td>
    </tr>
  );
};

const BookPage = () => {
  const { id } = useParams();
  const [bookInfo, setBookInfo] = useState(false);
  const [bookImgSrc, setBookImgSrc] = useState();
  const [openShare, setOpenShare] = useState(false);
  const [openInfo, setOpenInfo] = useState(false);
  const [allCollections, setAllCollections] = useState([]);
  const [collectionsFilter, setCollectionsFilter] = useState([]);
  const [downloading, setDownloading] = useState(false);

  const navigate = useNavigate();
  async function loadImgFromCache() {
    if (window.caches === undefined) {
      setBookImgSrc(axios.defaults.baseURL + "/book/" + id + "/cover");
      return;
    }
    let cache = await window.caches.open("bookCovers");
    let img = await cache.match(`/api/book/${id}/cover`);
    if (img === undefined) {
      setBookImgSrc(axios.defaults.baseURL + "/book/" + id + "/cover");
      return;
    }
    let blob = await img.blob();
    setBookImgSrc(URL.createObjectURL(blob));
  }
  const loadBookInfo = async (soft) => {
    if (!soft) {
      setBookInfo(false);
    }
    loadImgFromCache();
    let localBook = await getBook(id);
    if (window.onLine && !localBook) {
      axios
        .get("/book/" + id)
        .then((res) => setBookInfo(res.data))
        .catch(() => setBookInfo(404));
      axios.get("/collection").then((res) => setAllCollections(res.data));
    } else if (localBook) {
      setBookInfo(localBook);
    } else {
      navigate("/offline");
    }
  };
  const updateCollections = (id) => {
    setAllCollections((a) =>
      a.map((c) => {
        if (c.id !== id) return c;
        c.hasBook = !c.hasBook;
        return c;
      })
    );
  };
  useEffect(() => {
    loadBookInfo();
  }, []);
  useEffect(() => {
    // первоначальная загрузка наличия книги в списках (ааа какой же костыль)
    if (bookInfo.collections) {
      setAllCollections((a) =>
        a.map((c) => {
          if (bookInfo.collections.filter((o) => o.id === c.id).length > 0) {
            c.hasBook = true;
          } else {
            c.hasBook = false;
          }
          return c;
        })
      );
    }
  }, [bookInfo]);
  async function getBookBlob() {
    return (await axios.get(`/book/${id}/download`, { responseType: "blob" }))
      .data;
  }
  function getBookFilename() {
    if (bookInfo.authors === null) {
      return `${translit(bookInfo.title)}.${bookInfo.filetype}`;
    } else {
      return `${translit(bookInfo.authors[0].name)}_-_${translit(
        bookInfo.title
      )}.${bookInfo.filetype}`;
    }
  }
  async function downloadBook() {
    setDownloading(true);
    let a = document.createElement("a");
    let bookBlob = await getBookBlob();
    document.body.appendChild(a);
    a.style = "display: none";
    let blobURL = URL.createObjectURL(bookBlob);
    a.href = blobURL;
    a.download = getBookFilename();
    a.click();
    window.URL.revokeObjectURL(blobURL);
    setDownloading(false);
  }
  const selectLinkRef = useRef();
  const collectionDialogRef = useRef();
  function share() {
    setOpenShare(true);
  }
  if (bookInfo == 404) {
    return <NotFound />;
  }
  return (
    <div className="book_container">
      <Dialog open={openShare} onClose={() => setOpenShare(false)}>
        <div slot="headline">Поделиться</div>
        <div slot="content">
          <div
            style={{
              background: "var(--md-sys-color-inverse-on-surface)",
              color: "white",
              padding: "10px",
              borderRadius: "25px",
              display: "flex",
              alignItems: "center",
              gap: "15px",
            }}
          >
            <span
              ref={selectLinkRef}
              style={{ wordBreak: "break-all", textAlign: "center" }}
            >
              {window.location.protocol +
                "//" +
                window.location.host +
                window.location.pathname}
            </span>
            <div style={{ width: "40px", height: "40px" }}>
              <IconButton
                onClick={async () => {
                  let range = document.createRange();
                  range.selectNode(selectLinkRef.current);
                  let sel = window.getSelection();
                  sel.removeAllRanges();
                  sel.addRange(range);
                  await navigator.clipboard.writeText(sel.toString());
                  toast.success("скопировано");
                }}
                disabled={navigator.clipboard === undefined}
              >
                <Icon>link</Icon>
              </IconButton>
            </div>
          </div>
          {navigator.share === undefined ? (
            <p style={{ color: "#ff3333" }}>
              Ваш браузер не поддерживает{" "}
              <a
                href="https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share"
                style={{ color: "#ff3333" }}
              >
                share api
              </a>
            </p>
          ) : (
            <></>
          )}
        </div>
        <div slot="actions">
          <OutlinedButton onClick={() => setOpenShare(false)}>
            закрыть
          </OutlinedButton>
          {/* FileShare - до лучших времен
                     <OutlinedIconButton
                        disabled={navigator.share === undefined}
                        onClick={async () => {
                            let bookBlob = await getBookBlob()
                            console.log(bookBlob)
                            navigator.share({
                                files: [
                                    new File(
                                        [bookBlob],
                                        "test.fb2",
                                        {
                                            type: "application/pdf"
                                        }
                                    )
                                ],
                                text: "YaBL - " + bookInfo.title,
                                title: 'some_title',
                                url: 'some_url'
                            })
                        }}
                    >
                        <Icon>attach_file</Icon>
                    </OutlinedIconButton> */}
          <FilledButton
            onClick={() => {
              setOpenShare(false);
              navigator.share({
                url: "",
                title: "YaBL - " + bookInfo.title,
              });
            }}
            disabled={navigator.share === undefined}
            autoFocus
          >
            <Icon slot="icon">share</Icon>
            поделиться
          </FilledButton>
        </div>
      </Dialog>
      <Dialog open={openInfo} onClose={() => setOpenInfo(false)}>
        <div slot="headline">Информация</div>
        <div slot="content" className="m3infoTable">
          <h3>Вес файла</h3>
          <span>{(bookInfo.size / 1024 / 1024).toFixed(2)} Мб</span>
          <h3>Файл</h3>
          <span>{bookInfo.filename}</span>
          <h3>Хеш (xxh64)</h3>
          <span>{bookInfo.hash || "отсутствует"}</span>
          <h3>Архив</h3>
          <span>{bookInfo.bookcase}</span>
        </div>
        <div slot="actions">
          <FilledButton onClick={() => setOpenInfo(false)}>
            закрыть
          </FilledButton>
        </div>
      </Dialog>
      <Dialog ref={collectionDialogRef}>
        <div slot="headline">Коллекции</div>
        <div slot="content">
          <TextField onInput={(e) => setCollectionsFilter(e.target.value)}>
            <Icon slot="leading-icon">search</Icon>
          </TextField>
          <br />
          <br />
          <div style={{ height: 300 }}>
            <List
              style={{
                borderRadius: 12,
                overflowX: "hidden",
                height: "calc(100% - 10px)",
              }}
            >
              {allCollections
                .filter((coll) => coll.name.includes(collectionsFilter))
                .map((coll) => (
                  <ListItem
                    key={coll.id}
                    type="button"
                    onClick={() => {
                      axios
                        .post("/collection/" + coll.id, { book_id: id })
                        .then(() => updateCollections(coll.id));
                    }}
                  >
                    {coll.name}
                    {coll.hasBook ? <Icon slot="end">check</Icon> : <></>}
                  </ListItem>
                ))}
            </List>
          </div>
        </div>
        <div slot="actions">
          <FilledButton onClick={() => collectionDialogRef.current.close()}>
            закрыть
          </FilledButton>
        </div>
      </Dialog>
      <img className="book_cover" src={bookImgSrc} />
      <div className="book_info">
        <span
          className="break-words"
          style={{
            fontSize: "35px",
          }}
        >
          {bookInfo.title || <Skeleton width={200} />}
        </span>
        <span>
          {bookInfo.authors ? (
            bookInfo.authors
              .map((author) => (
                <Link
                  to={`/search?author=${author.id}&offset=0&limit=10`}
                  style={{ color: "var(--md-sys-color-on-background)" }}
                >
                  {author.name}
                </Link>
              ))
              .reduce((prev, curr) => [prev, ", ", curr])
          ) : bookInfo.authors === null ? (
            <span>Автор неизвестен</span>
          ) : (
            <Skeleton width={300} />
          )}
        </span>
        <ChipSet
          style={{
            margin: "10px 0",
          }}
        >
          {bookInfo.genres !== undefined ? (
            bookInfo.genres !== null ? (
              bookInfo.genres.map((value) => (
                <AssistChip label={value.name} key={value.id} />
              ))
            ) : (
              <></>
            )
          ) : (
            [150, 100, 200].map((w, key) => (
              <Skeleton width={w} height={32} key={key} />
            ))
          )}
        </ChipSet>

        <div className="buttons_container">
          <FilledButton
            style={{ width: "100%" }}
            disabled={!window.onLine || downloading}
            onClick={downloadBook}
            className="action_button"
          >
            {downloading ? (
              <>
                <div slot="icon" class="flex justify-center items-center">
                  <div class="w-3 border-t-transparent rounded-full h-3 border-2 animate-spin"></div>
                </div>
                <>Загрузка...</>
              </>
            ) : (
              <>
                <Icon slot="icon" style={{ marginTop: "2px" }}>
                  download
                </Icon>
                <>Скачать .{bookInfo.filetype}</>
              </>
            )}
          </FilledButton>
          <Link to={"/reader/" + id} className="action_button">
            <OutlinedButton style={{ width: "100%" }}>
              <Icon slot="icon" style={{ marginTop: "2px" }}>
                chrome_reader_mode
              </Icon>
              Читать онлайн
            </OutlinedButton>
          </Link>
          <OutlinedButton
            disabled={!window.onLine}
            className="action_button"
            onClick={() => collectionDialogRef.current.show()}
          >
            <Icon
              slot="icon"
              style={{
                marginTop: "2px",
              }}
            >
              collections_bookmark
            </Icon>
            В коллекцию
          </OutlinedButton>
        </div>
        {bookInfo.description !== "" ? (
          <span>
            <b>Описание</b>
          </span>
        ) : (
          <></>
        )}
        {bookInfo.description !== undefined || bookInfo.description !== "" ? (
          <div
            dangerouslySetInnerHTML={{
              __html: DOMPurify.sanitize(bookInfo.description),
            }}
          />
        ) : (
          <Skeleton count={10} />
        )}
        <div style={{ height: "20px" }} />
        <span>
          <b>Информация</b>
        </span>
        <div style={{ height: "20px" }} />
        {bookInfo ? (
          <table className="info_table">
            <tbody>
              <InfoRow field={bookInfo.lang} name={"Язык"} />
              <InfoRow field={bookInfo.translators} name={"Переводчики"} />
              <InfoRow field={bookInfo.sequence} name={"Серия"} />
              <InfoRow field={bookInfo.src_lang} name={"Язык оригинала"} />
              <InfoRow field={bookInfo.isbn} name={"ISBN"} />
              <InfoRow field={bookInfo.publisher} name={"Издатель"} />
              <InfoRow field={bookInfo.year} name={"Год выхода"} />
              <InfoRow field={bookInfo.downloads} name={"Загрузки"} />
            </tbody>
          </table>
        ) : (
          <Skeleton count={5} />
        )}
        <div
          style={{
            marginTop: "25px",
            display: "flex",
            justifyContent: "center",
            flexDirection: "row",
            alignItems: "center",
            gap: "15px",
          }}
        >
          <IconButton onClick={() => setOpenInfo(true)}>
            <Icon>info</Icon>
          </IconButton>
          <IconButton onClick={() => share()}>
            <Icon>share</Icon>
          </IconButton>
          <IconButton onClick={() => toast.info("coming soon...")}>
            <Icon>flag</Icon>
          </IconButton>
        </div>
      </div>
    </div>
  );
};

export default BookPage;
