// TODO: https://github.com/Daninet/hash-wasm probably
// since this one wasn't updated in 3 years
import sha256 from "sha256-wasm";
import {
  createDiscordChannelPageURL,
} from "#lib/urls";
import { fetchSearchFileByHash } from "#api/files";
import { PageSkeleton } from "#components/pages";
import { CardList, PostCard } from "#components/cards";
import { KemonoLink } from "#components/links";

import * as styles from "./search_hash.module.scss";
import { MouseEvent, useState } from "react";
import { LoadingIcon } from "#components/loading";

export function SearchFilesPage() {
  const title = "Search files";
  const heading = "Search Files";
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");
  const [files, setFiles] = useState<FileList | null>(null);
  const [hash, setHash] = useState("");
  const [result, setResult] = useState<Awaited<ReturnType<typeof fetchSearchFileByHash>> | null>(null);

  async function submitClicked(event: MouseEvent) {
    event.preventDefault();
    setLoading(true);

    try {
      if (files?.length) {
        let fileHash = await getFileHash(files[0]);
        setResult(await fetchSearchFileByHash(fileHash));
      } else {
        if (hash.match(/[a-f0-9]{64}/)) {
          setResult(await fetchSearchFileByHash(hash));
        } else {
          setError("Invalid hash!");
        }
      }
    } finally {
      setLoading(false);
    }
  }

  return (
    <PageSkeleton name="file-hash-search" title={title} heading={heading}>
      <form className={styles.searchForm}>
        <div className="form__section">
          <label htmlFor="file">File:</label>
          <input id="file" type="file" name="file" onChange={e => setFiles(e.target.files)} />
        </div>

        <div className="form__section" style={{marginTop: "-1em"}}>
          <span>
            <br />
            —or—
            <br />
          </span>
        </div>

        <div className="form__section">
          <label htmlFor="hash">SHA256 hash:</label>
          <input id="hash" type="text" name="hash" onChange={e => setHash(e.target.value.toLowerCase())} value={hash} />
        </div>

        <div className={styles.error} style={{display: error ? "block" : "none"}}>
          {error}
        </div>

        <button className="button" onClick={submitClicked} disabled={!(files?.length || hash) || loading}>Submit</button>
      </form>

      {loading ? <LoadingIcon /> : !result?.posts?.length ? (
        <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>
          {result.posts.map((post, index) => (
            <PostCard
              key={index}
              // @ts-expect-error custom endpoint meme type
              post={post}
            />
          ))}
        </CardList>
      )}

      {result?.discord_posts && result?.discord_posts.length !== 0 && (
        <>
          <h2>Discord</h2>
          {result.discord_posts.map((post, index) => (
            <p key={index}>
              <KemonoLink
                url={String(
                  createDiscordChannelPageURL(post.server, post.channel)
                )}
              >
                Server {post.server} channel {post.channel}
              </KemonoLink>
            </p>
          ))}
        </>
      )}
    </PageSkeleton>
  );
}

async function getFileHash(file: File) {
  const fileSize = file.size;
  const chunkSize = 1024 * 1024; // 1Mi
  let offset = 0;
  let hash = new sha256();

  while (offset < fileSize) {
    const arr = new Uint8Array(
      await file.slice(offset, chunkSize + offset).arrayBuffer()
    );
    hash.update(arr);
    offset += chunkSize;
  }

  return hash.digest("hex");
}
