import truncateHtml from "truncate-html";
import { convert } from "html-to-text";
import { parseCountryField } from "./countries.js";
import { formatDate, md } from "./formatters.js";
import { ICON_MAP } from "./icons.js";

const warningBanner = `<div class="banner warning"><p>${ICON_MAP["alertTriangle"]}There are probably spoilers after this banner — this is a warning about them.</p></div>`;

const generateAssociatedMediaHTML = (data, isGenre = false) => {
  const sections = [
    {
      key: "artists",
      icon: "headphones",
      category: "music",
      title: "Related Artist(s)",
    },
    {
      key: "related_artists",
      icon: "headphones",
      category: "music",
      title: "Related Artist(s)",
    },
    {
      key: "genres",
      icon: "headphones",
      category: "music",
      title: "Related Genre(s)",
    },
    {
      key: "movies",
      icon: "film",
      category: "movies",
      title: "Related Movie(s)",
    },
    {
      key: "shows",
      icon: "deviceTvOld",
      category: "tv",
      title: "Related Show(s)",
    },
    {
      key: "related_shows",
      icon: "deviceTvOld",
      category: "tv",
      title: "Related Show(s)",
    },
    {
      key: "posts",
      icon: "article",
      category: "article",
      title: "Related Post(s)",
    },
    {
      key: "books",
      icon: "books",
      category: "books",
      title: "Related Book(s)",
    },
    {
      key: "related_books",
      icon: "books",
      category: "books",
      title: "Related Book(s)",
    },
  ];

  return sections
    .filter(({ key }) => !(isGenre && key === "artists"))
    .map(({ key, category, icon, title }) => {
      const items = data[key];
      if (!items || items.length === 0) return "";

      return `
        <div class="associated-media">
          <p class="${category}">${ICON_MAP[icon]} ${title}</p>
          <ul>
            ${items
              .map((item) => {
                const name = item.name || item.title;
                const url = item.url;
                const year = item.year ? ` (${item.year})` : "";
                const author = item.author ? ` by ${item.author}` : "";
                const totalPlays = item.total_plays
                  ? ` <strong class="highlight-text">${item.total_plays} ${
                      item.total_plays === 1 ? "play" : "plays"
                    }</strong>`
                  : "";

                let listItemContent = name;

                if (key === "artists" || key === "related_artists") {
                  return `<li><a href="${url}">${name}</a>${totalPlays}</li>`;
                } else if (
                  key === "movies" ||
                  key === "shows" ||
                  key === "related_shows"
                ) {
                  listItemContent = `${name}${year}`;
                } else if (key === "books" || key === "related_books") {
                  listItemContent = `${name}${author}`;
                }

                return `<li><a href="${url}">${listItemContent}</a></li>`;
              })
              .join("")}
          </ul>
        </div>`;
    })
    .join("");
};

const generateMediaLinks = (data, type, count = 10) => {
  if (!data || !type) return "";

  const dataSlice = data.slice(0, count);
  if (dataSlice.length === 0) return null;

  const buildLink = (item) => {
    switch (type) {
      case "genre":
        return `<a href="${item["genre_url"]}">${item["genre_name"]}</a>`;
      case "artist":
        return `<a href="${item["url"]}">${item["name"]}</a>`;
      case "book":
        return `<a href="${item["url"]}">${item["title"]}</a>`;
      default:
        return "";
    }
  };

  if (dataSlice.length === 1) return buildLink(dataSlice[0]);

  const links = dataSlice.map(buildLink);
  const allButLast = links.slice(0, -1).join(", ");
  const last = links[links.length - 1];

  return `${allButLast} and ${last}`;
};

