import { notFound } from 'next/navigation'
import type { Metadata } from 'next'
import ProductDetailClient from '@/components/frontend/product/ProductDetailClient'
import JsonLd from '@/components/frontend/seo/JsonLd'
import { getProductDetail, type ProductDetail } from '@/lib/db/queries/getProductDetail'
import { getDefaultLanguage } from '@/lib/db/queries/getlanguages'
import { getSiteInfo } from '@/lib/db/queries/getSiteInfo'
import { getCurrencySettings } from '@/lib/db/queries/getCurrencySettings'
import { buildLocalizedPath } from '@/lib/i18n/buildLocalizedPath'

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

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

// The [slug] segment sometimes arrives still percent-encoded (seen on this
// Next.js build for non-ASCII slugs, e.g. Urdu/Arabic product names) and
// sometimes already decoded — decodeURIComponent() is idempotent on an
// already-decoded string with no literal '%', so this normalizes both.
function decodeSlug(slug: string): string {
  try {
    return decodeURIComponent(slug)
  } catch {
    return slug
  }
}

// locale -> full site-relative path, e.g. "/product/x" (default locale) or
// "/ur/product/y" — shared by hreflang alternates and, client-side, by
// LanguageSwitcher (see localeAlternatesStore.ts).
function buildAlternatePaths(product: ProductDetail, defaultLocale: string): Record<string, string> {
  const paths: Record<string, string> = {}
  for (const alt of product.alternateLocales) {
    paths[alt.locale] = buildLocalizedPath(alt.locale, defaultLocale, `/product/${alt.slug}`)
  }
  return paths
}

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

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

  const title = product.metaTitle || product.name
  const description =
    product.metaDescription ||
    product.shortDescription ||
    (product.description ? product.description.replace(/<[^>]+>/g, '').slice(0, 160) : undefined)
  const keywords = product.metaKeywords
    ? product.metaKeywords.split(',').map((k) => k.trim()).filter(Boolean)
    : undefined
  const primaryImage = product.images.find((img) => img.isPrimary) ?? product.images[0]
  const ogImages = primaryImage
    ? [{ url: primaryImage.url, alt: primaryImage.alt || product.name }]
    : 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: 'website',
    },
    twitter: {
      card: 'summary_large_image',
      title,
      description,
      images: ogImages?.map((img) => img.url),
    },
    robots: product.isIndexable
      ? { index: true, follow: true }
      : { index: false, follow: false },
  }
}

// Auto-generated Schema.org structured data from real product data — always
// rendered, so a product with no admin-entered schema still gets valid SEO
// markup. Any raw JSON-LD an admin entered via the product's SEO tab
// (SchemaEditor.tsx, product_schemas column) is rendered alongside this,
// additively, via <JsonLd> further down.
function buildProductSchema(
  product: ProductDetail,
  canonicalUrl: string,
  currencyCode: string,
): Record<string, unknown> {
  const availability =
    product.stockStatus === 'in_stock'
      ? 'https://schema.org/InStock'
      : product.stockStatus === 'backorder'
        ? 'https://schema.org/PreOrder'
        : 'https://schema.org/OutOfStock'

  const schema: Record<string, unknown> = {
    '@context': 'https://schema.org',
    '@type': 'Product',
    name: product.name,
    sku: product.sku,
    url: canonicalUrl,
    image: product.images.map((img) => img.url),
    description: product.shortDescription ?? product.description ?? undefined,
    category: product.category?.name,
    offers: {
      '@type': 'Offer',
      url: canonicalUrl,
      priceCurrency: currencyCode,
      price: product.price.toFixed(2),
      availability,
    },
  }

  if (product.ratingCount > 0) {
    schema.aggregateRating = {
      '@type': 'AggregateRating',
      ratingValue: product.ratingAverage,
      reviewCount: product.ratingCount,
    }
  }

  return schema
}

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

// Server Component: product data (translations, images, variations, specs,
// reviews, related products) is fetched via the locale-aware, ISR-cached
// getProductDetail() — see DATA_FETCHING_PATTERN.md and
// src/lib/db/queries/getProductDetail.ts. Interactivity (quantity, variant
// selection, add-to-cart) lives in ProductDetailClient.
export default async function ProductPage({ params }: ProductPageProps) {
  const { locale, slug } = await params
  const [product, defaultLanguage, currency] = await Promise.all([
    getProductDetail(decodeSlug(slug), locale),
    getDefaultLanguage(),
    getCurrencySettings(),
  ])

  if (!product) notFound()

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

  const schemas = [
    buildProductSchema(product, canonicalUrl, currency.code),
    buildBreadcrumbSchema(product, APP_URL, canonicalUrl),
    ...Object.values(product.schemas),
  ] as Record<string, unknown>[]

  return (
    <>
      <JsonLd data={schemas} />
      <ProductDetailClient product={product} alternatePaths={alternatePaths} defaultLocale={defaultLocale} />
    </>
  )
}
