import { getTaskById } from '../../repositories/task-repo.js'
import { listTaskInventoryBindingSummariesByTaskIds } from '../../repositories/task-inventory-binding-repo.js'
import { createHttpError } from '../../utils/http.js'
import { safeParseJson } from './admin-query-utils.js'
import {
  createAdminViewerContext,
  getTaskPrimaryClaimTokenId,
  getTaskPrimaryInventoryItemId,
  parseTaskContext,
} from './admin-read-shared-helpers.js'

import type {
  AdminAgisoAutoDeliveryStatus,
  AdminTaskBindingSummary,
  AdminTaskListItem,
} from '../../types/admin-read-models.js'
import type { AdminTaskActionPayload } from '../../types/admin-write-models.js'
import type {
  OrderRow,
  TaskEventRow,
  TaskInventoryBindingRow,
  TaskInventoryBindingSummaryRow,
  TaskRow,
} from '../../types/repository-rows.js'
import type { AdminViewerContext } from './admin-read-shared-helpers.js'

type JsonRecord = Record<string, any>

type TaskBindingState = {
  systemBindingStatus: string
  userBindingStatus: string
}

type TaskInventoryBindingLike = TaskInventoryBindingRow & {
  inventory_item_status?: string
}

type OrderBindingSummary = {
  totalTaskCount: number
  systemBoundTaskCount: number
  completedBindingTaskCount: number
  totalBindingCount: number
  reservedBindingCount: number
  consumedBindingCount: number
  releasedBindingCount: number
  systemBindingStatus: string
  userBindingStatus: string
}

type OrderAgisoAutoDeliverySummary = AdminAgisoAutoDeliveryStatus & {
  sourceTaskId: number | null
  sourceTaskNo: string
  totalTaskCount: number
  deliveredTaskCount: number
}

type OrderAgisoAutoDeliveryCandidate = AdminAgisoAutoDeliveryStatus & {
  sourceTaskId: number | null
  sourceTaskNo: string
}

export function mapAdminTaskSummary(
  task: TaskRow,
  bindingSummary: AdminTaskBindingSummary = createEmptyTaskBindingSummary(),
): JsonRecord {
  const binding = buildTaskBindingState(task)
  const taskContext = parseTaskContext(task)

  return {
    taskId: task.id,
    taskNo: task.task_no,
    deliveryStatus: task.delivery_status || '',
    status: task.task_status,
    systemBindingStatus: binding.systemBindingStatus,
    userBindingStatus: binding.userBindingStatus,
    loginType: task.login_type,
    browserSessionId: task.browser_session_id,
    claimedAt: task.claimed_at,
    roleConfirmedAt: task.role_confirmed_at,
    redeemedAt: task.redeemed_at,
    lastError: task.last_error,
    retryCount: getTaskRetryCount(task),
    bindingSummary,
    agisoAutoDelivery: mapAgisoAutoDeliveryContext(taskContext.agisoAutoDelivery),
    createdAt: task.created_at,
    updatedAt: task.updated_at,
  }
}

export function mapTaskActionPayload(task: any): AdminTaskActionPayload {
  const inventoryItemId = getTaskPrimaryInventoryItemId(task)
  const primaryClaimTokenId = getTaskPrimaryClaimTokenId(task)

  return {
    taskId: task.id,
    taskNo: task.task_no,
    status: task.task_status,
    deliveryStatus: task.delivery_status,
    resultCode: task.result_code,
    resultMessage: task.result_message,
    inventoryItemId,
    primaryClaimTokenId,
    lastError: task.last_error,
    updatedAt: task.updated_at,
  }
}

export async function getRequiredTask(taskId: number | string): Promise<TaskRow> {
  const task = await getTaskById(Number(taskId))

  if (!task) {
    throw createHttpError('任务不存在', {
      statusCode: 404,
      errorCode: 'admin_task_not_found',
    })
  }

  return task
}

