import { notFound } from 'next/navigation'
import type { Metadata } from 'next'
import BlogDetailClient from '@/components/frontend/blog/BlogDetailClient'
import JsonLd from '@/components/frontend/seo/JsonLd'
import { getBlogPostDetail, type BlogPostDetail } from '@/lib/db/queries/getBlogPosts'
import { getDefaultLanguage } from '@/lib/db/queries/getlanguages'
import { getSiteInfo } from '@/lib/db/queries/getSiteInfo'
import { buildLocalizedPath } from '@/lib/i18n/buildLocalizedPath'

interface BlogDetailPageProps {
  params: Promise<{ locale: string; slug: string }>
}

const APP_URL = (process.env.NEXT_PUBLIC_APP_URL ?? 'http://localhost:3000').replace(/\/$/, '')

// Same percent-encoding inconsistency already hit on the product detail
// page (this Next.js build's Page params can arrive still percent-encoded
// for a non-ASCII slug, while generateMetadata's don't) — idempotent guard.
function decodeSlug(slug: string): string {
  try {
    return decodeURIComponent(slug)
  } catch {
    return slug
  }
}

function buildAlternatePaths(post: BlogPostDetail, defaultLocale: string): Record<string, string> {
  const paths: Record<string, string> = {}
  for (const alt of post.alternateLocales) {
    paths[alt.locale] = buildLocalizedPath(alt.locale, defaultLocale, `/blog/${alt.slug}`)
  }
  return paths
}

export async function generateMetadata({ params }: BlogDetailPageProps): Promise<Metadata> {
  const { locale, slug } = await params
  const [post, defaultLanguage, siteInfo] = await Promise.all([
    getBlogPostDetail(decodeSlug(slug), locale),
    getDefaultLanguage(),
    getSiteInfo(),
  ])
  if (!post) return {}

  const defaultLocale = defaultLanguage?.code ?? 'en'
  const alternatePaths = buildAlternatePaths(post, defaultLocale)
  const canonicalPath = buildLocalizedPath(locale, defaultLocale, `/blog/${post.slug}`)

  const title = post.metaTitle || post.title
  const description =
    post.metaDescription ||
    post.excerpt ||
    (post.content ? post.content.replace(/<[^>]+>/g, '').slice(0, 160) : undefined)
  const keywords = post.metaKeywords
    ? post.metaKeywords.split(',').map((k) => k.trim()).filter(Boolean)
    : undefined
  const ogImages = post.imageUrl ? [{ url: post.imageUrl, alt: post.title }] : undefined

  return {
    title: `${title} | ${siteInfo.siteName}`,
    description,
    keywords,
    alternates: {
      canonical: `${APP_URL}${canonicalPath}`,
      languages: {
        ...Object.fromEntries(
          Object.entries(alternatePaths).map(([loc, path]) => [loc, `${APP_URL}${path}`]),
        ),
        'x-default': `${APP_URL}${alternatePaths[defaultLocale] ?? canonicalPath}`,
      },
    },
    openGraph: {
      title,
      description,
      siteName: siteInfo.siteName,
      url: `${APP_URL}${canonicalPath}`,
      images: ogImages,
      type: 'article',
      publishedTime: post.publishedAt,
    },
    twitter: {
      card: 'summary_large_image',
      title,
      description,
      images: ogImages?.map((img) => img.url),
    },
  }
}

// No per-post author/byline column exists on posts (see getBlogPosts.ts) —
// attributing the Article schema to the site itself (Organization) is the
// honest choice for a CMS-authored blog with no real byline data, not a
// fabricated person's name.
function buildArticleSchema(post: BlogPostDetail, canonicalUrl: string, siteName: string): Record<string, unknown> {
  return {
    '@context': 'https://schema.org',
    '@type': 'Article',
    headline: post.title,
    description: post.excerpt ?? undefined,
    image: post.imageUrl ? [post.imageUrl] : undefined,
    datePublished: post.publishedAt,
    dateModified: post.publishedAt,
    author: { '@type': 'Organization', name: siteName },
    publisher: { '@type': 'Organization', name: siteName },
    mainEntityOfPage: { '@type': 'WebPage', '@id': canonicalUrl },
  }
}

function buildBreadcrumbSchema(post: BlogPostDetail, siteUrl: string, canonicalUrl: string): Record<string, unknown> {
  const items = [
    { '@type': 'ListItem', position: 1, name: 'Home', item: siteUrl },
    { '@type': 'ListItem', position: 2, name: 'Blog', item: `${siteUrl}/blogs` },
  ]
  if (post.categoryName) {
    items.push({
      '@type': 'ListItem',
      position: items.length + 1,
      name: post.categoryName,
      item: `${siteUrl}/blogs?category=${post.categorySlug}`,
    })
  }
  items.push({ '@type': 'ListItem', position: items.length + 1, name: post.title, item: canonicalUrl })
  return { '@context': 'https://schema.org', '@type': 'BreadcrumbList', itemListElement: items }
}

// Server Component: post data (translation, category, related posts, SEO
// fields) comes from the locale-aware, ISR-cached getBlogPostDetail() — see
// DATA_FETCHING_PATTERN.md and src/lib/db/queries/getBlogPosts.ts.
// Interactivity (locale-alternate registration, share button) lives in
// BlogDetailClient.
export default async function BlogDetailPage({ params }: BlogDetailPageProps) {
  const { locale, slug } = await params
  const [post, defaultLanguage, siteInfo] = await Promise.all([
    getBlogPostDetail(decodeSlug(slug), locale),
    getDefaultLanguage(),
    getSiteInfo(),
  ])

  if (!post) notFound()

  const defaultLocale = defaultLanguage?.code ?? 'en'
  const alternatePaths = buildAlternatePaths(post, defaultLocale)
  const canonicalUrl = `${APP_URL}${buildLocalizedPath(locale, defaultLocale, `/blog/${post.slug}`)}`

  const schemas = [
    buildArticleSchema(post, canonicalUrl, siteInfo.siteName),
    buildBreadcrumbSchema(post, APP_URL, canonicalUrl),
    ...Object.values(post.schemas),
  ] as Record<string, unknown>[]

  return (
    <>
      <JsonLd data={schemas} />
      <BlogDetailClient post={post} alternatePaths={alternatePaths} defaultLocale={defaultLocale} />
    </>
  )
}