export const generateArtistHTML = (artist, globals) => {
  const playLabel = artist?.["total_plays"] === 1 ? "play" : "plays";
  const concertsList = artist["concerts"]?.length
    ? `<hr />
    <p id="concerts" class="concerts">
      ${ICON_MAP["deviceSpeaker"]}
      I've seen this artist live!
    </p>
    <ul>${artist["concerts"].map(generateConcertModal).join("")}</ul>`
    : "";
  const albumsTable = artist["albums"]?.length
    ? `<table>
        <tr><th>Album</th><th>Plays</th><th>Year</th></tr>
        ${artist["albums"]
          .map(
            (album) => `
          <tr>
            <td>${album["name"]}</td>
            <td>${album["total_plays"] || 0}</td>
            <td>${album["release_year"]}</td>
          </tr>`
          )
          .join("")}
      </table>
      <p><em>These are the albums by this artist that are in my collection, not necessarily a comprehensive discography.</em></p>
      `
    : "";

  return `
    <a class="icon-link" href="/music">${ICON_MAP.arrowLeft} Back to music</a>
    <article class="artist-focus">
      <div class="artist-display">
        <img
          srcset="
            ${globals["cdn_url"]}${artist["image"]}?class=w200&type=webp 200w,
            ${globals["cdn_url"]}${artist["image"]}?class=w600&type=webp 400w,
            ${globals["cdn_url"]}${artist["image"]}?class=w800&type=webp 800w
          "
          sizes="(max-width: 450px) 200px,
            (max-width: 850px) 400px,
            800px"
          src="${globals["cdn_url"]}${artist["image"]}?class=w200&type=webp"
          alt="${artist["name"]} / ${artist["country"]}"
          loading="eager"
          decoding="async"
          width="200"
          height="200"
        />
        <div class="artist-meta">
          <p class="title"><strong>${artist["name"]}</strong></p>
          <p class="sub-meta country">${ICON_MAP["mapPin"]} ${parseCountryField(
    artist["country"]
  )}</p>
          ${
            artist["favorite"]
              ? `<p class="sub-meta favorite">${ICON_MAP["heart"]} This is one of my favorite artists!</p>`
              : ""
          }
          ${
            artist["tattoo"]
              ? `<p class="sub-meta tattoo">${ICON_MAP["needle"]} I have a tattoo inspired by this artist!</p>`
              : ""
          }
          ${
            artist["total_plays"]
              ? `<p class="sub-meta"><strong class="highlight-text">${artist["total_plays"]} ${playLabel}</strong></p>`
              : ""
          }
          <p class="sub-meta">${
            artist["genre"]
              ? `<a href="${artist["genre"]["url"]}">${artist["genre"]["name"]}</a>`
              : ""
          }</p>
        </div>
      </div>
      ${generateAssociatedMediaHTML(artist)}
      ${
        artist["description"]
          ? `
        <h2>Overview</h2>
        <div data-toggle-content class="text-toggle-hidden">${md.render(
          artist["description"]
        )}</div>
        <button data-toggle-button>Show more</button>`
          : ""
      }
      ${concertsList}
      ${albumsTable}
    </article>
  `;
};

