---
interface SchemaNode {
  [key: string]: unknown;
}

interface Props {
  title: string;
  description: string;
  type?: 'website' | 'article';
  image?: string;
  keywords?: string[];
  noindex?: boolean;
  articlePublishedTime?: string;
  articleModifiedTime?: string;
  articleTags?: string[];
  schema?: SchemaNode | SchemaNode[];
}

const siteUrl = 'https://kiln3d.com';
const siteName = 'Kiln';
const defaultImage = '/assets/kiln-social-preview.png';
const defaultKeywords = [
  'Kiln',
  'Kiln 3D',
  '3D printing',
  'AI 3D printing',
  'MCP server',
  'model context protocol',
  '3D printer tools for AI',
  'ai infrastructure for 3d printing',
];

const {
  title,
  description,
  type = 'website',
  image = defaultImage,
  keywords = [],
  noindex = false,
  articlePublishedTime,
  articleModifiedTime,
  articleTags = [],
  schema,
} = Astro.props as Props;

const canonicalUrl = new URL(Astro.url.pathname, siteUrl).toString();
const ogImage = image.startsWith('http') ? image : new URL(image, siteUrl).toString();
const mergedKeywords = Array.from(new Set([...defaultKeywords, ...keywords]));
const robotsContent = noindex
  ? 'noindex, nofollow'
  : 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1';

const graph: SchemaNode[] = [
  {
    '@type': 'WebSite',
    '@id': `${siteUrl}/#website`,
    name: siteName,
    alternateName: ['Kiln 3D', 'kiln3d'],
    url: siteUrl,
    inLanguage: 'en-US',
    publisher: { '@id': `${siteUrl}/#organization` },
  },
  {
    '@type': 'Organization',
    '@id': `${siteUrl}/#organization`,
    name: siteName,
    url: siteUrl,
    logo: {
      '@type': 'ImageObject',
      url: `${siteUrl}/assets/kiln-logo-dark-notext.svg`,
    },
    sameAs: [
      'https://github.com/codeofaxel/Kiln',
      'https://twitter.com/kiln3d',
    ],
  },
  {
    '@type': 'SoftwareApplication',
    '@id': `${siteUrl}/#software`,
    name: siteName,
    alternateName: ['Kiln 3D', 'kiln3d'],
    applicationCategory: 'DeveloperApplication',
    applicationSubCategory: 'Developer Infrastructure',
    operatingSystem: 'Linux, macOS, Windows',
    offers: {
      '@type': 'Offer',
      price: '0',
      priceCurrency: 'USD',
    },
    description:
      'Open-source MCP server and CLI that gives AI agents safe access to 3D printers, fleet management, and print workflows.',
    url: siteUrl,
    downloadUrl: 'https://pypi.org/project/kiln3d/',
    license: 'https://github.com/codeofaxel/Kiln/blob/main/LICENSE',
    codeRepository: 'https://github.com/codeofaxel/Kiln',
    programmingLanguage: 'Python',
    keywords: mergedKeywords.join(', '),
    author: { '@id': `${siteUrl}/#organization` },
  },
  {
    '@type': 'WebPage',
    '@id': `${canonicalUrl}#webpage`,
    url: canonicalUrl,
    name: title,
    description,
    inLanguage: 'en-US',
    isPartOf: { '@id': `${siteUrl}/#website` },
    about: { '@id': `${siteUrl}/#software` },
  },
];

if (type === 'article') {
  graph.push({
    '@type': 'BlogPosting',
    '@id': `${canonicalUrl}#article`,
    headline: title,
    description,
    image: ogImage,
    ...(articlePublishedTime ? { datePublished: articlePublishedTime } : {}),
    ...(articleModifiedTime || articlePublishedTime
      ? { dateModified: articleModifiedTime ?? articlePublishedTime }
      : {}),
    mainEntityOfPage: { '@id': `${canonicalUrl}#webpage` },
    author: { '@id': `${siteUrl}/#organization` },
    publisher: { '@id': `${siteUrl}/#organization` },
    ...(articleTags.length > 0 ? { keywords: articleTags.join(', ') } : {}),
  });
}

const extraSchemas = Array.isArray(schema) ? schema : schema ? [schema] : [];
for (const entry of extraSchemas) {
  const normalized: SchemaNode = { ...entry };
  delete normalized['@context'];
  graph.push(normalized);
}

const structuredData = JSON.stringify({
  '@context': 'https://schema.org',
  '@graph': graph,
});
---

<title>{title}</title>
<meta name="description" content={description}>
<meta name="keywords" content={mergedKeywords.join(', ')}>
<meta name="author" content="Kiln Contributors">
<meta name="robots" content={robotsContent}>
<meta name="googlebot" content={robotsContent}>
<meta name="application-name" content="Kiln">
<meta name="apple-mobile-web-app-title" content="Kiln">
<meta name="theme-color" content="#ff6b2b">

<link rel="canonical" href={canonicalUrl}>
<link rel="alternate" hreflang="en-US" href={canonicalUrl}>
<link rel="alternate" hreflang="x-default" href={canonicalUrl}>

<meta property="og:type" content={type}>
<meta property="og:site_name" content={siteName}>
<meta property="og:locale" content="en_US">
<meta property="og:title" content={title}>
<meta property="og:description" content={description}>
<meta property="og:image" content={ogImage}>
<meta property="og:url" content={canonicalUrl}>

<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@kiln3d">
<meta name="twitter:creator" content="@kiln3d">
<meta name="twitter:title" content={title}>
<meta name="twitter:description" content={description}>
<meta name="twitter:image" content={ogImage}>

{type === 'article' && articlePublishedTime && (
  <meta property="article:published_time" content={articlePublishedTime} />
)}
{type === 'article' && articleModifiedTime && (
  <meta property="article:modified_time" content={articleModifiedTime} />
)}
{type === 'article' &&
  articleTags.map((tag) => <meta property="article:tag" content={tag} />)}

<script type="application/ld+json" set:html={structuredData} />
