import { query, withTransaction } from '../../db/client.js'
import type { WorkerSessionRow } from './types.js'

export type CreateWorkerSessionInput = {
  sessionId: string
  workerId: number
  deviceId: string
  deviceType: string
  deviceName: string
  userAgent: string
  ipAddress: string
  issuedAt: string
  expiresAt: string
  now: string
  maxDevices: number
}

export type CreateWorkerSessionResult = {
  created: boolean
  activeSessions: WorkerSessionRow[]
  session: WorkerSessionRow | null
}

export async function createWorkerSessionRecord(
  input: CreateWorkerSessionInput,
): Promise<CreateWorkerSessionResult> {
  return withTransaction(async (client) => {
    // 对账号加行锁，避免并发登录同时绕过设备数量限制。
    await client.query('SELECT id FROM worker_users WHERE id = $1 FOR UPDATE', [input.workerId])
    await client.query(
      `UPDATE worker_sessions
       SET status = 'revoked', revoked_at = $2, updated_at = $2
       WHERE worker_id = $1 AND status = 'active' AND expires_at <= $2`,
      [input.workerId, input.now],
    )
    await client.query(
      `UPDATE worker_sessions
       SET status = 'revoked', revoked_at = $3, updated_at = $3
       WHERE worker_id = $1 AND device_id = $2 AND status = 'active'`,
      [input.workerId, input.deviceId, input.now],
    )
    const activeResult = await client.query<WorkerSessionRow>(
      `SELECT * FROM worker_sessions
       WHERE worker_id = $1 AND device_type = $2 AND status = 'active' AND expires_at > $3
       ORDER BY last_seen_at DESC, id DESC`,
      [input.workerId, input.deviceType, input.now],
    )
    const activeSessions = activeResult.rows
    if (activeSessions.length >= input.maxDevices) {
      return { created: false, activeSessions, session: null }
    }
    const result = await client.query<WorkerSessionRow>(
      `INSERT INTO worker_sessions (
         session_id, worker_id, device_id, device_type, device_name,
         user_agent, ip_address, status, issued_at, last_seen_at,
         expires_at, created_at, updated_at
       ) VALUES ($1, $2, $3, $4, $5, $6, $7, 'active', $8, $8, $9, $10, $10)
       RETURNING *`,
      [
        input.sessionId,
        input.workerId,
        input.deviceId,
        input.deviceType,
        input.deviceName,
        input.userAgent,
        input.ipAddress,
        input.issuedAt,
        input.expiresAt,
        input.now,
      ],
    )
    return { created: true, activeSessions, session: result.rows[0] || null }
  })
}

export async function getWorkerSessionBySessionId(
  sessionId: string,
): Promise<WorkerSessionRow | null> {
  const result = await query<WorkerSessionRow>(
    'SELECT * FROM worker_sessions WHERE session_id = $1 LIMIT 1',
    [String(sessionId || '').trim()],
  )
  return result.rows[0] || null
}

export async function touchWorkerSession(sessionId: string, now: string): Promise<boolean> {
  const result = await query(
    `UPDATE worker_sessions
     SET last_seen_at = $2, updated_at = $2
     WHERE session_id = $1 AND status = 'active' AND expires_at > $2`,
    [String(sessionId || '').trim(), now],
  )
  return (result.rowCount || 0) > 0
}

export async function revokeWorkerSession(
  workerId: number | string,
  sessionId: string,
  now: string,
): Promise<boolean> {
  const result = await query(
    `UPDATE worker_sessions
     SET status = 'revoked', revoked_at = $3, updated_at = $3
     WHERE worker_id = $1 AND session_id = $2 AND status = 'active'`,
    [Number(workerId), String(sessionId || '').trim(), now],
  )
  return (result.rowCount || 0) > 0
}

export async function revokeAllWorkerSessions(
  workerId: number | string,
  now: string,
): Promise<number> {
  const result = await query(
    `UPDATE worker_sessions
     SET status = 'revoked', revoked_at = $2, updated_at = $2
     WHERE worker_id = $1 AND status = 'active'`,
    [Number(workerId), now],
  )
  return result.rowCount || 0
}

export async function listWorkerSessions(
  workerId: number | string,
  now: string,
): Promise<WorkerSessionRow[]> {
  await query(
    `UPDATE worker_sessions
     SET status = 'revoked', revoked_at = $2, updated_at = $2
     WHERE worker_id = $1 AND status = 'active' AND expires_at <= $2`,
    [Number(workerId), now],
  )
  const result = await query<WorkerSessionRow>(
    `SELECT * FROM worker_sessions
     WHERE worker_id = $1 AND status = 'active' AND expires_at > $2
     ORDER BY device_type ASC, last_seen_at DESC, id DESC`,
    [Number(workerId), now],
  )
  return result.rows
}
