/**
 * Every address this site talks to, in one place, every one of them settable from env/cms.env.
 *
 * The rule: no component, page or helper writes a URL or a path of its own. They ask here. So moving the
 * platform, renaming its feed endpoint, pointing the site at a staging platform, or putting a CDN in front
 * of the media is one line in the env file and a restart — never an edit in the code and never a content
 * change in the CMS.
 *
 * Two kinds of value:
 *   server    read at request time on the server. They may hold internal addresses the browser cannot
 *             reach (PLATFORM_INTERNAL_URL is the container's short path to the platform).
 *   public    reach the browser, so they MUST be named NEXT_PUBLIC_* — Next replaces those at build time
 *             and anything else is simply undefined in the browser, silently. `publicConfig()` is what a
 *             client component is handed; it is the only thing that crosses that line.
 *
 * Nothing here throws on a missing value. A site whose platform is unreachable still has to serve its
 * pages — the catalogue falls back to the CMS copy — so every getter returns a usable default instead.
 */

/** A trailing slash on a base address doubles every slash in a joined path. */
const trim = (s: string | undefined) => (s || '').trim().replace(/\/+$/, '')

/** A path setting always starts with exactly one slash, however it was written in the env file. */
const path = (s: string | undefined, fallback: string) => {
  const v = (s || '').trim()
  if (!v) return fallback
  return v.startsWith('/') ? v : `/${v}`
}

const num = (s: string | undefined, fallback: number) => {
  const n = Number((s || '').trim())
  return Number.isFinite(n) && n >= 0 ? n : fallback
}

const bool = (s: string | undefined, fallback: boolean) => {
  const v = (s || '').trim().toLowerCase()
  if (!v) return fallback
  return v === '1' || v === 'true' || v === 'yes' || v === 'on'
}

export const platform = {
  /**
   * The address a visitor's browser should use: it goes into links the student clicks (sign in, enrol).
   * Never the internal one, which resolves only inside the docker network.
   */
  public: () => trim(process.env.PLATFORM_URL),

  /**
   * The address THIS server should use when it asks the platform for data. A container reaching the
   * platform by service name skips the public hostname, TLS and the round trip out and back.
   * Falls back to the public address, which is right on a machine with no internal route.
   */
  internal: () => trim(process.env.PLATFORM_INTERNAL_URL) || trim(process.env.PLATFORM_URL),

  /** The catalogue endpoint, relative to the platform. */
  feedPath: () => path(process.env.PLATFORM_FEED_PATH, '/local/thinkera/feed.php'),

  /** Seconds Next may serve a cached catalogue before asking again. 0 = never cache. */
  feedTtl: () => num(process.env.PLATFORM_FEED_TTL, 300),

  /** Milliseconds to wait for the platform before giving up and using the CMS copy. */
  feedTimeout: () => num(process.env.PLATFORM_FEED_TIMEOUT, 4000),

  /** Where «sign in» goes. Empty = the platform's own root. */
  loginUrl: () => trim(process.env.PLATFORM_LOGIN_URL) || trim(process.env.PLATFORM_URL),

  /**
   * Where a course's enrol button goes, when the feed does not carry its own `enrolUrl`.
   * `{slug}` is replaced with the course's slug.
   */
  enrolTemplate: () => (process.env.PLATFORM_ENROL_URL || '').trim(),
}

/** The full catalogue-feed address, or '' when there is no platform configured to ask. */
export function feedUrl(): string {
  const root = platform.internal()
  return root ? root + platform.feedPath() : ''
}

/** A course's enrol address: what the platform said, else the template, else the platform root. */
export function enrolUrl(slug: string, fromFeed?: string | null): string {
  if (fromFeed) return fromFeed
  const tpl = platform.enrolTemplate()
  if (tpl) return tpl.replace('{slug}', encodeURIComponent(slug))
  return platform.public()
}

/**
 * What the browser is allowed to know. Everything a client component needs arrives through this one
 * object, passed down from a server component — never read from `process.env` in the browser, where
 * only NEXT_PUBLIC_* exists at all and a typo is an undefined nobody notices.
 */
export type PublicConfig = {
  /** Courses per page in the catalogue. */
  pageSize: number
  /** The chat bubble: off entirely when false, and then nothing of it is rendered or sent. */
  chatEnabled: boolean
  /** Digits only, no plus — what wa.me expects. Empty = no WhatsApp handoff anywhere. */
  whatsapp: string
  /** Shown in the footer and on the contact page. */
  email: string
  /** Light or dark before the visitor has ever chosen; after that their choice wins. */
  defaultTheme: 'light' | 'dark'
}

export function publicConfig(): PublicConfig {
  const theme = (process.env.NEXT_PUBLIC_DEFAULT_THEME || '').trim().toLowerCase()
  return {
    pageSize: num(process.env.NEXT_PUBLIC_PAGE_SIZE, 6),
    chatEnabled: bool(process.env.NEXT_PUBLIC_CHAT_ENABLED, true),
    whatsapp: (process.env.NEXT_PUBLIC_WHATSAPP || '').replace(/[^\d]/g, '').replace(/^00/, ''),
    email: (process.env.NEXT_PUBLIC_CONTACT_EMAIL || '').trim(),
    defaultTheme: theme === 'dark' ? 'dark' : 'light',
  }
}
