import { getDb } from '../client'
import { cronTasks, taskExecutions } from '../schema'
import { eq, and, or, desc, sql } from 'drizzle-orm'
import { nowExpr } from '../shared/dialect-helpers'

/**
 * CronTask Repository。封装 cron_tasks 表的所有查询。
 * task_executions 的级联删除由 deleteByIdAndOwner 事务承担（无 FK）。
 *
 * 设计约定：
 * - 返回类型由 drizzle 推断，消费方不再写 `as Record<string, unknown>`
 * - 删除操作用 db.transaction 包裹级联
 * - heartbeat 任务受保护：不可删除（由调用方先调 findHeartbeatFlagByIdAndOwner 判定）
 * - UPDATE 显式刷新 updated_at 用 nowExpr()
 */

/** PATCH 可更新的字段白名单（对应 route 的 allowedFields，drizzle 驼峰键） */
type CronTaskUpdatable = Partial<
  Pick<
    typeof cronTasks.$inferInsert,
    | 'name'
    | 'schedule'
    | 'action'
    | 'actionType'
    | 'agentName'
    | 'skillName'
    | 'workspaceId'
    | 'enabled'
    | 'config'
    | 'lastRunAt'
    | 'lastRunResult'
    | 'webhookEnabled'
  >
>

export const cronTaskRepo = {
  /**
   * 列出 owner 的任务。
   * - 传 workspaceId：返回该 workspace 的任务 + 全局 heartbeat 任务
   * - 不传：返回 owner 的全部任务
   * 两种情况均按 is_heartbeat DESC, updated_at DESC 排序（heartbeat 优先）。
   */
  listByOwner(userId: string, workspaceId?: string) {
    if (workspaceId) {
      return getDb()
        .select()
        .from(cronTasks)
        .where(
          and(
            eq(cronTasks.ownerUserId, userId),
            or(eq(cronTasks.workspaceId, workspaceId), eq(cronTasks.isHeartbeat, 1)),
          ),
        )
        .orderBy(desc(cronTasks.isHeartbeat), desc(cronTasks.updatedAt))
        .all()
    }
    return getDb()
      .select()
      .from(cronTasks)
      .where(eq(cronTasks.ownerUserId, userId))
      .orderBy(desc(cronTasks.isHeartbeat), desc(cronTasks.updatedAt))
      .all()
  },

  /** 按 id + owner 查单个任务（owner 隔离） */
  findByIdAndOwner(id: string, userId: string) {
    return getDb()
      .select()
      .from(cronTasks)
      .where(and(eq(cronTasks.id, id), eq(cronTasks.ownerUserId, userId)))
      .get()
  },

  /** 按 id 查（不限 owner，用于内部流程如 execute/cron engine） */
  findById(id: string) {
    return getDb().select().from(cronTasks).where(eq(cronTasks.id, id)).get()
  },

  /**
   * 读取 heartbeat 标记，用于删除前的保护判定。
   * 返回 is_heartbeat 值（0/1），不存在则 undefined。
   */
  findHeartbeatFlagByIdAndOwner(id: string, userId: string): number | undefined {
    const row = getDb()
      .select({ isHeartbeat: cronTasks.isHeartbeat })
      .from(cronTasks)
      .where(and(eq(cronTasks.id, id), eq(cronTasks.ownerUserId, userId)))
      .get()
    return row?.isHeartbeat
  },

  /** 创建任务，返回创建后的完整行 */
  create(data: {
    id: string
    name?: string
    schedule?: string
    action?: string
    actionType?: 'run-agent' | 'run-skill' | 'custom-prompt'
    agentName?: string
    skillName?: string
    workspaceId?: string
    enabled?: number
    config?: string
    webhookEnabled?: number
    ownerUserId: string
  }) {
    getDb()
      .insert(cronTasks)
      .values({
        id: data.id,
        name: data.name ?? 'New Task',
        schedule: data.schedule ?? '',
        action: data.action ?? '',
        actionType: data.actionType ?? 'custom-prompt',
        agentName: data.agentName ?? '',
        skillName: data.skillName ?? '',
        workspaceId: data.workspaceId ?? '',
        enabled: data.enabled ?? 1,
        config: data.config ?? '{}',
        webhookEnabled: data.webhookEnabled ?? 0,
        ownerUserId: data.ownerUserId,
      })
      .run()
    return this.findById(data.id)
  },

  /**
   * 动态字段更新（PATCH）。仅允许白名单字段，自动刷新 updated_at。
   * 返回更新后的完整行。
   */
  updateFields(id: string, userId: string, fields: CronTaskUpdatable) {
    getDb()
      .update(cronTasks)
      .set({ ...fields, updatedAt: nowExpr() })
      .where(and(eq(cronTasks.id, id), eq(cronTasks.ownerUserId, userId)))
      .run()
    return this.findByIdAndOwner(id, userId)
  },

  /**
   * 刷新最近一次执行信息。
   * - lastRunAt 省略时使用 datetime('now')
   * - lastRunResult 截断等由调用方负责
   */
  updateLastRun(id: string, lastRunResult: string, lastRunAt?: string) {
    getDb()
      .update(cronTasks)
      .set({
        lastRunAt: lastRunAt ?? nowExpr(),
        lastRunResult,
        updatedAt: nowExpr(),
      })
      .where(eq(cronTasks.id, id))
      .run()
  },

  /** 启用/禁用任务（cron engine 自动停用一次性任务、PATCH 切换启用态） */
  setEnabled(id: string, enabled: 0 | 1) {
    getDb()
      .update(cronTasks)
      .set({ enabled, updatedAt: nowExpr() })
      .where(eq(cronTasks.id, id))
      .run()
  },

  /**
   * 列出所有启用的常规 cron 任务（排除 heartbeat 与 webhook 任务）。
   * 供 cron engine tick 轮询使用。
   */
  listEnabledCronTasks() {
    return getDb()
      .select()
      .from(cronTasks)
      .where(
        and(
          eq(cronTasks.enabled, 1),
          eq(cronTasks.isHeartbeat, 0),
          eq(cronTasks.webhookEnabled, 0),
        ),
      )
      .all()
  },

  /**
   * 按 id + owner 删除任务：事务级联删 task_executions（替代原隐式清理）。
   * heartbeat 保护由调用方在调用前用 findHeartbeatFlagByIdAndOwner 判定。
   */
  deleteByIdAndOwner(id: string, userId: string) {
    getDb().transaction((tx) => {
      tx.delete(taskExecutions).where(eq(taskExecutions.taskId, id)).run()
      tx.delete(cronTasks)
        .where(and(eq(cronTasks.id, id), eq(cronTasks.ownerUserId, userId)))
        .run()
    })
  },
}
