import { getDb } from '../client'
import { apiProviders } from '../schema'
import { eq, and, asc, sql } from 'drizzle-orm'
import { nowExpr } from '../shared/dialect-helpers'
import { ApiProviderStatus } from '../shared/enums'

/**
 * ApiProvider Repository。封装 api_providers 表的所有查询。
 *
 * 设计约定（与 session.repo / message.repo 一致）：
 * - 返回类型由 drizzle 推断；消费方不再写 `as Record<string, unknown>`
 * - 列出 / 单查返回 PROVIDER_SELECT 形状：id 列经 CASE WHEN 重映射
 *   （custom → 原始主键 id；内置 → provider 名），与原裸 SQL 完全等价
 * - 内置 provider 的 upsert（首次使用时 INSERT）由 upsertBuiltin 承担
 * - UPDATE 显式刷新 updated_at 用 nowExpr()
 * - 路由层负责业务编排（builtin 合并、auto-reset status 等），repo 只做数据访问
 */

/**
 * PROVIDER_SELECT 等价字段集。
 * 原始 SQL：
 *   CASE WHEN provider = 'custom' THEN id ELSE provider END AS id,
 *   name, provider, api_key, base_url, model_name, is_active,
 *   status, status_error, created_at, updated_at
 */
const providerSelectFields = {
  id: sql<string>`CASE WHEN ${apiProviders.provider} = 'custom' THEN ${apiProviders.id} ELSE ${apiProviders.provider} END`,
  name: apiProviders.name,
  provider: apiProviders.provider,
  apiKey: apiProviders.apiKey,
  baseUrl: apiProviders.baseUrl,
  modelName: apiProviders.modelName,
  isActive: apiProviders.isActive,
  status: apiProviders.status,
  statusError: apiProviders.statusError,
  modelsFetchedAt: apiProviders.modelsFetchedAt,
  modelsFetchError: apiProviders.modelsFetchError,
  createdAt: apiProviders.createdAt,
  updatedAt: apiProviders.updatedAt,
}

/**
 * 按 id 或 provider 名解析 WHERE 条件（替代原 resolveProviderWhere）。
 * - 'custom-' 前缀 → 按主键 id 匹配
 * - 其他 → 按 provider 列匹配（内置 provider 名）
 */
function byIdOrProvider(id: string) {
  return id.startsWith('custom-')
    ? eq(apiProviders.id, id)
    : eq(apiProviders.provider, id)
}

/** updateFields 接受的可更新字段（与原 allowedFields 白名单一致） */
type ApiProviderUpdatableFields = {
  apiKey?: string
  baseUrl?: string
  isActive?: number
  status?: string
  statusError?: string
  name?: string
  modelName?: string
  modelsFetchedAt?: string
  modelsFetchError?: string
}

