/**
 * Feishu user token file storage.
 *
 * Stores OAuth tokens per-user in {forgeDataDir}/feishu-tokens/{openId}.json.
 * Tokens are injected into the SDK subprocess via the native lark-cli env
 * contract (LARKSUITE_CLI_USER_ACCESS_TOKEN et al.), avoiding any dependency
 * on lark-cli's own Keychain/encrypted storage.
 */

import fs from 'fs'
import path from 'path'
import { getForgeDataDir } from '@/lib/forge-data'

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

export interface FeishuUserToken {
  accessToken: string
  refreshToken: string
  expiresAt: number        // Unix ms — access_token expiry
  refreshExpiresAt: number // Unix ms — refresh_token expiry
  scope: string            // scopes actually GRANTED by the server
  /**
   * Scopes REQUESTED at authorization time (space-separated).
   * Compared against the current FORGE_FEISHU_SCOPES to decide whether a
   * re-authorization is needed. We compare against requested (not granted)
   * scopes because the server may permanently refuse to grant some scopes
   * (e.g. not enabled in the console) — comparing against granted would then
   * loop forever.
   */
  requestedScope?: string
  grantedAt: number        // Unix ms
  /** Unix ms — last successful server-side verification (throttles revocation checks) */
  lastVerifiedAt?: number
}

// ---------------------------------------------------------------------------
// File path helpers
// ---------------------------------------------------------------------------

function tokensDir(): string {
  return path.join(getForgeDataDir(), 'feishu-tokens')
}

function tokenPath(appId: string, openId: string): string {
  // appId + openId 联合主键——不同 bot 的同一用户 token 不冲突
  const safeAppId = appId.replace(/[^a-zA-Z0-9._-]/g, '_')
  return path.join(tokensDir(), `${safeAppId}_${openId}.json`)
}

// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------

export function readFeishuToken(appId: string, openId: string): FeishuUserToken | null {
  const p = tokenPath(appId, openId)
  if (!fs.existsSync(p)) return null
  try {
    return JSON.parse(fs.readFileSync(p, 'utf-8')) as FeishuUserToken
  } catch {
    return null
  }
}

export function writeFeishuToken(appId: string, openId: string, token: FeishuUserToken): void {
  const dir = tokensDir()
  fs.mkdirSync(dir, { recursive: true })
  fs.writeFileSync(tokenPath(appId, openId), JSON.stringify(token, null, 2), { mode: 0o600 })
}

export function deleteFeishuToken(appId: string, openId: string): void {
  const p = tokenPath(appId, openId)
  if (fs.existsSync(p)) fs.unlinkSync(p)
}

// ---------------------------------------------------------------------------
// Token status
// ---------------------------------------------------------------------------

/** Refresh proactively when access_token is within 5 minutes of expiry. */
const REFRESH_AHEAD_MS = 5 * 60 * 1000

export type TokenStatus = 'valid' | 'needs_refresh' | 'expired'

export function checkTokenStatus(token: FeishuUserToken): TokenStatus {
  const now = Date.now()
  if (now < token.expiresAt - REFRESH_AHEAD_MS) return 'valid'
  if (now < token.refreshExpiresAt) return 'needs_refresh'
  return 'expired'
}
