import { getAuthRuntimeConfig } from './auth-env'
import type { PublicLaunchChecklistItem, PublicLaunchReadiness, PublicLaunchTargets } from '../shared/public-launch'

const authRuntime = getAuthRuntimeConfig()
const DEFAULT_AUTH_API_TIMEOUT_MS = authRuntime.authApiTimeoutMs

function normalizeBaseUrl(value: unknown) {
  return String(value || '').trim().replace(/\/$/, '')
}

function normalizePath(path: string) {
  return path.startsWith('/') ? path : `/${path}`
}

function buildCandidateBaseUrls() {
  const configured = normalizeBaseUrl(authRuntime.authApiBaseUrl)
  const origin = normalizeBaseUrl(typeof window !== 'undefined' ? window.location.origin : '')
  return Array.from(new Set([configured, origin].filter(Boolean)))
}

function buildTimeoutSignal(timeoutMs: number) {
  const controller = new AbortController()
  const timeout = window.setTimeout(() => controller.abort(), timeoutMs)
  return {
    signal: controller.signal,
    cleanup() {
      window.clearTimeout(timeout)
    },
  }
}

function createAuthApiError(status: number, code: string) {
  const error = new Error(code) as Error & { status?: number; code?: string }
  error.status = status
  error.code = code
  return error
}

export interface AuthApiFetchResult {
  response: Response
  baseUrl: string
}

export interface DesktopLinkPayload {
  ok: true
  token: string
  expires_at: string
}

export interface DesktopLinkVerifyPayload {
  ok: true
  email: string
  plan: string
  role: string
  can_download: boolean
  access_status: string
}

export interface AuthHealthPayload {
  ok: true
  service: string
  supertokens: {
    configured: boolean
    reachable: boolean
    ready: boolean
    apiVersion?: string | null
    error?: string | null
    oauth?: {
      github: boolean
      google: boolean
      orcid?: boolean
    }
  }
  fallback: {
    enabled: boolean
    active?: boolean
    reason?: string | null
  }
  billing: {
    statePath: string
    processedEventCount: number
    pricePlanMapConfigured: boolean
    productPlanMapConfigured: boolean
    webhookSecretConfigured: boolean
  }
  runtime: {
    mode: 'local' | 'mixed' | 'public'
    public_origin_ready: boolean
    cookie_secure: boolean
    api_domain: string
    website_domain: string
    warnings: string[]
    errors: string[]
  }
  launch?: {
    posture: 'launch-ready' | 'preview'
    ready: boolean
    readiness: PublicLaunchReadiness
    checklist: PublicLaunchChecklistItem[]
    missingLabels: string[]
    targets: PublicLaunchTargets
  }
}

export interface ReleaseManifestPlatformPayload {
  platform_key: 'windows' | 'macos' | 'linux'
  platform: string
  subtitle: string
  details: string
  configured: boolean
  channel: string
  version: string | null
  build_id: string | null
  published_at: string | null
  file_name: string | null
  file_size_bytes: number | null
  checksum_sha256: string | null
  download_url: string | null
  download_available: boolean
  validation_summary?: {
    lane: string
    result: 'passed' | 'failed'
    generated_at: string
    configuration: string
    skip_build: boolean
    pre_package_editor_build?: {
      lane: string
      performed: boolean
      result: 'passed' | 'not-run'
    } | null
    smoke_map_count: number
    smoke_maps: Array<{
      map_url: string
      label: string
      result: 'passed' | 'failed'
    }>
  } | null
}

export interface ReleaseManifestPayload {
  ok: true
  manifest: {
    generated_at: string
    support_email: string
    public_docs_url: string | null
    release_notes_url: string | null
    corresponding_source_url: string | null
    open_source_repo_url: string | null
    commerce?: {
      operator_checkout_url: string | null
      studio_checkout_url: string | null
      plan_price_operator: string
      plan_price_studio: string
    }
    viewer: {
      authenticated: boolean
      canDownload: boolean
      plan: string | null
      role: string | null
      accessStatus: string | null
    }
    platforms: ReleaseManifestPlatformPayload[]
  }
}