export const apiProviderRepo = {
  /**
   * 列出用户的所有 provider，按 created_at 正序（与原 ORDER BY created_at 一致）。
   * 返回 PROVIDER_SELECT 形状；调用方负责合并内置 provider 默认行。
   */
  listByUser(userId: string) {
    return getDb()
      .select(providerSelectFields)
      .from(apiProviders)
      .where(eq(apiProviders.userId, userId))
      .orderBy(asc(apiProviders.createdAt))
      .all()
  },

  /**
   * 按 id（custom-xxx）或 provider 名查单个 provider（PROVIDER_SELECT 形状）。
   * 用于 PATCH/DELETE/test 路由更新后的回读。
   */
  findByIdAndUser(id: string, userId: string) {
    return getDb()
      .select(providerSelectFields)
      .from(apiProviders)
      .where(and(byIdOrProvider(id), eq(apiProviders.userId, userId)))
      .get()
  },

  /**
   * 按 id（custom-xxx）或 provider 名查原始行（全字段，用于存在性检查 + 凭证读取）。
   * 返回 drizzle 推断的完整行类型，包含 api_key / base_url / provider 等原始列。
   */
  findRawByIdAndUser(id: string, userId: string) {
    return getDb()
      .select()
      .from(apiProviders)
      .where(and(byIdOrProvider(id), eq(apiProviders.userId, userId)))
      .get()
  },

  /** 创建 custom provider（对应 POST /api/api-providers） */
  createCustom(data: {
    id: string
    name: string
    baseUrl: string
    apiKey?: string
    modelName?: string
    userId: string
  }) {
    getDb()
      .insert(apiProviders)
      .values({
        id: data.id,
        name: data.name,
        provider: 'custom',
        apiKey: data.apiKey ?? '',
        baseUrl: data.baseUrl,
        modelName: data.modelName ?? '',
        isActive: 0,
        status: ApiProviderStatus.NOT_CONFIGURED,
        statusError: '',
        userId: data.userId,
      })
      .run()
  },

  /**
   * 内置 provider 首次使用时 INSERT（对应 PATCH / test 路由的 upsert 分支）。
   * id 格式：`${providerName}-${userId}`，与原 SQL 完全一致。
   */
  upsertBuiltin(providerName: string, displayName: string, userId: string) {
    getDb()
      .insert(apiProviders)
      .values({
        id: `${providerName}-${userId}`,
        name: displayName,
        provider: providerName,
        userId,
      })
      .run()
  },

  /**
   * 动态字段 UPDATE（对应 PATCH 路由的动态 SET）。
   * 仅接受白名单字段；自动刷新 updated_at。
   * 业务编排（如 api_key 变更时 auto-reset status）由调用方决定传入哪些字段。
   */
  updateFields(id: string, userId: string, fields: ApiProviderUpdatableFields) {
    getDb()
      .update(apiProviders)
      .set({ ...fields, updatedAt: nowExpr() })
      .where(and(byIdOrProvider(id), eq(apiProviders.userId, userId)))
      .run()
  },

  /**
   * 更新 status + status_error + updated_at（对应 test 路由的所有状态写入）。
   * 用于连接测试结果回写：connected / error / not_configured / cli_authenticated。
   */
  updateStatus(id: string, userId: string, status: string, statusError: string = '') {
    getDb()
      .update(apiProviders)
      .set({ status, statusError, updatedAt: nowExpr() })
      .where(and(byIdOrProvider(id), eq(apiProviders.userId, userId)))
      .run()
  },

  /**
   * 更新模型发现元数据（发现时间、错误信息）。
   */
  updateFetchMeta(id: string, userId: string, fetchedAt: string, fetchError: string = '') {
    getDb()
      .update(apiProviders)
      .set({ modelsFetchedAt: fetchedAt, modelsFetchError: fetchError, updatedAt: nowExpr() })
      .where(and(byIdOrProvider(id), eq(apiProviders.userId, userId)))
      .run()
  },

  /**
   * 删除 provider（对应 DELETE 路由；仅 custom 可删，由路由层校验）。
   * api_providers 无子表依赖，单行删除即可。
   */
  deleteByIdAndUser(id: string, userId: string) {
    getDb()
      .delete(apiProviders)
      .where(and(eq(apiProviders.id, id), eq(apiProviders.userId, userId)))
      .run()
  },

  // ─── provider.ts 凭证查询 ───────────────────────────────────

  /**
   * 按 provider 名查凭证（provider.ts resolveProvider 内置分支）。
   * 返回 id / apiKey / baseUrl / provider。
   */
  findCredentialByProvider(providerName: string, userId: string) {
    return getDb()
      .select({
        id: apiProviders.id,
        apiKey: apiProviders.apiKey,
        baseUrl: apiProviders.baseUrl,
        provider: apiProviders.provider,
      })
      .from(apiProviders)
      .where(and(eq(apiProviders.provider, providerName), eq(apiProviders.userId, userId)))
      .get()
  },

  /**
   * 按 model_name 查 custom provider 凭证（provider.ts resolveProvider 自定义分支）。
   * 要求 api_key 非空。返回 id / name / apiKey / baseUrl。
   */
  findCustomCredentialByModel(model: string, userId: string) {
    return getDb()
      .select({
        id: apiProviders.id,
        name: apiProviders.name,
        apiKey: apiProviders.apiKey,
        baseUrl: apiProviders.baseUrl,
      })
      .from(apiProviders)
      .where(
        and(
          eq(apiProviders.provider, 'custom'),
          eq(apiProviders.modelName, model),
          sql`${apiProviders.apiKey} != ''`,
          eq(apiProviders.userId, userId),
        ),
      )
      .get()
  },

  /**
   * 按 id 查 api_key（provider.ts hasCredentials / hasApiKey）。
   * 不限 user_id——这两个 helper 原始 SQL 就没有 user_id 过滤。
   */
  findApiKeyById(id: string) {
    return getDb()
      .select({ apiKey: apiProviders.apiKey })
      .from(apiProviders)
      .where(eq(apiProviders.id, id))
      .get()
  },

  /**
   * 列出所有 connected 的 custom provider 的 {id, name, model_name}（对应 GET /api/models）。
   * 原始 SQL 无 user_id 过滤、无 ORDER BY；返回 id / name / modelName。
   */
  listCustomConnectedModels() {
    return getDb()
      .select({
        id: apiProviders.id,
        name: apiProviders.name,
        modelName: apiProviders.modelName,
      })
      .from(apiProviders)
      .where(
        and(
          eq(apiProviders.provider, 'custom'),
          sql`${apiProviders.modelName} != ''`,
          eq(apiProviders.status, ApiProviderStatus.CONNECTED),
        ),
      )
      .all()
  },

  /**
   * 按内置 STT 主键（'stt'）取转写配置 ——全局单例，不限 user_id。
   * 与原 SQL `SELECT api_key, base_url, model_name FROM api_providers WHERE id = 'stt'`
   * 完全等价；返回 { apiKey, baseUrl, modelName } 或 undefined。
   */
  findSttConfig() {
    return getDb()
      .select({
        apiKey: apiProviders.apiKey,
        baseUrl: apiProviders.baseUrl,
        modelName: apiProviders.modelName,
      })
      .from(apiProviders)
      .where(eq(apiProviders.id, 'stt'))
      .get()
  },
}