export function mapAdminTaskListItem(
  task: TaskRow,
  bindingSummary: AdminTaskBindingSummary = createEmptyTaskBindingSummary(),
  viewerContext: AdminViewerContext = createAdminViewerContext(),
): AdminTaskListItem {
  const binding = buildTaskBindingState(task)
  const taskContext = parseTaskContext(task)

  return {
    taskId: task.id,
    taskNo: task.task_no,
    platformOrderId: task.platform_order_id,
    skuCode: task.sku_code || '',
    skuName: task.sku_name || '',
    status: task.task_status,
    executorKey: task.executor_key || '',
    deliveryStatus: task.delivery_status || '',
    resultCode: task.result_code || '',
    resultMessage: task.result_message || '',
    systemBindingStatus: binding.systemBindingStatus,
    userBindingStatus: binding.userBindingStatus,
    loginType: task.login_type,
    roleName: task.role_name,
    roleId: task.role_id,
    browserSessionId: task.browser_session_id,
    claimedAt: task.claimed_at,
    roleConfirmedAt: task.role_confirmed_at,
    redeemedAt: task.redeemed_at,
    retryCount: getTaskRetryCount(task),
    bindingSummary,
    agisoAutoDelivery: mapAgisoAutoDeliveryContext(taskContext.agisoAutoDelivery),
    lastError: task.last_error,
    createdAt: task.created_at,
    updatedAt: task.updated_at,
    inventoryDisplayMasked: viewerContext.canViewSensitiveTaskData ? maskCode(task.primary_inventory_display_value) : '',
    inventoryCredentialType: String(task.primary_inventory_credential_type || '').trim(),
    claimToken: viewerContext.canViewSensitiveTaskData ? (task.primary_claim_token || task.claim_token || '') : '',
    screenshotPath: viewerContext.role === 'support' ? '' : (task.screenshot_path || ''),
  }
}

export function mapAdminTaskEvent(event: TaskEventRow): JsonRecord {
  const payload = safeParseJson(event.payload_json)

  return {
    eventId: event.id,
    eventType: String(event.event_type || '').trim(),
    payload: normalizeRecord(payload),
    createdAt: event.created_at,
  }
}

export function createEmptyTaskBindingSummary(): AdminTaskBindingSummary {
  return {
    totalBindingCount: 0,
    reservedBindingCount: 0,
    consumedBindingCount: 0,
    releasedBindingCount: 0,
    roleKeys: [],
  }
}

export async function getTaskBindingSummaryMap(taskIds: Array<number | string> = []): Promise<Map<number, AdminTaskBindingSummary>> {
  const rows = await listTaskInventoryBindingSummariesByTaskIds(taskIds)
  const output = new Map<number, AdminTaskBindingSummary>()

  for (const row of rows as TaskInventoryBindingSummaryRow[]) {
    output.set(Number(row.task_id), {
      totalBindingCount: Number(row.total_binding_count || 0),
      reservedBindingCount: Number(row.reserved_binding_count || 0),
      consumedBindingCount: Number(row.consumed_binding_count || 0),
      releasedBindingCount: Number(row.released_binding_count || 0),
      roleKeys: Array.isArray(row.role_keys)
        ? row.role_keys.map((value) => String(value || '').trim()).filter(Boolean)
        : [],
    })
  }

  return output
}

export function getTaskBindingSummary(
  summaryMap: Map<number, AdminTaskBindingSummary>,
  taskId: number | string,
): AdminTaskBindingSummary {
  return summaryMap.get(Number(taskId)) || createEmptyTaskBindingSummary()
}

export function createTaskBindingSummaryFromBindings(
  bindings: Array<Partial<TaskInventoryBindingRow>> | null | undefined = [],
): AdminTaskBindingSummary {
  const normalizedBindings = Array.isArray(bindings) ? bindings : []
  const roleKeys = Array.from(new Set(normalizedBindings
    .map((binding) => String(binding?.role_key || '').trim())
    .filter(Boolean)))

  return {
    totalBindingCount: normalizedBindings.length,
    reservedBindingCount: normalizedBindings.filter((binding) => String(binding?.binding_status || '') === 'reserved').length,
    consumedBindingCount: normalizedBindings.filter((binding) => String(binding?.binding_status || '') === 'consumed').length,
    releasedBindingCount: normalizedBindings.filter((binding) => String(binding?.binding_status || '') === 'released').length,
    roleKeys,
  }
}

