import crypto from 'crypto'
import { sessionRepo } from '@/lib/database/repositories/session.repo'
import { h5PageRepo } from '@/lib/database/repositories/h5-page.repo'
import type { Session } from '@/lib/database/schema'

/**
 * SQLite datetime('now') 格式 "YYYY-MM-DD HH:MM:SS" 是 UTC 但无时区标记，
 * 前端 new Date 会按本地时区误解析（UTC+8 会偏差 8 小时，表现为「8 小时前」）。
 * 补 T 和 Z 转标准 ISO（带 Z），让前端正确识别为 UTC；解析失败回退原值（兼容异常数据）。
 */
export function toIsoUtc(raw: string): string {
  const d = new Date(raw.replace(' ', 'T') + 'Z')
  return Number.isNaN(d.getTime()) ? raw : d.toISOString()
}

/**
 * H5 Router。
 *
 * 仿 ChannelRouter，但**不落绑定表**：外部身份存在 sessions.external_user_id 列。
 *
 * 安全关键：所有隔离校验必须用 external_user_id，绝不能用 user_id——
 * 同一 H5 页面的所有外部用户 user_id 都是同一个 owner，按 user_id 校验会导致
 * 外部用户 A 传入外部用户 B 的 sessionId 而错误通过校验（跨用户会话泄露）。
 */

/** Session 解析结果 */
export interface H5SessionResolution {
  session: Session
  isNew: boolean
}

/** H5 页面配置的精简视图（避免到处传整个 row 类型） */
export interface H5PageContext {
  id: string
  workspaceId: string
  defaultModel: string
  permissionMode: 'confirm' | 'full'
}

/** 会话越权错误（403） */
export class H5ForbiddenError extends Error {
  constructor(message: string) {
    super(message)
    this.name = 'H5ForbiddenError'
  }
}

export class H5Router {
  /**
   * 解析（或创建）外部用户的会话。
   *
   * - 有 requestedSessionId：校验 external_user_id + workspace 归属，失败抛 403
   * - 无 requestedSessionId：取最近活动会话；无则新建
   *
   * 所有查询都以 external_user_id 为隔离键。
   */
  resolveSession(
    page: H5PageContext,
    externalUserId: string,
    requestedSessionId?: string,
    displayName?: string,
  ): H5SessionResolution {
    if (requestedSessionId) {
      // ⚠️ 必须用 external_user_id 校验，不能用 user_id（安全关键点）
      const session = sessionRepo.findByIdAndExternalUser(
        requestedSessionId,
        externalUserId,
        page.workspaceId,
      )
      if (!session) {
        throw new H5ForbiddenError(
          `Session ${requestedSessionId} not accessible for this external user`,
        )
      }
      return { session, isNew: false }
    }

    const recent = sessionRepo.findRecentByExternalUser(externalUserId, page.workspaceId)
    if (recent) {
      return { session: recent, isNew: false }
    }

    return { session: this.createSession(page, externalUserId, displayName), isNew: true }
  }

  /**
   * 为外部用户新建会话。
   *
   * - user_id 落 owner（与 IM 一致，让 H5 会话自动出现在 owner Web 端会话列表）
   * - external_user_id 落外部身份（隔离键）
   * - 标题前缀 [name]（无 name 时回退 [extuser]）
   */
  createSession(page: H5PageContext, externalUserId: string, displayName?: string): Session {
    const sessionId = crypto.randomUUID()
    const ownerUserId = h5PageRepo.resolveOwnerUserIdByWorkspace(page.workspaceId)

    if (!ownerUserId) {
      throw new Error(`No owner found for workspace ${page.workspaceId}`)
    }

    const created = sessionRepo.create({
      id: sessionId,
      title: `[${displayName || 'extuser'}] New conversation`,
      workspace: page.workspaceId,
      model: page.defaultModel || 'claude-sonnet-4-6',
      userId: ownerUserId,
      externalUserId,
    })
    if (!created) {
      throw new Error(`Failed to create session for external user ${externalUserId}`)
    }
    return created
  }

  /** 列出外部用户的会话（侧栏用）。updatedAt 标准化为 ISO UTC，避免前端时区误解析。 */
  listSessions(externalUserId: string, workspaceId: string) {
    return sessionRepo.listByExternalUser(externalUserId, workspaceId).map((s) => ({
      ...s,
      updatedAt: toIsoUtc(s.updatedAt),
    }))
  }

  /** 删除外部用户的会话（必须同时校验 externalUserId + workspace，防跨用户泄露） */
  deleteSession(id: string, externalUserId: string, workspaceId: string) {
    sessionRepo.deleteByIdAndExternalUser(id, externalUserId, workspaceId)
  }

  /** 重命名外部用户的会话（带归属校验） */
  renameSession(id: string, title: string, externalUserId: string, workspaceId: string) {
    sessionRepo.updateTitleByIdAndExternalUser(id, title, externalUserId, workspaceId)
  }
}

/** 单例 */
export const h5Router = new H5Router()
