const SITE_NAME = 'The Meme Protocol';
const SITE_DESCRIPTION = 'A live, moderated meme stream for The Meme Protocol: WebP memes, MEME_CONSENSUS_SCORE ranking, and community review.';
const REPO_URL = 'https://git.yoonect.com/Nautilus/bitsforfree';
const SOCIAL_IMAGE_PATH = '/assets/social-preview-v2.78d008df9860.jpg';
const NOT_FOUND_IMAGE_PATH = '/assets/homo-reseticus-404-828.68be2119.webp';
const FAVICON_PATH = '/assets/favicon';
const FAVICON_VERSION = '20260814';

export function publicBaseUrl(req) {
  if (process.env.SITE_URL) return cleanBase(process.env.SITE_URL);
  const host = process.env.TRUST_PROXY === 'true'
    ? req.headers['x-forwarded-host'] || req.headers.host
    : req.headers.host;
  const proto = process.env.TRUST_PROXY === 'true'
    ? req.headers['x-forwarded-proto'] || 'https'
    : 'http';
  return cleanBase(`${proto}://${host || 'localhost:8080'}`);
}

export function renderIndex({ template, baseUrl, nonce, approvedCount, meme = null, lore = false }) {
  const home = `${baseUrl}/`;
  const canonical = meme ? `${baseUrl}/meme/${meme.id}` : lore ? `${baseUrl}/lore` : home;
  const image = meme ? `${baseUrl}/media/${meme.id}` : `${baseUrl}${SOCIAL_IMAGE_PATH}`;
  const imageType = meme ? meme.mime : 'image/jpeg';
  const imageWidth = meme ? meme.width : 1200;
  const imageHeight = meme ? meme.height : 630;
  const imageAlt = meme ? `Meme ${shortId(meme.id)}` : `${SITE_NAME} — memes bring us together`;
  const title = meme ? `Meme ${shortId(meme.id)} | ${SITE_NAME}` : lore ? `Lore | ${SITE_NAME}` : SITE_NAME;
  const description = meme
    ? `View and share meme ${shortId(meme.id)} on ${SITE_NAME}.`
    : lore
      ? `Read, copy, download, and share the lore of ${SITE_NAME}.`
      : SITE_DESCRIPTION;
  const pageMetadata = meme
    ? {
        '@type': 'ImageObject',
        '@id': `${canonical}#meme`,
        name: `Meme ${shortId(meme.id)}`,
        contentUrl: image,
        url: canonical,
        uploadDate: meme.createdAt,
        width: meme.width,
        height: meme.height,
        isPartOf: { '@id': `${home}#website` }
      }
    : lore
      ? {
          '@type': 'CreativeWork',
          '@id': `${canonical}#lore`,
          name: `${SITE_NAME} Lore`,
          url: canonical,
          description,
          encoding: {
            '@type': 'MediaObject',
            contentUrl: `${baseUrl}/assets/meme-protocol-lore.txt`,
            encodingFormat: 'text/plain'
          },
          isPartOf: { '@id': `${home}#website` }
        }
    : {
        '@type': 'CollectionPage',
        '@id': `${canonical}#collection`,
        name: SITE_NAME,
        url: canonical,
        description: SITE_DESCRIPTION,
        isPartOf: { '@id': `${home}#website` },
        about: ['memes', 'internet culture', 'image gallery', 'community moderation'],
        numberOfItems: approvedCount
      };
  const jsonLd = {
    '@context': 'https://schema.org',
    '@graph': [
      {
        '@type': 'WebSite',
        '@id': `${home}#website`,
        name: SITE_NAME,
        url: home,
        description: SITE_DESCRIPTION,
        inLanguage: 'en'
      },
      pageMetadata,
      {
        '@type': 'SoftwareApplication',
        name: SITE_NAME,
        applicationCategory: 'MultimediaApplication',
        operatingSystem: 'Web',
        url: home,
        codeRepository: REPO_URL,
        offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' }
      }
    ]
  };

  return template
    .replaceAll('__SEO_TITLE__', escapeHtml(title))
    .replaceAll('__SEO_DESCRIPTION__', escapeHtml(description))
    .replaceAll('__SEO_CANONICAL__', canonical)
    .replaceAll('__SEO_IMAGE__', image)
    .replaceAll('__SEO_IMAGE_TYPE__', imageType)
    .replaceAll('__SEO_IMAGE_WIDTH__', String(imageWidth))
    .replaceAll('__SEO_IMAGE_HEIGHT__', String(imageHeight))
    .replaceAll('__SEO_IMAGE_ALT__', escapeHtml(imageAlt))
    .replaceAll('__SEO_JSON_LD__', escapeJsonScript(JSON.stringify(jsonLd)))
    .replaceAll('__CSP_NONCE__', nonce);
}

export function renderNotFound({ template, baseUrl, pathname }) {
  const title = `404 | ${SITE_NAME}`;
  const description = 'The requested Meme Protocol node could not be found.';
  const pageUrl = new URL(pathname, `${baseUrl}/`).href;
  const image = `${baseUrl}${NOT_FOUND_IMAGE_PATH}`;
  const imageAlt = 'Homo Reseticus surrounded by an unreachable node pattern';

  return template
    .replaceAll('__SEO_TITLE__', escapeHtml(title))
    .replaceAll('__SEO_DESCRIPTION__', escapeHtml(description))
    .replaceAll('__SEO_URL__', escapeHtml(pageUrl))
    .replaceAll('__SEO_IMAGE__', escapeHtml(image))
    .replaceAll('__SEO_IMAGE_ALT__', escapeHtml(imageAlt));
}

