import clsx from "clsx";
import { useEffect, useRef, useState } from "react";
import { THUMBNAILS_PREPEND, VIDEO_AD } from "#env/env-vars";
import { createAttachmentURL, createPreviewURL } from "#lib/urls";
import { MiddleAd } from "#components/advs";
import {
  IPostAttachment,
  IPostPoll,
  IPreviewEmbed,
  IPreviewThumbnail,
} from "#entities/posts";
import { cleanupBody } from "./clean-body";
import { IPostOverviewProps } from "./types";
import { PostVideo } from "./video";
import { FlagButton } from "./flag-button";

import * as styles from "./body.module.scss";

interface IPostBodyProps
  extends Pick<
    IPostOverviewProps,
    "post" | "videos" | "attachments" | "previews" | "archives_enabled"
  > {
  flagged?: 0;
}

const formattedServices = ["fantia", "onlyfans", "fansly", "candfans"];

export function PostBody({
  post,
  attachments,
  previews,
  videos,
  archives_enabled,
  flagged,
}: IPostBodyProps) {
  const { incomplete_rewards, poll, content, service, user, id } = post;
  const postBodyRef = useRef<HTMLDivElement>(null);

  useEffect(
    () => {
      const bodyElement = postBodyRef.current;

      if (!bodyElement) {
        return;
      }

      cleanupBody(bodyElement, service);
    },
    // rerun it on post change
    [id, user, service]
  );

  return (
    <div ref={postBodyRef} className="post__body">
      <MiddleAd />

      {post.service === "dlsite" && attachments && attachments.length > 1 && (
        <p className="subtitle">
          This DLsite post was received as a split set of multiple files due to
          file size. Download all the files, then open the .exe file to compile
          them into a single one.
        </p>
      )}

      {videos && videos.length !== 0 && (
        <>
          <h2>Videos</h2>
          <script
            // yikes
            dangerouslySetInnerHTML={{
              __html: `window.videoAds = ${VIDEO_AD}`,
            }}
          ></script>
          <ul style={{ textAlign: "center", listStyleType: "none" }}>
            {videos.map((video) => (
              <PostVideo
                key={`${post.user}${post.id}${video.index}${video.path}`}
                video={video}
              />
            ))}
          </ul>
        </>
      )}

      {attachments && attachments.length !== 0 && (
        <>
          <h2>Downloads</h2>
          <ul className="post__attachments">
            {attachments.map((attachment, index) => (
              <PostAttachment
                key={index}
                attachment={attachment}
                archives_enabled={archives_enabled}
              />
            ))}
          </ul>
        </>
      )}

      {incomplete_rewards && (
        <div className="post__warning" style={{ color: "red" }}>
          <pre>{incomplete_rewards}</pre>
        </div>
      )}

      {poll && <PostPoll poll={poll} />}

      {content && (
        <>
          <h2>Content</h2>
          {/* TODO: rewrite without this */}
          <div className="post__content">
            <pre
              className={styles.content}
              dangerouslySetInnerHTML={{ __html: content }}
            ></pre>
          </div>
        </>
      )}

      {previews && <PostPreviews previews={previews} />}
    </div>
  );
}

interface IPostAttachmentProps
  extends Pick<IPostOverviewProps, "archives_enabled"> {
  attachment: IPostAttachment;
}

const archiveFileExtension = [".zip", ".rar", ".7z"];

function PostAttachment({
  attachment,
  archives_enabled,
}: IPostAttachmentProps) {
  const { name, path, server, extension, name_extension, stem } = attachment;
  const isArchiveFile = Boolean(
    archives_enabled &&
      (archiveFileExtension.includes(extension) ||
        archiveFileExtension.includes(name_extension))
  );

  return (
    <li className="post__attachment">
      <a
        className="post__attachment-link"
        href={String(createAttachmentURL(path, name, server))}
        download={name}
      >
        Download {name}
      </a>
      {isArchiveFile && (
        <>
          {/* TODO: a proper URL function */}(
          <a href={`/posts/archives/${stem}`}>browse »</a>)
        </>
      )}
    </li>
  );
}