export const generateBookHTML = (book, globals) => {
  const alt = `${book["title"]}${
    book["author"] ? ` by ${book["author"]}` : ""
  }`;
  const percentage = book["progress"] ? `${book["progress"]}%` : "";
  const status =
    book["status"] === "finished"
      ? `Finished on <strong class="highlight-text">${formatDate(
          book["date_finished"]
        )}</strong>`
      : percentage
      ? `<div class="progress-bar-wrapper" title="${percentage}">
        <div style="width:${percentage}" class="progress-bar"></div>
      </div>`
      : "";

  return `
    <a class="icon-link" href="/books">${
      ICON_MAP["arrowLeft"]
    } Back to books</a>
    <article class="book-focus">
      <div class="book-display">
        <img
          srcset="
            ${globals["cdn_url"]}${
    book["image"]
  }?class=verticalsm&type=webp 200w,
            ${globals["cdn_url"]}${
    book["image"]
  }?class=verticalmd&type=webp 400w,
            ${globals["cdn_url"]}${
    book["image"]
  }?class=verticalbase&type=webp 800w
          "
          sizes="(max-width: 450px) 203px, (max-width: 850px) 406px, 812px"
          src="${globals["cdn_url"]}${book["image"]}?class=verticalsm&type=webp"
          alt="${alt}"
          loading="lazy"
          decoding="async"
          width="200"
          height="307"
        />
        <div class="book-meta">
          <p class="title"><strong>${book["title"]}</strong></p>
          ${book["rating"] ? `<p>${book["rating"]}</p>` : ""}
          ${
            book["author"] ? `<p class="sub-meta">By ${book["author"]}</p>` : ""
          }
          ${
            book["favorite"]
              ? `<p class="sub-meta favorite">${ICON_MAP["heart"]} This is one of my favorite books!</p>`
              : ""
          }
          ${
            book["tattoo"]
              ? `<p class="sub-meta tattoo">${ICON_MAP["needle"]} I have a tattoo inspired by this book!</p>`
              : ""
          }
          ${status ? `<p class="sub-meta">${status}</p>` : ""}
        </div>
      </div>
      ${
        book["review"]
          ? `${warningBanner}<h2>My thoughts</h2><p>${book["review"]}</p>`
          : ""
      }
      ${generateAssociatedMediaHTML(book)}
      <h2>Overview</h2>
      <p>${md.render(book["description"])}</p>
    </article>
  `;
};

export const generateGenreHTML = (genre) => {
  const artistCount = genre["artists"]?.length || 0;
  const connectingWords = artistCount > 1 ? "artists are" : "artist is";
  const mediaLinks = generateMediaLinks(genre["artists"], "artist", 5);

  return `
    <a class="icon-link" href="/music">${
      ICON_MAP["arrowLeft"]
    } Back to music</a>
    <h2>${genre["name"]}</h2>
    <article class="genre-focus">
      ${
        mediaLinks
          ? `
        <p>My top <strong class="highlight-text">${genre["name"]}</strong> ${connectingWords} ${mediaLinks}. I've listened to <strong class="highlight-text">${genre["total_plays"]}</strong> tracks from this genre.</p>
        <hr />`
          : ""
      }
      ${generateAssociatedMediaHTML(genre, true)}
      ${
        genre["description"]
          ? `
        <h3>Overview</h3>
        <div data-toggle-content class="text-toggle-hidden">
          ${md.render(genre["description"])}
          <p><a href="${
            genre["wiki_link"]
          }">Continue reading at Wikipedia.</a></p>
          <p><em>Wikipedia content provided under the terms of the <a href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons BY-SA license</a>.</em></p>
        </div>
        <button data-toggle-button>Show more</button>`
          : ""
      }
    </article>
  `;
};

export const generateMetadata = (data, type, globals) => {
  let title = globals["site_name"];
  let description = data["description"] || globals["site_description"];
  const canonicalUrl = data["url"]
    ? `${globals["url"]}${data["url"]}`
    : globals["url"];
  const ogImage = `${globals["cdn_url"]}${
    data["image"] || globals["avatar"]
  }?class=w800`;

  description = convert(
    truncateHtml(md.render(description), 100, {
      byWords: true,
      ellipsis: "...",
    }),
    {
      wordwrap: false,
      selectors: [
        { selector: "a", options: { ignoreHref: true } },
        { selector: "h1", options: { uppercase: false } },
        { selector: "h2", options: { uppercase: false } },
        { selector: "h3", options: { uppercase: false } },
        { selector: "*", format: "block" },
      ],
    }
  )
    .replace(/\s+/g, " ")
    .trim();

  switch (type) {
    case "artist":
      title = `Artists / ${data["name"]} / ${globals["site_name"]}`;
      break;
    case "genre":
      title = `Genre / ${data["name"]} / ${globals["site_name"]}`;
      break;
    case "book":
      title = `Books / ${data["title"]} by ${data.author} / ${globals["site_name"]}`;
      break;
    case "movie":
      title = `Movies / ${data["title"]} (${data.year}) / ${globals["site_name"]}`;
      break;
    case "show":
      title = `Shows / ${data["title"]} / ${globals["site_name"]}`;
      break;
    default:
      title = `${data["title"] || globals["site_name"]}`;
  }

  return {
    title,
    description,
    "og:title": title,
    "og:description": description,
    "og:image": ogImage,
    "og:url": canonicalUrl,
    canonical: canonicalUrl,
  };
};

