/**
 * Per-route document head.
 *
 * `scripts/prerender.mjs` bakes these tags into the static HTML at build time,
 * which is what crawlers and link unfurlers actually read. This hook exists for
 * the other half: a visitor who lands on `/` and clicks through to a demo never
 * fetches a new document, so without it the tab title and the canonical link
 * would still say "home" three pages later.
 *
 * Deliberately no cleanup. Restoring the previous head on unmount would mean
 * every navigation flickers back to the old title before the next route sets
 * its own; the next route always sets one, so the last writer simply wins.
 */

import { useEffect } from 'react';

export const SITE_ORIGIN = 'https://demo.primeintellectgrowth.com';
export const SITE_NAME = 'PIG Demo';

/** `Wordle-five — PIG Demo`. One place, so every tab reads the same shape. */
export function pageTitle(name?: string): string {
  return name && name.trim() !== '' ? `${name} — ${SITE_NAME}` : SITE_NAME;
}

/**
 * Absolutise a site-root path. Open Graph consumers do not resolve relative
 * URLs — a relative `og:image` is simply no image, silently, and you only find
 * out when someone pastes the link into Slack.
 */
export function absoluteUrl(pathOrUrl: string): string {
  if (/^https?:\/\//i.test(pathOrUrl)) return pathOrUrl;
  return `${SITE_ORIGIN}${pathOrUrl.startsWith('/') ? '' : '/'}${pathOrUrl}`;
}

export interface SeoInput {
  /** Used verbatim as `document.title`. Wrap with `pageTitle()` if you want the suffix. */
  title: string;
  description?: string;
  /** Site-root path or absolute URL. */
  canonical?: string;
  /** Site-root path or absolute URL. */
  ogImage?: string;
}

type MetaKey = { name: string } | { property: string };

function upsertMeta(key: MetaKey, content: string): void {
  const selector =
    'name' in key ? `meta[name="${key.name}"]` : `meta[property="${key.property}"]`;
  let tag = document.head.querySelector<HTMLMetaElement>(selector);
  if (!tag) {
    tag = document.createElement('meta');
    if ('name' in key) tag.setAttribute('name', key.name);
    else tag.setAttribute('property', key.property);
    document.head.appendChild(tag);
  }
  tag.setAttribute('content', content);
}

function upsertCanonical(href: string): void {
  let link = document.head.querySelector<HTMLLinkElement>('link[rel="canonical"]');
  if (!link) {
    link = document.createElement('link');
    link.setAttribute('rel', 'canonical');
    document.head.appendChild(link);
  }
  link.setAttribute('href', href);
}

export function applySeo(input: SeoInput): void {
  if (typeof document === 'undefined') return;

  document.title = input.title;
  upsertMeta({ property: 'og:title' }, input.title);
  upsertMeta({ name: 'twitter:title' }, input.title);

  if (input.description) {
    upsertMeta({ name: 'description' }, input.description);
    upsertMeta({ property: 'og:description' }, input.description);
    upsertMeta({ name: 'twitter:description' }, input.description);
  }

  if (input.canonical) {
    const href = absoluteUrl(input.canonical);
    upsertCanonical(href);
    upsertMeta({ property: 'og:url' }, href);
  }

  if (input.ogImage) {
    const href = absoluteUrl(input.ogImage);
    upsertMeta({ property: 'og:image' }, href);
    upsertMeta({ name: 'twitter:image' }, href);
  }
}

/**
 * Set the head for this route.
 *
 * Deps are the individual strings rather than the object, so a caller can pass
 * an inline literal without re-running this on every render.
 */
export function useSeo(input: SeoInput): void {
  const { title, description, canonical, ogImage } = input;
  useEffect(() => {
    applySeo({
      title,
      ...(description === undefined ? {} : { description }),
      ...(canonical === undefined ? {} : { canonical }),
      ...(ogImage === undefined ? {} : { ogImage }),
    });
  }, [title, description, canonical, ogImage]);
}
