interface RuntimeConfigInput {
  apiDomain: string
  websiteDomain: string
  superTokensCoreUri: string
  cookieSecure: boolean
  githubClientId?: string
  githubClientSecret?: string
  googleClientId?: string
  googleClientSecret?: string
  orcidClientId?: string
  orcidClientSecret?: string
}

export interface RuntimeConfigDiagnostics {
  mode: 'local' | 'mixed' | 'public'
  publicOriginReady: boolean
  cookieSecure: boolean
  warnings: string[]
  errors: string[]
  apiDomain: string
  websiteDomain: string
}

function normalizeTrimmed(value: string) {
  return value.trim()
}

function tryParseUrl(value: string) {
  const trimmed = normalizeTrimmed(value)
  if (!trimmed) {
    return null
  }

  try {
    return new URL(trimmed)
  } catch {
    return null
  }
}

function hasOriginOnlyPath(url: URL) {
  return url.pathname === '/' || url.pathname === ''
}

function isLoopbackHostname(hostname: string) {
  const normalized = hostname.trim().toLowerCase()
  return normalized === 'localhost'
    || normalized === '127.0.0.1'
    || normalized === '::1'
    || normalized === '[::1]'
}

function isHttpsUrl(url: URL) {
  return url.protocol === 'https:'
}

function hasCompleteCredentialPair(valueA: string | undefined, valueB: string | undefined) {
  return Boolean(String(valueA || '').trim() && String(valueB || '').trim())
}

export function getRuntimeConfigDiagnostics({
  apiDomain,
  websiteDomain,
  superTokensCoreUri,
  cookieSecure,
  githubClientId,
  githubClientSecret,
  googleClientId,
  googleClientSecret,
  orcidClientId,
  orcidClientSecret,
}: RuntimeConfigInput): RuntimeConfigDiagnostics {
  const warnings: string[] = []
  const errors: string[] = []

  const parsedApiDomain = tryParseUrl(apiDomain)
  const parsedWebsiteDomain = tryParseUrl(websiteDomain)
  const parsedSuperTokensCoreUri = tryParseUrl(superTokensCoreUri)

  if (!parsedApiDomain) {
    errors.push('API_DOMAIN must be an absolute URL origin.')
  } else if (!hasOriginOnlyPath(parsedApiDomain)) {
    errors.push('API_DOMAIN must not include a path; use API_BASE_PATH for route prefixing.')
  }

  if (!parsedWebsiteDomain) {
    errors.push('WEBSITE_DOMAIN must be an absolute URL origin.')
  } else if (!hasOriginOnlyPath(parsedWebsiteDomain)) {
    errors.push('WEBSITE_DOMAIN must not include a path; use WEBSITE_BASE_PATH for route prefixing.')
  }

  if (!parsedSuperTokensCoreUri) {
    errors.push('SUPERTOKENS_CORE_URI must be an absolute URL.')
  }

  const apiIsLoopback = parsedApiDomain ? isLoopbackHostname(parsedApiDomain.hostname) : false
  const websiteIsLoopback = parsedWebsiteDomain ? isLoopbackHostname(parsedWebsiteDomain.hostname) : false
  const coreIsLoopback = parsedSuperTokensCoreUri ? isLoopbackHostname(parsedSuperTokensCoreUri.hostname) : false
  const allLoopback = apiIsLoopback && websiteIsLoopback && coreIsLoopback
  const noLoopback = !apiIsLoopback && !websiteIsLoopback && !coreIsLoopback

  if (apiIsLoopback) {
    warnings.push('API_DOMAIN still targets a loopback/local-development origin.')
  }
  if (websiteIsLoopback) {
    warnings.push('WEBSITE_DOMAIN still targets a loopback/local-development origin.')
  }
  if (coreIsLoopback) {
    warnings.push('SUPERTOKENS_CORE_URI still targets a loopback/local-development host.')
  }

  if (parsedApiDomain && !apiIsLoopback && !isHttpsUrl(parsedApiDomain)) {
    warnings.push('API_DOMAIN uses HTTP on a non-loopback origin; use HTTPS before public launch.')
  }
  if (parsedWebsiteDomain && !websiteIsLoopback && !isHttpsUrl(parsedWebsiteDomain)) {
    warnings.push('WEBSITE_DOMAIN uses HTTP on a non-loopback origin; use HTTPS before public launch.')
  }

  if (!cookieSecure && !allLoopback) {
    warnings.push('COOKIE_SECURE is disabled; production auth cookies will not be hardened.')
  }

  if (cookieSecure && (
    (parsedApiDomain && !apiIsLoopback && !isHttpsUrl(parsedApiDomain))
    || (parsedWebsiteDomain && !websiteIsLoopback && !isHttpsUrl(parsedWebsiteDomain))
  )) {
    warnings.push('COOKIE_SECURE is enabled while a non-loopback auth origin still uses HTTP; verify reverse-proxy TLS posture.')
  }

  if (!hasCompleteCredentialPair(githubClientId, githubClientSecret) && (githubClientId || githubClientSecret)) {
    warnings.push('GitHub OAuth is only partially configured; set both client ID and client secret or neither.')
  }

  if (!hasCompleteCredentialPair(googleClientId, googleClientSecret) && (googleClientId || googleClientSecret)) {
    warnings.push('Google OAuth is only partially configured; set both client ID and client secret or neither.')
  }

  if (!hasCompleteCredentialPair(orcidClientId, orcidClientSecret) && (orcidClientId || orcidClientSecret)) {
    warnings.push('ORCID OAuth is only partially configured; set both client ID and client secret or neither.')
  }

  const mode: RuntimeConfigDiagnostics['mode'] = allLoopback
    ? 'local'
    : noLoopback
      ? 'public'
      : 'mixed'

  const publicOriginReady = Boolean(
    parsedApiDomain
    && parsedWebsiteDomain
    && !apiIsLoopback
    && !websiteIsLoopback
    && isHttpsUrl(parsedApiDomain)
    && isHttpsUrl(parsedWebsiteDomain)
    && cookieSecure
    && errors.length === 0
  )

  return {
    mode,
    publicOriginReady,
    cookieSecure,
    warnings,
    errors,
    apiDomain: normalizeTrimmed(apiDomain),
    websiteDomain: normalizeTrimmed(websiteDomain),
  }
}