export interface ApiBootstrapUserPayload {
  user: {
    id: string
    email: string
    name?: string
    plan?: string
    role?: string
    can_download?: boolean
    billing?: {
      source?: string
      access_status?: string
      can_download?: boolean
      subscription_id?: string | null
      customer_id?: string | null
      transaction_id?: string | null
      last_event_id?: string | null
      last_event_type?: string | null
      last_event_at?: string | null
      updated_at?: string | null
      state_path?: string | null
    }
    is_admin?: boolean
    auth_method?: string
  }
  mode: string
}

export function buildAuthApiBaseUrls() {
  return buildCandidateBaseUrls()
}

export async function authApiFetch(
  path: string,
  init?: RequestInit,
  options?: {
    timeoutMs?: number
    baseUrls?: string[]
  },
): Promise<AuthApiFetchResult> {
  const baseUrls = options?.baseUrls?.length ? options.baseUrls : buildCandidateBaseUrls()
  const timeoutMs = Math.max(1000, options?.timeoutMs ?? DEFAULT_AUTH_API_TIMEOUT_MS)
  const normalizedPath = normalizePath(path)

  let lastError: unknown = null
  for (const baseUrl of baseUrls) {
    const { signal, cleanup } = buildTimeoutSignal(timeoutMs)
    try {
      const response = await fetch(`${baseUrl}${normalizedPath}`, {
        credentials: 'include',
        ...init,
        signal,
      })
      return { response, baseUrl }
    } catch (error) {
      lastError = error
    } finally {
      cleanup()
    }
  }

  throw lastError ?? new Error('Auth API unreachable')
}

export async function getCurrentUser() {
  const result = await authApiFetch('/api/auth/me')
  return result.response
}

export async function logoutCurrentUser() {
  const result = await authApiFetch('/api/auth/logout', {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
    },
  })
  return result.response
}

export async function createDesktopLinkToken() {
  const result = await authApiFetch('/api/auth/desktop-link', {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
    },
    body: JSON.stringify({}),
  })
  const payload = await result.response.json() as DesktopLinkPayload | { error?: string }
  if (!result.response.ok || payload == null || (payload as DesktopLinkPayload).ok !== true) {
    throw createAuthApiError(
      result.response.status,
      (payload as { error?: string }).error || `desktop_link_http_${result.response.status}`,
    )
  }
  return payload as DesktopLinkPayload
}

export async function verifyDesktopLinkToken(token: string) {
  const result = await authApiFetch(`/api/auth/desktop-link/verify?token=${encodeURIComponent(token)}`)
  const payload = await result.response.json() as DesktopLinkVerifyPayload | { error?: string }
  if (!result.response.ok || payload == null || (payload as DesktopLinkVerifyPayload).ok !== true) {
    throw createAuthApiError(
      result.response.status,
      (payload as { error?: string }).error || `desktop_link_verify_http_${result.response.status}`,
    )
  }
  return payload as DesktopLinkVerifyPayload
}

export async function getAuthHealth() {
  const result = await authApiFetch('/api/auth/health')
  const payload = await result.response.json() as AuthHealthPayload
  if (!result.response.ok) {
    throw createAuthApiError(result.response.status, `auth_health_http_${result.response.status}`)
  }
  return payload
}

export async function getReleaseManifest() {
  const result = await authApiFetch('/api/releases/manifest')
  const payload = await result.response.json() as ReleaseManifestPayload | { error?: string }
  if (!result.response.ok || payload == null || (payload as ReleaseManifestPayload).ok !== true) {
    throw createAuthApiError(
      result.response.status,
      (payload as { error?: string }).error || `release_manifest_http_${result.response.status}`,
    )
  }
  return payload as ReleaseManifestPayload
}
