import type { PoolClient } from 'pg'

import { query, withTransaction } from '../../db/client.js'
import { createWorkOrderEventWithClient } from './work-order-event-repo.js'
import { getWorkOrderByIdWithClient } from './work-order-repo.js'
import type { WorkerOrderFeedbackRow, WorkOrderRow, WorkOrderShareRow } from './types.js'

const WORKER_ORDER_FEEDBACK_SELECT = `
  SELECT
    wf.*,
    COALESCE(NULLIF(BTRIM(wo.platform_order_id), ''), wo.work_order_no) AS work_order_no,
    wo.product_name,
    COALESCE(
      NULLIF(BTRIM(o.shop_name), ''),
      NULLIF(BTRIM(o.shop_id), ''),
      NULLIF(BTRIM(ft.shop_name), ''),
      NULLIF(BTRIM(ft.shop_id), ''),
      ''
    ) AS shop_name,
    wu.username AS worker_username,
    wu.display_name AS worker_display_name,
    wos.quantity AS share_quantity
  FROM worker_order_feedbacks wf
  INNER JOIN work_orders wo ON wo.id = wf.work_order_id
  LEFT JOIN orders o ON o.id = wo.order_id
  LEFT JOIN fulfillment_tasks ft ON ft.id = wo.task_id
  INNER JOIN worker_users wu ON wu.id = wf.worker_id
  LEFT JOIN work_order_shares wos ON wos.id = wf.work_order_share_id
`

async function getWorkerOrderFeedbackByIdWithClient(
  client: PoolClient,
  feedbackId: number | string,
): Promise<WorkerOrderFeedbackRow | null> {
  const result = await client.query<WorkerOrderFeedbackRow>(
    `${WORKER_ORDER_FEEDBACK_SELECT} WHERE wf.id = $1 LIMIT 1`,
    [Number(feedbackId)],
  )
  return result.rows[0] || null
}

/** 批量查询打手在各工单上未处理的问题反馈，用于订单角标与问题单归类。 */
export async function getPendingFeedbackOrderIds(
  workerId: number,
  workOrderIds: number[],
): Promise<Set<number>> {
  if (workOrderIds.length === 0) return new Set()
  const result = await query<{ work_order_id: number }>(
    `
      SELECT work_order_id
      FROM worker_order_feedbacks
      WHERE worker_id = $1 AND work_order_id = ANY($2::bigint[]) AND status = 'pending'
    `,
    [Number(workerId), workOrderIds],
  )
  return new Set(result.rows.map((row) => Number(row.work_order_id)))
}

export async function createWorkerOrderFeedback(input: {
  workOrderId: number
  workerId: number
  content: string
  now: string
}): Promise<{ feedback: WorkerOrderFeedbackRow | null; failureReason: 'owner_required' | null }> {
  return withTransaction(async (client) => {
    const orderResult = await client.query<WorkOrderRow>(
      'SELECT * FROM work_orders WHERE id = $1 FOR UPDATE',
      [input.workOrderId],
    )
    const order = orderResult.rows[0] || null
    if (!order) return { feedback: null, failureReason: 'owner_required' }

    const shareResult = await client.query<WorkOrderShareRow>(
      `SELECT * FROM work_order_shares
       WHERE work_order_id = $1 AND worker_id = $2 AND status != 'cancelled'
       FOR UPDATE`,
      [input.workOrderId, input.workerId],
    )
    const share = shareResult.rows[0] || null
    const isOrderOwner =
      Number(order.assigned_worker_id || 0) === input.workerId ||
      Number(order.last_assigned_worker_id || 0) === input.workerId
    if (!share && !isOrderOwner) return { feedback: null, failureReason: 'owner_required' }

    const result = await client.query<{ id: number }>(
      `INSERT INTO worker_order_feedbacks (
         work_order_id, work_order_share_id, worker_id, content, status, created_at, updated_at
       ) VALUES ($1, $2, $3, $4, 'pending', $5, $5)
       RETURNING id`,
      [input.workOrderId, share?.id || null, input.workerId, input.content, input.now],
    )
    const feedbackId = Number(result.rows[0]?.id || 0)
    await createWorkOrderEventWithClient(client, {
      workOrderId: input.workOrderId,
      actorType: 'worker',
      actorId: String(input.workerId),
      eventType: 'worker_feedback_submitted',
      fromStatus: order.status,
      toStatus: order.status,
      payloadJson: JSON.stringify({
        feedbackId,
        shareId: share?.id || null,
        content: input.content,
      }),
      now: input.now,
    })
    return {
      feedback: await getWorkerOrderFeedbackByIdWithClient(client, feedbackId),
      failureReason: null,
    }
  })
}

export async function listWorkerOrderFeedbacks(
  workerId: number | string,
): Promise<WorkerOrderFeedbackRow[]> {
  const result = await query<WorkerOrderFeedbackRow>(
    `${WORKER_ORDER_FEEDBACK_SELECT}
     WHERE wf.worker_id = $1
     ORDER BY wf.id DESC
     LIMIT 100`,
    [Number(workerId)],
  )
  return result.rows
}

export async function listAdminWorkerOrderFeedbacks(
  status = 'pending',
): Promise<WorkerOrderFeedbackRow[]> {
  const result = await query<WorkerOrderFeedbackRow>(
    `${WORKER_ORDER_FEEDBACK_SELECT}
     WHERE ($1 = '' OR wf.status = $1)
     ORDER BY wf.id DESC
     LIMIT 200`,
    [status],
  )
  return result.rows
}

export async function resolveWorkerOrderFeedback(input: {
  feedbackId: number
  reply: string
  actorName: string
  now: string
}): Promise<{
  feedback: WorkerOrderFeedbackRow | null
  order: WorkOrderRow | null
  failureReason: 'not_found' | 'not_pending' | null
}> {
  return withTransaction(async (client) => {
    const feedbackResult = await client.query<WorkerOrderFeedbackRow>(
      'SELECT * FROM worker_order_feedbacks WHERE id = $1 FOR UPDATE',
      [input.feedbackId],
    )
    const feedback = feedbackResult.rows[0] || null
    if (!feedback) return { feedback: null, order: null, failureReason: 'not_found' }
    if (feedback.status !== 'pending') {
      return {
        feedback: await getWorkerOrderFeedbackByIdWithClient(client, feedback.id),
        order: null,
        failureReason: 'not_pending',
      }
    }
    const orderResult = await client.query<WorkOrderRow>(
      'SELECT * FROM work_orders WHERE id = $1 FOR UPDATE',
      [feedback.work_order_id],
    )
    const order = orderResult.rows[0] || null
    if (!order) return { feedback: null, order: null, failureReason: 'not_found' }
    await client.query(
      `UPDATE worker_order_feedbacks
       SET status = 'resolved', reply = $1, handled_by = $2, handled_at = $3, updated_at = $3
       WHERE id = $4`,
      [input.reply, input.actorName, input.now, feedback.id],
    )
    await createWorkOrderEventWithClient(client, {
      workOrderId: Number(order.id),
      actorType: 'admin',
      actorId: input.actorName,
      eventType: 'worker_feedback_resolved',
      fromStatus: order.status,
      toStatus: order.status,
      payloadJson: JSON.stringify({ feedbackId: feedback.id, reply: input.reply }),
      now: input.now,
    })
    return {
      feedback: await getWorkerOrderFeedbackByIdWithClient(client, feedback.id),
      order: await getWorkOrderByIdWithClient(client, order.id),
      failureReason: null,
    }
  })
}
