import config from '@payload-config'
import { getPayload } from 'payload'
import { cache } from 'react'
import type { Course, Media, Setting } from '@/payload-types'
import { catalogueFeed, fromFeed } from './catalogueFeed'

export type Locale = 'ar' | 'en'
export const isLocale = (x: string): x is Locale => x === 'ar' || x === 'en'
export const other = (l: Locale): Locale => (l === 'ar' ? 'en' : 'ar')

export const cms = cache(() => getPayload({ config }))

/** Everything every page needs: site settings and the course list, in one language. */
/**
 * Where the learning platform lives. PLATFORM_URL in .env wins over whatever the CMS holds, so moving the
 * platform to another address (or running a copy of the site against a test platform) is one line and no
 * content edit. Empty: the CMS value is used as it is.
 */
const platformBase = (process.env.PLATFORM_URL || '').trim().replace(/\/+$/, '')

/** A CMS address rewritten onto PLATFORM_URL, keeping its path. */
function onPlatform(href?: string | null): string | null | undefined {
  if (!platformBase || !href) return href
  try {
    const u = new URL(href)
    return platformBase + u.pathname + u.search + u.hash
  } catch {
    return href
  }
}

export type Category = { id: number; slug: string; name: string }

export const loadSite = cache(async (locale: Locale) => {
  const p = await cms()
  const [settings, stored, feed] = await Promise.all([
    p.findGlobal({ slug: 'settings', locale, fallbackLocale: 'ar', depth: 0 }),
    p.find({ collection: 'courses', locale, fallbackLocale: 'ar', sort: 'order', limit: 100, depth: 1 }),
    catalogueFeed(),
  ])
  const siteSettings = { ...settings, platformUrl: onPlatform(settings.platformUrl) }

  if (!feed) {
    // The platform did not answer: the CMS copy of the catalogue stands in, exactly as it was written.
    return {
      settings: siteSettings,
      categories: [] as Category[],
      courses: stored.docs.map((c) => ({ ...c, platformUrl: onPlatform(c.platformUrl) })),
    }
  }

  // The platform's catalogue, in its order, each course wearing its CMS row for the things only the site decides.
  const bySlug = new Map(stored.docs.map((c) => [c.slug, c]))
  const courses = feed.courses.map((fc, i) => {
    const c = fromFeed(fc, i + 1, locale, bySlug.get(fc.slug))
    return { ...c, platformUrl: onPlatform(c.platformUrl) }
  })
  const categories: Category[] = feed.categories.map((k) => ({ id: k.id, slug: k.slug, name: k.name[locale] || k.name.ar }))
  return { settings: siteSettings, categories, courses }
})

export const loadPage = cache(async <S extends 'home' | 'catalogue' | 'pricing' | 'about'>(slug: S, locale: Locale) =>
  (await cms()).findGlobal({ slug, locale, fallbackLocale: 'ar', depth: 1 }),
)

/** A site path in the page's language: "/courses" stays for Arabic and becomes "/en/courses" for English. */
export function localHref(locale: Locale, href?: string | null): string {
  if (!href) return '#'
  if (/^(https?:|mailto:|tel:|#)/.test(href) || href.startsWith('/brand/') || href.startsWith('/api/')) return href
  const p = href.startsWith('/') ? href : `/${href}`
  if (locale === 'ar') return p
  return p === '/' ? '/en' : p.startsWith('/#') ? `/en${p.slice(1)}` : `/en${p}`
}

export const isExternal = (href?: string | null) => Boolean(href && /^https?:/.test(href))

export function media(m: Course['poster'] | number | string | null | undefined): Media | null {
  return m && typeof m === 'object' ? (m as Media) : null
}

/**
 * What a course costs today, and what it costs normally while an offer is running.
 *
 * The offer ends by itself: `amount` is always the normal price, so the day after `offerEnds` the pages show
 * that price again with nobody having to remember. The end date names a whole day, and that day is inside the
 * offer, so the comparison runs to the end of it.
 */
export function price(c: Course, s: Setting): { now: string; was: string | null; ends: Date | null } {
  const unit = s.currency?.label || s.currency?.code || ''
  const money = (n: number) => `${n.toLocaleString('en-US')} ${unit}`.trim()
  const normal = c.price?.amount
  if (normal === null || normal === undefined) return { now: c.price?.note || '', was: null, ends: null }

  const offer = c.price?.offer
  const ends = c.price?.offerEnds ? new Date(c.price.offerEnds) : null
  // Both the CMS picker and the platform give midnight UTC of the chosen day, so the day is measured
  // in UTC too: a server in another timezone would otherwise end the offer a day early or late.
  const lastMoment = ends && !Number.isNaN(ends.getTime())
    ? new Date(ends).setUTCHours(23, 59, 59, 999) : null
  const live = offer !== null && offer !== undefined && lastMoment !== null && Date.now() <= lastMoment
  return live
    ? { now: money(offer as number), was: money(normal), ends }
    : { now: money(normal), was: null, ends: null }
}

/** The one figure to print where there is room for one: what the student pays today. */
export function priceText(c: Course, s: Setting): string {
  return price(c, s).now
}

/** «15 أكتوبر 2026» / «15 October 2026», in the language of the page. */
export function dateText(d: Date, locale: Locale): string {
  // Arabic pages count in Western digits everywhere else on this site, so the date does too
  return new Intl.DateTimeFormat(locale === 'ar' ? 'ar-EG-u-nu-latn' : 'en-GB',
    { day: 'numeric', month: 'long', year: 'numeric', timeZone: 'UTC' }).format(d)
}

export const dir = (l: Locale) => (l === 'ar' ? 'rtl' : 'ltr')

/**
 * A YouTube or Vimeo watch address as its privacy-friendly embed address, or '' when the link is neither.
 * The same rule the learning platform uses, so one link works in both places.
 */
export function embedUrl(url?: string | null): string {
  const raw = (url || '').trim()
  const yt = raw.match(
    /(?:youtube(?:-nocookie)?\.com\/(?:watch\?(?:.*&)?v=|embed\/|shorts\/|live\/)|youtu\.be\/)([A-Za-z0-9_-]{11})/,
  )
  if (yt) {
    const t = raw.match(/[?&#]t=(\d+)/)
    return `https://www.youtube-nocookie.com/embed/${yt[1]}?rel=0&modestbranding=1&playsinline=1${t ? `&start=${t[1]}` : ''}`
  }
  const vm = raw.match(/vimeo\.com\/(?:video\/)?(\d+)/)
  return vm ? `https://player.vimeo.com/video/${vm[1]}?dnt=1` : ''
}

/**
 * A WhatsApp number as {href, label}: the address WhatsApp itself understands (digits only, no plus, no
 * leading zeros of the international prefix) and the number written the way a reader scans it.
 * `text` is the first line already typed into the chat, so the visitor only presses send.
 */
export function whatsapp(raw?: string | null, text?: string): { href: string; label: string } | null {
  const digits = (raw || '').replace(/[^\d]/g, '').replace(/^00/, '')
  if (digits.length < 8) return null
  const label = '+' + (digits.startsWith('20')
    ? `${digits.slice(0, 2)} ${digits.slice(2, 5)} ${digits.slice(5, 8)} ${digits.slice(8)}`
    : digits)
  const query = text ? `?text=${encodeURIComponent(text)}` : ''
  return { href: `https://wa.me/${digits}${query}`, label }
}
