import { type FC } from 'react';
import Head from 'next/head';

import type { ToStructuredDataExtra } from './toStructuredData';

import { FACEBOOK_PAGE_ID } from '~/lib/constants';
import i18nConfig, { DEFAULT_LANGUAGE } from '~/i18n.config';
import { toPublicEndpoint } from '~/src/lib/getPublicEndpoint';
import { useAppRouter } from '~/src/lib/router2';
import isExternalUrl from '~/src/lib/utils/isExternalUrl';
import { useSelector } from '~/src/store/redux';
import {
  selectSessionCustomDomain,
  selectSessionScope,
} from '~/src/store/session/selectors';
import safariMaskIcon from './images/safariMaskIcon.external.svg';
import songwhipFavicon from './images/songwhipFavicon.external.svg';
import toStructuredData from './toStructuredData';

const DEFAULT_IMAGE_URL = '/static/og-image-1200x630.jpg';
const { locales } = i18nConfig();

export interface PageMetadataProps {
  title?: string;
  imageUrl?: string;
  imageAlt?: string;
  ogType?: string;
  description?: string;
  canonicalPath?: string;
  /**
   * The URL to use in the og:url meta tag. If not provided, the canonical URL will be used.
   * This is useful for cases where the canonical URL is not the same as the URL in the address bar (eg. when using a custom domain or scoped app).
   */
  ogUrl?: string;
  titleSuffix?: string;
  facebookAppId?: string;
  facebookPageId?: string;
  twitterHandle?: string;
  nextPagePath?: string;
  prevPagePath?: string;
  toStructuredData?: ToStructuredDataExtra;
  safariMaskIconUrl?: string;
  faviconUrl?: string;
  error?: Error;
  noIndex?: boolean;
}

const PageMetadata: FC<PageMetadataProps> = ({
  error,
  title = '',
  imageUrl = DEFAULT_IMAGE_URL,
  imageAlt,
  ogType = 'website',
  description,
  canonicalPath,
  ogUrl,
  titleSuffix = null,
  facebookAppId = '620945261442606',
  facebookPageId = FACEBOOK_PAGE_ID,
  twitterHandle = '@songwhip',
  nextPagePath,
  prevPagePath,
  toStructuredData: toStructuredDataExtra,
  safariMaskIconUrl = safariMaskIcon.src,
  faviconUrl = songwhipFavicon.src,
  noIndex,
}) => {
  const router = useAppRouter();
  const asPath = router.getAsPath();
  const isScoped = !!useSelector(selectSessionScope);
  const isCustomDomain = !!useSelector(selectSessionCustomDomain);
  const withConicalUrl = !isScoped && !isCustomDomain;

  // fallback canonical path
  if (!canonicalPath) {
    canonicalPath = asPath;
  }

  // If the app is 'scoped' (ie. custom subdomain) don't include a canonical url
  // as the baseUrl may not actually be the url in the address bar. A canonical url
  // mismatch causes fb og metadata parser to treat this as a redirect and follows it.
  const canonicalUrl = withConicalUrl ? toPublicEndpoint(canonicalPath) : null;

  // consume app paths or external urls
  const imageUrlResolved = isExternalUrl(imageUrl)
    ? imageUrl
    : toPublicEndpoint(imageUrl);

  // if there's an error override the title
  let pageTitle = error ? 'Error' : title;
  if (titleSuffix) pageTitle += ` - ${titleSuffix}`;

  const url = ogUrl || canonicalUrl;

  // NOTE: <Head> only supports children of html tags (no react components)
  // https://github.com/zeit/next.js/issues/5888#issuecomment-449878754
  return (
    <Head>
      <title>{pageTitle}</title>
      {canonicalUrl && <link rel="canonical" href={canonicalUrl} />}
      {nextPagePath && <link rel="next" href={nextPagePath} />}
      {prevPagePath && <link rel="prev" href={prevPagePath} />}
      <meta name="description" content={description} />
      <meta property="og:type" content={ogType} />
      <meta property="og:site_name" content="Songwhip" />
      <meta property="og:title" content={title} />
      <meta property="og:description" content={description} />
      {url && <meta property="og:url" content={url} />}
      {imageUrlResolved && (
        <>
          <meta property="og:image" content={imageUrlResolved} />
          {imageAlt && <meta property="og:image:alt" content={imageAlt} />}
        </>
      )}
      <meta property="og:image:width" content="1200" />
      <meta property="og:image:height" content="630" />
      <meta property="fb:app_id" content={facebookAppId} />
      <meta property="fb:page_id" content={facebookPageId} />
      <meta name="twitter:card" content="summary_large_image" />
      <meta name="twitter:site" content={twitterHandle} />
      <meta name="twitter:title" content={title} />
      <meta name="twitter:description" content={description} />
      {imageUrlResolved && (
        <>
          <meta name="twitter:image" content={imageUrlResolved} />
          {imageAlt && <meta name="twitter:image:alt" content={imageAlt} />}
        </>
      )}
      {noIndex && <meta name="robots" content="noindex" />}
      <link
        rel="sitemap"
        type="application/xml"
        title="Sitemap"
        href="/sitemap.xml"
      />
      <link rel="icon" href={faviconUrl} />
      <link rel="mask-icon" href={safariMaskIconUrl} color="#fff" />
      {/* coil.com monetization experiment */}
      <meta name="monetization" content="$ilp.gatehub.net/673226609" />
      {/* canonicalPath can be undefined */}
      {canonicalUrl && (
        <>
          <link rel="alternate" hrefLang="x-default" href={canonicalUrl} />
          {/* tell crawlers there are localized versions of this page */}
          {locales
            .filter((locale) => locale !== DEFAULT_LANGUAGE)
            .map((locale) => (
              <link
                key={locale}
                rel="alternate"
                hrefLang={locale}
                href={`${canonicalUrl}?lang=${locale}`}
              />
            ))}
        </>
      )}
      {toStructuredData({
        title,
        description,
        imageUrl: imageUrlResolved,
        pagePath: canonicalPath || asPath,
        toStructuredDataExtra,
      })}
    </Head>
  );
};

export default PageMetadata;