export function robotsTxt(baseUrl) {
  return [
    'User-agent: *',
    'Allow: /',
    'Disallow: /admin/',
    'Disallow: /admin-media/',
    'Disallow: /api/',
    'Disallow: /download/',
    '',
    `Sitemap: ${baseUrl}/sitemap.xml`,
    ''
  ].join('\n');
}

export function llmsTxt(baseUrl) {
  return [
    '# The Meme Protocol',
    '',
    '> A live, moderated meme gallery. Uploads are PNG/JPEG inputs normalized to metadata-stripped WebP, scored with MEME_CONSENSUS_SCORE, and published only after AI or admin approval.',
    '',
    'Important URLs:',
    `- Site: ${baseUrl}/`,
    `- OpenAPI: ${baseUrl}/openapi.json`,
    `- API skill: ${baseUrl}/meme-api.skill.md`,
    `- JSON feed: ${baseUrl}/feed.json`,
    `- Sitemap: ${baseUrl}/sitemap.xml`,
    `- Lore: ${baseUrl}/lore`,
    `- Source: ${REPO_URL}`,
    '',
    'Crawler guidance:',
    '- Public approved meme images are available under /media/<sha256>.',
    '- Public API clients should use /openapi.json and /meme-api.skill.md before calling API routes.',
    '- Admin, review, upload, and API mutation routes are not public knowledge sources.',
    '- The site is intentionally visual and sparse; use metadata, sitemap URLs, and JSON feed for machine summaries.',
    ''
  ].join('\n');
}

export function manifest(baseUrl) {
  return {
    name: SITE_NAME,
    short_name: 'Meme Protocol',
    description: SITE_DESCRIPTION,
    start_url: '/',
    scope: '/',
    display: 'standalone',
    background_color: '#050505',
    theme_color: '#00ff41',
    icons: [
      {
        src: `${baseUrl}${FAVICON_PATH}/web-app-manifest-192x192.png?v=${FAVICON_VERSION}`,
        sizes: '192x192',
        type: 'image/png',
        purpose: 'maskable'
      },
      {
        src: `${baseUrl}${FAVICON_PATH}/web-app-manifest-512x512.png?v=${FAVICON_VERSION}`,
        sizes: '512x512',
        type: 'image/png',
        purpose: 'maskable'
      }
    ]
  };
}

export function feedJson(baseUrl, memes) {
  return {
    version: 'https://jsonfeed.org/version/1.1',
    title: SITE_NAME,
    home_page_url: `${baseUrl}/`,
    feed_url: `${baseUrl}/feed.json`,
    description: SITE_DESCRIPTION,
    items: memes.slice(0, 50).map((meme) => ({
      id: meme.id,
      url: `${baseUrl}/meme/${meme.id}`,
      image: `${baseUrl}/media/${meme.id}`,
      title: `Meme ${shortId(meme.id)}`,
      content_text: `Approved meme with MEME_CONSENSUS_SCORE ${meme.moderationScore}/100.`,
      date_published: meme.createdAt
    }))
  };
}

export function sitemapXml(baseUrl, memes) {
  const latest = memes[0]?.createdAt || new Date().toISOString();
  const urls = [
    [
      '  <url>',
      `    <loc>${xmlEscape(`${baseUrl}/`)}</loc>`,
      `    <lastmod>${xmlEscape(latest)}</lastmod>`,
      '  </url>'
    ].join('\n'),
    [
      '  <url>',
      `    <loc>${xmlEscape(`${baseUrl}/lore`)}</loc>`,
      `    <lastmod>${xmlEscape(latest)}</lastmod>`,
      '  </url>'
    ].join('\n'),
    ...memes.slice(0, 1000).map((meme) => [
      '  <url>',
      `    <loc>${xmlEscape(`${baseUrl}/meme/${meme.id}`)}</loc>`,
      `    <lastmod>${xmlEscape(meme.createdAt)}</lastmod>`,
      '  </url>'
    ].join('\n'))
  ].join('\n');

  return [
    '<?xml version="1.0" encoding="UTF-8"?>',
    '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
    urls,
    '</urlset>',
    ''
  ].join('\n');
}

export function noIndex(res) {
  res.setHeader('X-Robots-Tag', 'noindex, nofollow, noarchive');
}

function cleanBase(value) {
  return String(value).replace(/\/+$/, '');
}

function shortId(id) {
  return `0x${id.slice(0, 4).toUpperCase()}...${id.slice(-4).toUpperCase()}`;
}

function escapeHtml(value) {
  return String(value)
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;');
}

function xmlEscape(value) {
  return escapeHtml(value).replaceAll("'", '&apos;');
}

function escapeJsonScript(value) {
  return value.replaceAll('<', '\\u003c').replaceAll('>', '\\u003e').replaceAll('&', '\\u0026');
}
