/**
 * DingTalk Device Flow — Quick app creation via QR scan.
 *
 * Based on the official DingTalk "一键创建钉钉应用扫码接入流程" protocol.
 * Three-step flow: init → begin → poll.
 */

const BASE_URL = 'https://oapi.dingtalk.com'
const API_TIMEOUT_MS = 15_000

export interface InitResponse {
  errcode: number
  errmsg: string
  nonce: string
  expires_in: number
}

export interface BeginResponse {
  errcode: number
  errmsg: string
  device_code: string
  user_code: string
  verification_uri: string
  verification_uri_complete: string
  expires_in: number
  interval: number
}

export type PollStatus = 'WAITING' | 'SUCCESS' | 'FAIL' | 'EXPIRED'

export interface PollResponse {
  errcode: number
  errmsg: string
  status: PollStatus
  client_id?: string
  client_secret?: string
  fail_reason?: string
}

async function dingtalkRequest<T>(endpoint: string, body: Record<string, unknown>): Promise<T> {
  const res = await fetch(`${BASE_URL}${endpoint}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
    signal: AbortSignal.timeout(API_TIMEOUT_MS),
  })

  if (!res.ok) {
    throw new Error(`DingTalk API error: ${res.status} ${res.statusText}`)
  }

  const rawText = await res.text()
  if (!rawText.trim()) {
    return {} as T
  }

  try {
    return JSON.parse(rawText) as T
  } catch (err) {
    throw new Error(
      `DingTalk API returned non-JSON body for ${endpoint}: ${err instanceof Error ? err.message : String(err)}`,
    )
  }
}

/**
 * Step 1: Initialize the device flow and obtain a nonce.
 */
export async function initDeviceFlow(source?: string): Promise<InitResponse> {
  const body: Record<string, unknown> = {}
  if (source) body.source = source
  return dingtalkRequest<InitResponse>('/app/registration/init', body)
}

/**
 * Step 2: Begin authorization — exchange nonce for device_code and QR URI.
 */
export async function beginAuth(nonce: string): Promise<BeginResponse> {
  return dingtalkRequest<BeginResponse>('/app/registration/begin', { nonce })
}

/**
 * Step 3: Poll authorization status using device_code.
 */
export async function pollAuth(deviceCode: string): Promise<PollResponse> {
  return dingtalkRequest<PollResponse>('/app/registration/poll', { device_code: deviceCode })
}