export function mapAdminTaskInventoryBinding(
  binding: TaskInventoryBindingLike,
  task: TaskRow,
  viewerContext: AdminViewerContext = createAdminViewerContext(),
): JsonRecord {
  const metadata = safeParseJson(binding.metadata_json)

  return {
    bindingId: binding.id,
    inventoryItemId: binding.inventory_item_id,
    roleKey: String(binding.role_key || '').trim(),
    quantity: Math.max(1, Number(binding.quantity || 1)),
    bindingStatus: String(binding.binding_status || '').trim(),
    inventoryStatus: String(binding.inventory_item_status || '').trim(),
    skuCode: String(binding.sku_code || '').trim(),
    batchNo: String(binding.batch_no || '').trim(),
    credentialType: String(binding.credential_type || 'tencent_code').trim() || 'tencent_code',
    displayValue: viewerContext.canViewSensitiveTaskData ? String(binding.display_value || '').trim() : '',
    invalidReason: String(binding.invalid_reason || '').trim(),
    consumedAt: binding.consumed_at || null,
    releasedAt: binding.released_at || null,
    createdAt: binding.created_at,
    updatedAt: binding.updated_at,
    metadata: normalizeRecord(metadata),
    isPrimary: Number(binding.inventory_item_id || 0) === getTaskPrimaryInventoryItemId(task),
    canRelease: viewerContext.canManageSensitiveInventory && canReleaseTaskInventoryBinding(task, binding),
  }
}

export function buildOrderBindingSummary(
  tasks: TaskRow[] | null | undefined,
  taskBindingSummaryMap: Map<number, AdminTaskBindingSummary> = new Map(),
): OrderBindingSummary {
  const normalizedTasks = Array.isArray(tasks) ? tasks : []
  const totalTaskCount = normalizedTasks.length
  const taskBindings = normalizedTasks.map((task) => buildTaskBindingState(task))
  const systemBoundTaskCount = normalizedTasks.filter((task) => isTaskSystemBound(task)).length
  const completedBindingTaskCount = normalizedTasks.filter((task) => String(task?.task_status || '') === 'redeemed').length
  const bindingSummaries = normalizedTasks.map((task) => getTaskBindingSummary(taskBindingSummaryMap, task.id))
  const totalBindingCount = bindingSummaries.reduce((sum, item) => sum + item.totalBindingCount, 0)
  const reservedBindingCount = bindingSummaries.reduce((sum, item) => sum + item.reservedBindingCount, 0)
  const consumedBindingCount = bindingSummaries.reduce((sum, item) => sum + item.consumedBindingCount, 0)
  const releasedBindingCount = bindingSummaries.reduce((sum, item) => sum + item.releasedBindingCount, 0)

  let systemBindingStatus = 'pending_binding'
  let userBindingStatus = 'not_started'

  if (totalTaskCount === 0) {
    return {
      totalTaskCount,
      systemBoundTaskCount,
      completedBindingTaskCount,
      totalBindingCount,
      reservedBindingCount,
      consumedBindingCount,
      releasedBindingCount,
      systemBindingStatus,
      userBindingStatus,
    }
  }

  if (normalizedTasks.every((task) => String(task.task_status || '') === 'redeemed')) {
    systemBindingStatus = 'system_bound'
    userBindingStatus = 'binding_completed'
  } else if (taskBindings.some((item) => ['binding_in_progress', 'binding_confirmed', 'link_opened'].includes(item.userBindingStatus))) {
    systemBindingStatus = systemBoundTaskCount > 0 ? 'system_bound' : 'pending_binding'
    userBindingStatus = 'user_binding'
  } else if (taskBindings.some((item) => item.userBindingStatus === 'waiting_user_claim')) {
    systemBindingStatus = systemBoundTaskCount > 0 ? 'system_bound' : 'pending_binding'
    userBindingStatus = 'waiting_user_claim'
  } else if (taskBindings.some((item) => item.userBindingStatus === 'binding_exception')) {
    systemBindingStatus = systemBoundTaskCount > 0 ? 'system_bound' : 'pending_binding'
    userBindingStatus = 'binding_exception'
  } else if (systemBoundTaskCount > 0) {
    systemBindingStatus = 'system_bound'
  } else if (taskBindings.some((item) => ['manual_review', 'retry_pending', 'waiting_inventory'].includes(item.systemBindingStatus))) {
    systemBindingStatus = 'binding_exception'
  }

  return {
    totalTaskCount,
    systemBoundTaskCount,
    completedBindingTaskCount,
    totalBindingCount,
    reservedBindingCount,
    consumedBindingCount,
    releasedBindingCount,
    systemBindingStatus,
    userBindingStatus,
  }
}

