import { cloneable } from "./helpers.ts/cloneable"
import { PageData } from "./models/TaprootPageRenderer"
import { Author, Publisher } from "./models/TaprootPluginOptions"

interface SocialImage {
  Url: string
  Width: number
  Height: number
  MediaType: string
}

interface HeadData extends Omit<PageData, "Author"> {
  Author?: Author
  CharSet?: string
  Locale?: string
  NoRobots?: boolean
  PageType?: string
  Publisher: Publisher
  SocialImage: SocialImage
}

// NOTE: Flash of unstyled content can happen when resources,
//       such as fonts and other styles, are loaded after
//       initial render. This waits for things to load before
//       showing the page. Template body needs an initial
//       class of "loading" for it to work.
const FUCFix = [
  `<style>
  body {
    transition: opacity ease-in 500ms;
  }
  body.loading {
    opacity: 0;
  }
  body.loading.loaded {
    opacity: 100;
  }
</style>`,
  `<script type="text/javascript">
  window.onload = () => {
    document.body.classList.add("loaded")
  }
</script>`,
]

const BuildHead = (data: HeadData): string => {
  if (!data.Canonical) {
    throw "No canonical specified"
  }

  // Clone it so any changes made here do not bubble up.
  data = cloneable.deepCopy(data)

  console.log(JSON.stringify(data))

  data.Canonical = data.Canonical?.replace("index.html", "")
  data.CharSet = data.CharSet ?? "UTF-8"
  data.Locale = data.Locale ?? "en_US"
  data.PageType = data.PageType?.toLowerCase() ?? "article"

  if (!data.Title) {
    throw `No title for ${data.Canonical}`
  }

  if (!data.Description) {
    throw `No description for ${data.Canonical}`
  }

  const validPageTypes = ["article", "website"]

  if (validPageTypes.indexOf(data.PageType) < 0) {
    throw `Invalid page type for ${data.Canonical}`
  }

  if (data.PageType == "article" && !data.Author) {
    throw `Article must have an author for ${data.Canonical}`
  }

  const tags = [
    `<meta charset="${data.CharSet}" />`,
    `<meta name="viewport" content="width=device-width, initial-scale=1" />`,
  ]

  if (!data.NoRobots) {
    tags.push(
      `<meta name="robots" content="index, follow, max-image-preview:large" />`
    )
  }

  tags.push(...FUCFix)

  tags.push(
    `<title>${data.Title} → ${data.Publisher.Name}</title>`,
    `<meta name="description" content="${data.Description}" />`,
    `<link rel="canonical" href="${data.Canonical}" />`,
    `<meta property="og:locale" content="${data.Locale}" />`,
    `<meta property="og:type" content="${data.PageType}" />`,
    `<meta property="og:title" content="${data.Title}" />`,
    `<meta property="og:description" content="${data.Description}" />`,
    `<meta property="og:url" content="${data.Canonical}" />`,
    `<meta property="og:site_name" content="${data.Publisher.Name}" />`,
    `<meta property="article:publisher" content="${data.Publisher.FacebookPage}" />`,
    `<meta property="og:image" content="${data.SocialImage.Url}" />`,
    `<meta property="og:image:width" content="${data.SocialImage.Width}" />`,
    `<meta property="og:image:height" content="${data.SocialImage.Height}" />`,
    `<meta property="og:image:type" content="${data.SocialImage.MediaType}" />`, // e.g. "image/png"
    `<meta name="twitter:card" content="summary_large_image" />`,
    `<meta name="twitter:site" content="${data.Publisher.TwitterHandle}" />`
  )

  if (data.DatePublished) {
    tags.push(
      `<meta property="article:published_time" content="${data.DatePublished}" />`
    )
  }

  if (data.DateModified) {
    tags.push(
      `<meta property="article:modified_time" content="${data.DateModified}" />`
    )
  }

  if (data.Author) {
    tags.push(
      `<meta property="article:author" content="${data.Author.FacebookPage}" />`,
      `<meta name="author" content="${data.Author.Name}" />`,
      `<meta name="twitter:creator" content="${data.Author.TwitterHandle}" />`,
      `<meta name="twitter:label1" content="Written by" />`,
      `<meta name="twitter:data1" content="${data.Author.Name}" />`
    )
  }

  return tags.join("\n")
}

export { BuildHead, type HeadData, type SocialImage }