export const generateWatchingHTML = (media, globals, type) => {
  const isShow = type === "show";
  const label = isShow ? "show" : "movie";
  const lastWatched =
    media["last_watched"] || (isShow && media["episode"]?.["last_watched_at"]);

  return `
    <a class="icon-link" href="/watching">${
      ICON_MAP.arrowLeft
    } Back to watching</a>
    <article class="watching focus">
      <img
        srcset="
          ${globals["cdn_url"]}${
    media["backdrop"]
  }?class=bannersm&type=webp 256w,
          ${globals["cdn_url"]}${
    media["backdrop"]
  }?class=bannermd&type=webp 512w,
          ${globals["cdn_url"]}${
    media["backdrop"]
  }?class=bannerbase&type=webp 1024w
        "
        sizes="(max-width: 450px) 256px,
          (max-width: 850px) 512px,
          1024px"
        src="${globals["cdn_url"]}${media["backdrop"]}?class=bannersm&type=webp"
        alt="${media["title"]} / ${media["year"]}"
        class="image-banner"
        loading="eager"
        decoding="async"
        width="256"
        height="180"
      />
      <div class="meta">
        <p class="title"><strong>${media["title"]}</strong> (${
    media["year"]
  })</p>
        ${
          media["favorite"]
            ? `<p class="sub-meta favorite">${ICON_MAP["heart"]} This is one of my favorite ${label}s!</p>`
            : ""
        }
        ${
          media["tattoo"]
            ? `<p class="sub-meta tattoo">${ICON_MAP["needle"]} I have a tattoo inspired by this ${label}!</p>`
            : ""
        }
        ${
          media["collected"]
            ? `<p class="sub-meta collected">${ICON_MAP["circleCheck"]} This ${label} is in my collection!</p>`
            : ""
        }
        ${
          lastWatched
            ? `<p class="sub-meta">Last watched on <strong class="highlight-text">${formatDate(
                lastWatched
              )}</strong></p>`
            : ""
        }
      </div>
      ${
        media["review"]
          ? `${warningBanner}<h2>My thoughts</h2><p>${md.render(
              media["review"]
            )}</p>`
          : ""
      }
      ${generateAssociatedMediaHTML(media)}
      ${
        media["description"]
          ? `<h2>Overview</h2><p>${md.render(media["description"])}</p>`
          : ""
      }
    </article>
  `;
};

export const generateConcertModal = (concert) => {
  const venue = concert["venue_name"]
    ? concert["venue_latitude"] && concert["venue_longitude"]
      ? `<a href="https://www.openstreetmap.org/?mlat=${concert["venue_latitude"]}&mlon=${concert["venue_longitude"]}#map=18/${concert["venue_latitude"]}/${concert["venue_longitude"]}">${concert["venue_name_short"]}</a>`
      : concert["venue_name_short"]
    : "";

  const notesModal = concert["notes"]
    ? `<input class="modal-input" id="${
        concert["id"]
      }" type="checkbox" tabindex="0" />
      <label class="modal-toggle" for="${concert["id"]}">${
        ICON_MAP["infoCircle"]
      }</label>
      <div class="modal-wrapper">
        <div class="modal-body">
          <label class="modal-close" for="${concert["id"]}">${
        ICON_MAP["circleX"]
      }</label>
          <div>
            <h3>Notes</h3>
            ${md.render(concert["notes"])}
          </div>
        </div>
      </div>`
    : "";

  return `
    <li>
      <strong class="highlight-text">${formatDate(
        concert["date"]
      )}</strong> at ${venue}
      ${notesModal}
    </li>
  `;
};