export function buildOrderAgisoAutoDeliverySummary(
  order: Partial<OrderRow> | null | undefined,
  tasks: TaskRow[] = [],
): OrderAgisoAutoDeliverySummary | null {
  if (String(order?.provider || '').trim() !== 'agiso' || String(order?.platform || '').trim() !== 'xianyu') {
    return null
  }

  const normalizedTasks = Array.isArray(tasks) ? tasks.filter(Boolean) : []
  const totalTaskCount = normalizedTasks.length
  const deliveredTaskCount = normalizedTasks.filter((task) => String(task?.delivery_status || '').trim() === 'delivered').length
  const latest = normalizedTasks.reduce<OrderAgisoAutoDeliveryCandidate | null>((best, task) => {
    const autoDelivery = mapAgisoAutoDeliveryContext(parseTaskContext(task).agisoAutoDelivery)

    if (!autoDelivery) {
      return best
    }

    const candidate = {
      ...autoDelivery,
      sourceTaskId: Number(task.id || 0) || null,
      sourceTaskNo: String(task.task_no || '').trim(),
    }
    const candidateTime = Date.parse(String(candidate.updatedAt || task.updated_at || ''))
    const bestTime = Date.parse(String(best?.updatedAt || ''))

    if (!best || (Number.isFinite(candidateTime) && (!Number.isFinite(bestTime) || candidateTime >= bestTime))) {
      return candidate
    }

    return best
  }, null)

  if (latest) {
    return {
      ...latest,
      totalTaskCount,
      deliveredTaskCount,
    }
  }

  return {
    status: totalTaskCount === 0 ? 'not_started' : deliveredTaskCount >= totalTaskCount ? 'pending' : 'waiting',
    trigger: '',
    reason: deliveredTaskCount >= totalTaskCount ? '' : 'waiting_other_tasks',
    platformOrderId: String(order?.platform_order_id || '').trim(),
    responseStatus: 0,
    errorMessage: '',
    requestId: '',
    updatedAt: null,
    sourceTaskId: null,
    sourceTaskNo: '',
    totalTaskCount,
    deliveredTaskCount,
  }
}

function canReleaseTaskInventoryBinding(task: TaskRow | null | undefined, binding: TaskInventoryBindingLike | null | undefined): boolean {
  if (!task || !binding) {
    return false
  }

  if (String(binding.binding_status || '').trim() !== 'reserved') {
    return false
  }

  return !['redeemed', 'expired'].includes(String(task.task_status || '').trim())
}