interface IPostPollProps {
  poll: IPostPoll;
}

function PostPoll({ poll }: IPostPollProps) {
  const {
    title,
    description,
    choices,
    total_votes,
    created_at,
    closes_at,
    allow_multiple,
  } = poll;

  return (
    <>
      <h2>Poll</h2>

      <article id="poll">
        <div id="poll-summary">
          <h3>{title}</h3>
          {!description ? undefined : <h4>{description}</h4>}
        </div>

        <ul>
          {choices.map((choice) => {
            const percentage = (choice.votes / (total_votes ?? 1)) * 100;

            return (
              <li title={`${percentage}%`}>
                <span className="choice-text">{choice.text}</span>
                <span className="choice-votes">{choice.votes}</span>
                <span
                  className="choice-fill"
                  style={{ width: `${percentage}%` }}
                ></span>
              </li>
            );
          })}
        </ul>

        <footer>
          <ul>
            <li id="start" title={created_at}>
              {created_at}
            </li>
            {closes_at && (
              <li id="end" title={closes_at}>
                —{closes_at}
              </li>
            )}

            {allow_multiple && (
              <>
                <span className="sep"></span>
                <li id="multiple-choice">multiple choice</li>
              </>
            )}

            <span className="sep"></span>
            <li id="vote-count">{total_votes} votes</li>
          </ul>
        </footer>
      </article>
      <span style={{ display: "none" }}>{String(poll)}</span>
    </>
  );
}

interface IPostPreviewsProps
  extends Pick<Required<IPostOverviewProps>, "previews"> {}

function PostPreviews({ previews }: IPostPreviewsProps) {
  return (
    <>
      <h2>Files</h2>
      <div className="post__files">
        {previews.map((preview, index) =>
          preview.type === "thumbnail" ? (
            <PreviewThumbnail
              key={`${index}-${preview.name}`}
              preview={preview}
            />
          ) : (
            <PreviewEmbed key={`${index}-${preview.url}`} preview={preview} />
          )
        )}
      </div>
    </>
  );
}

interface IPreviewThumbnailProps {
  preview: IPreviewThumbnail;
}

function PreviewThumbnail({ preview }: IPreviewThumbnailProps) {
  const [isExpanded, switchExpansion] = useState(false);
  const { server, path, name, caption } = preview;
  const url = String(createPreviewURL(path, name, server));
  const downloadName = encodeURIComponent(name);
  const thumbnailRef = useRef<HTMLDivElement>(null);

  return (
    <div ref={thumbnailRef} className="post__thumbnail">
      <figure>
        {!isExpanded ? (
          <a
            className="fileThumb image-link"
            href={url}
            download={downloadName}
            // this is gigatrash
            onClick={(event) => {
              const thumbnailElement = thumbnailRef.current;

              if (!thumbnailElement) {
                return;
              }

              event.preventDefault();
              switchExpansion(true);

              setTimeout(() => {
                // I fucking love trashy DOM getters/setters
                thumbnailElement.scrollTop = 0;
              }, 50);
            }}
          >
            {/* TODO: move backup image logic to the script */}
            <img
              data-src={`${THUMBNAILS_PREPEND}/thumbnail/data${path}`}
              src={`${THUMBNAILS_PREPEND}/thumbnail/data${path}`}
              loading="lazy"
            />
          </a>
        ) : (
          <div className={styles.expanded}>
            <img src={url} alt="" />
          </div>
        )}

        {caption && <figcaption>{caption}</figcaption>}
      </figure>
    </div>
  );
}

interface IPreviewEmbedProps {
  preview: IPreviewEmbed;
}

function PreviewEmbed({ preview }: IPreviewEmbedProps) {
  const { url, description, subject } = preview;

  return (
    <a href={url} target="_blank">
      <div className="embed-view">
        <h3 className={subject ? undefined : "subtitle"}>
          {!subject ? "(No title)" : subject}
        </h3>
        {description && <p>{description}</p>}
      </div>
    </a>
  );
}

interface IActionsProps {
  service: string;
  profileID: string;
  postID: string;
  flagged?: 0;
}