function buildTaskBindingState(task: TaskRow | null | undefined): TaskBindingState {
  const normalizedStatus = String(task?.task_status || '').trim()

  if (!normalizedStatus) {
    return {
      systemBindingStatus: 'pending_binding',
      userBindingStatus: 'not_started',
    }
  }

  if (normalizedStatus === 'pending_payment') {
    return { systemBindingStatus: 'pending_payment', userBindingStatus: 'not_started' }
  }

  if (normalizedStatus === 'paid') {
    return { systemBindingStatus: 'pending_binding', userBindingStatus: 'not_started' }
  }

  if (normalizedStatus === 'waiting_inventory') {
    return { systemBindingStatus: 'waiting_inventory', userBindingStatus: 'not_started' }
  }

  if (normalizedStatus === 'pending_binding_prepare') {
    return { systemBindingStatus: 'pending_binding', userBindingStatus: 'not_started' }
  }

  if (normalizedStatus === 'waiting_binding') {
    return { systemBindingStatus: 'system_bound', userBindingStatus: 'waiting_user_claim' }
  }

  if (normalizedStatus === 'dispatched_pending_return') {
    return { systemBindingStatus: 'system_bound', userBindingStatus: 'binding_completed' }
  }

  if (normalizedStatus === 'completed') {
    return { systemBindingStatus: 'system_bound', userBindingStatus: 'binding_completed' }
  }

  if (normalizedStatus === 'manual_review') {
    return { systemBindingStatus: 'manual_review', userBindingStatus: 'binding_exception' }
  }

  if (normalizedStatus === 'retry_pending') {
    return { systemBindingStatus: 'retry_pending', userBindingStatus: 'binding_exception' }
  }

  if (normalizedStatus === 'closed') {
    return { systemBindingStatus: 'closed', userBindingStatus: 'closed' }
  }

  if (normalizedStatus === 'expired') {
    return { systemBindingStatus: 'expired', userBindingStatus: 'expired' }
  }

  if (normalizedStatus === 'link_generated') {
    return { systemBindingStatus: 'system_bound', userBindingStatus: 'waiting_user_claim' }
  }

  if (normalizedStatus === 'claimed') {
    return { systemBindingStatus: 'system_bound', userBindingStatus: 'link_opened' }
  }

  if (normalizedStatus === 'role_confirmed') {
    return { systemBindingStatus: 'system_bound', userBindingStatus: 'binding_confirmed' }
  }

  if (normalizedStatus === 'redeeming') {
    return { systemBindingStatus: 'system_bound', userBindingStatus: 'binding_in_progress' }
  }

  if (normalizedStatus === 'redeemed') {
    return { systemBindingStatus: 'system_bound', userBindingStatus: 'binding_completed' }
  }

  if (isTaskSystemBound(task)) {
    return { systemBindingStatus: 'system_bound', userBindingStatus: 'waiting_user_claim' }
  }

  return { systemBindingStatus: 'pending_binding', userBindingStatus: 'not_started' }
}

function isTaskSystemBound(task: TaskRow | null | undefined): boolean {
  return Boolean(task && (getTaskPrimaryInventoryItemId(task) || getTaskPrimaryClaimTokenId(task)))
}

function mapAgisoAutoDeliveryContext(value: unknown): AdminAgisoAutoDeliveryStatus | null {
  if (!value || typeof value !== 'object') {
    return null
  }

  const record = value as JsonRecord
  return {
    status: String(record.status || '').trim(),
    trigger: String(record.trigger || '').trim(),
    reason: String(record.reason || '').trim(),
    platformOrderId: String(record.platformOrderId || '').trim(),
    responseStatus: Number(record.responseStatus || 0),
    errorMessage: String(record.errorMessage || '').trim(),
    requestId: String(record.requestId || '').trim(),
    updatedAt: record.updatedAt || null,
  }
}

function normalizeRecord(value: unknown): JsonRecord {
  return value && typeof value === 'object' && !Array.isArray(value) ? value : {}
}

function maskCode(value: unknown): string {
  const text = String(value || '').trim()
  if (!text) {
    return ''
  }
  if (text.length <= 8) {
    return `${text.slice(0, 2)}****${text.slice(-2)}`
  }
  return `${text.slice(0, 4)}****${text.slice(-4)}`
}

function getTaskRetryCount(task: TaskRow | null | undefined): number {
  return Number(task?.attempt_count || 0)
}
