import test from 'node:test'
import assert from 'node:assert/strict'

import { runtimeConfig } from '../../../../config/runtime.js'
import {
  hasAgisoAutoDeliverySucceeded,
  ensureAgisoXianyuAutoDeliveryForDeliveredTaskWithDeps,
  isOrderReadyForAgisoAutoDelivery,
  isAgisoAutoDeliverySuccess,
  resolveAgisoAutoDeliveryEndpoint,
  resolveAgisoAutoDeliveryErrorMessage,
} from './auto-delivery-service.js'

const agisoOrder = {
  id: 101,
  provider: 'agiso',
  platform: 'xianyu',
  shop_id: 'shop-auto-delivery-test',
  shop_name: '自动发货测试店',
  platform_order_id: 'P-AUTO-10001',
}

function createDeliveredTask(patch = {}) {
  return {
    id: 201,
    order_id: agisoOrder.id,
    task_status: 'completed',
    delivery_status: 'delivered',
    context_json: '{}',
    ...patch,
  }
}

test('isOrderReadyForAgisoAutoDelivery requires every task to be delivered', () => {
  assert.equal(isOrderReadyForAgisoAutoDelivery([]), false)
  assert.equal(isOrderReadyForAgisoAutoDelivery([
    { delivery_status: 'delivered' },
    { delivery_status: 'delivered' },
  ]), true)
  assert.equal(isOrderReadyForAgisoAutoDelivery([
    { delivery_status: 'delivered' },
    { delivery_status: 'processing' },
  ]), false)
})

test('hasAgisoAutoDeliverySucceeded detects successful context on any task', () => {
  assert.equal(hasAgisoAutoDeliverySucceeded([
    { context_json: {} },
    { context_json: { agisoAutoDelivery: { status: 'success' } } },
  ]), true)

  assert.equal(hasAgisoAutoDeliverySucceeded([
    { context_json: { agisoAutoDelivery: { status: 'failed' } } },
  ]), false)
})

test('hasAgisoAutoDeliverySucceeded handles string and invalid task context payloads', () => {
  assert.equal(hasAgisoAutoDeliverySucceeded([
    { context_json: '{bad-json' },
    { context_json: JSON.stringify({ agisoAutoDelivery: { status: 'success' } }) },
  ]), true)

  assert.equal(hasAgisoAutoDeliverySucceeded([
    { context_json: '{bad-json' },
    { context_json: JSON.stringify({ agisoAutoDelivery: { status: 'skipped' } }) },
  ]), false)
})

test('isAgisoAutoDeliverySuccess accepts empty successful payloads and explicit success codes', () => {
  assert.equal(isAgisoAutoDeliverySuccess(200, {}), true)
  assert.equal(isAgisoAutoDeliverySuccess(200, { IsSuccess: true }), true)
  assert.equal(isAgisoAutoDeliverySuccess(200, { Error_Code: 0 }), true)
  assert.equal(isAgisoAutoDeliverySuccess(500, { IsSuccess: true }), false)
  assert.equal(isAgisoAutoDeliverySuccess(200, { Error_Code: 500 }), false)
})

test('resolveAgisoAutoDeliveryErrorMessage prefers structured payload message before raw text', () => {
  assert.equal(
    resolveAgisoAutoDeliveryErrorMessage(
      { Error_Msg: '库存不足' },
      'raw body',
      400,
    ),
    '库存不足',
  )

  assert.equal(
    resolveAgisoAutoDeliveryErrorMessage(
      {},
      'fallback raw body',
      400,
    ),
    'fallback raw body',
  )
})

test('resolveAgisoAutoDeliveryEndpoint falls back to DummySend', () => {
  assert.equal(
    resolveAgisoAutoDeliveryEndpoint(''),
    'https://gw-api.agiso.com/aldsIdle/Order/DummySend',
  )

  assert.equal(
    resolveAgisoAutoDeliveryEndpoint('https://gw-api.agiso.com/aldsIdle/Order/DummySend'),
    'https://gw-api.agiso.com/aldsIdle/Order/DummySend',
  )
})

test('ensureAgisoXianyuAutoDeliveryForDeliveredTaskWithDeps skips while other order tasks are not delivered', async () => {
  const calls = {
    update: 0,
    fetch: 0,
  }

  const result = await ensureAgisoXianyuAutoDeliveryForDeliveredTaskWithDeps({
    order: agisoOrder,
    task: createDeliveredTask(),
  }, {
    listTasksByOrderId: async () => [
      createDeliveredTask(),
      createDeliveredTask({ id: 202, delivery_status: 'processing' }),
    ],
    updateTask: async () => {
      calls.update += 1
      return null
    },
    fetch: async () => {
      calls.fetch += 1
      return { status: 200, text: async () => '{}' }
    },
  })

  assert.equal(result.sent, false)
  assert.equal(result.skipped, true)
  assert.equal(result.reason, 'waiting_other_tasks')
  assert.equal(calls.update, 0)
  assert.equal(calls.fetch, 0)
})

test('ensureAgisoXianyuAutoDeliveryForDeliveredTaskWithDeps persists missing config as skipped', async () => {
  const originalAppSecret = runtimeConfig.platforms.agiso.appSecret
  const originalShops = runtimeConfig.platforms.agiso.messaging.shops
  const updates = []
  const events = []

  runtimeConfig.platforms.agiso.appSecret = ''
  runtimeConfig.platforms.agiso.messaging.shops = {}

  try {
    const task = createDeliveredTask({ context_json: JSON.stringify({ existing: true }) })
    const result = await ensureAgisoXianyuAutoDeliveryForDeliveredTaskWithDeps({
      order: {
        ...agisoOrder,
        shop_id: 'missing-auto-delivery-config-shop',
      },
      task,
      trigger: 'unit_test',
    }, {
      listTasksByOrderId: async () => [task],
      updateTask: async (taskId, patch) => {
        updates.push({ taskId, patch })
        return { ...task, ...patch }
      },
      createTaskEvent: async (taskId, eventType, payload, createdAt) => {
        events.push({ taskId, eventType, payload, createdAt })
        return { id: 1 }
      },
      fetch: async () => {
        throw new Error('fetch should not be called without config')
      },
      nowIso: () => '2026-05-21T12:00:00.000Z',
    })

    assert.equal(result.sent, false)
    assert.equal(result.skipped, true)
    assert.equal(result.reason, 'missing_config')
    assert.equal(updates.length, 1)
    assert.equal(events[0]?.eventType, 'agiso_auto_delivery_skipped')

    const context = JSON.parse(updates[0].patch.context_json)
    assert.equal(context.existing, true)
    assert.equal(context.agisoAutoDelivery.status, 'skipped')
    assert.equal(context.agisoAutoDelivery.reason, 'missing_config')
    assert.deepEqual({
      hasEndpoint: context.agisoAutoDelivery.hasEndpoint,
      hasAccessToken: context.agisoAutoDelivery.hasAccessToken,
      hasAppSecret: context.agisoAutoDelivery.hasAppSecret,
    }, {
      hasEndpoint: true,
      hasAccessToken: false,
      hasAppSecret: false,
    })
  } finally {
    runtimeConfig.platforms.agiso.appSecret = originalAppSecret
    runtimeConfig.platforms.agiso.messaging.shops = originalShops
  }
})

test('ensureAgisoXianyuAutoDeliveryForDeliveredTaskWithDeps fails when accepted delivery is not confirmed as shipped', async () => {
  const originalAppSecret = runtimeConfig.platforms.agiso.appSecret
  const originalShops = runtimeConfig.platforms.agiso.messaging.shops
  const updates = []
  const events = []
  const messages = []

  runtimeConfig.platforms.agiso.appSecret = 'runtime-secret'
  runtimeConfig.platforms.agiso.messaging.shops = {
    [agisoOrder.shop_id]: {
      accessToken: 'access-token',
      appSecret: 'shop-secret',
      apiVersion: '1',
    },
  }

  try {
    const task = createDeliveredTask()
    const result = await ensureAgisoXianyuAutoDeliveryForDeliveredTaskWithDeps({
      order: agisoOrder,
      task,
      trigger: 'unit_test',
    }, {
      listTasksByOrderId: async () => [task],
      fetch: async () => ({
        status: 200,
        text: async () => JSON.stringify({ IsSuccess: true, RequestId: 'req-1' }),
      }),
      confirmAgisoXianyuAutoDeliveryShipped: async (input) => ({
        shipped: false,
        orderStatus: 2,
        shipTime: 0,
        reason: `not shipped: ${input.requestId}`,
      }),
      updateTask: async (taskId, patch) => {
        updates.push({ taskId, patch })
        return { ...task, ...patch }
      },
      createTaskEvent: async (taskId, eventType, payload, createdAt) => {
        events.push({ taskId, eventType, payload, createdAt })
        return { id: 2 }
      },
      ensureAgisoXianyuAutoDeliveryMessageDeliveredForTask: async (payload) => {
        messages.push(payload)
        return { sent: true }
      },
      nowIso: () => '2026-05-21T12:01:00.000Z',
    })

    assert.equal(result.sent, false)
    assert.equal(result.skipped, false)
    assert.equal(result.reason, 'delivery_not_confirmed')
    assert.equal(messages.length, 0)
    assert.equal(events[0]?.eventType, 'agiso_auto_delivery_failed')

    const context = JSON.parse(updates[0].patch.context_json)
    assert.equal(context.agisoAutoDelivery.status, 'failed')
    assert.equal(context.agisoAutoDelivery.reason, 'delivery_not_confirmed')
    assert.equal(context.agisoAutoDelivery.requestId, 'req-1')
    assert.equal(context.agisoAutoDelivery.confirmOrderStatus, 2)
    assert.match(context.agisoAutoDelivery.errorMessage, /订单仍未进入已发货/)
  } finally {
    runtimeConfig.platforms.agiso.appSecret = originalAppSecret
    runtimeConfig.platforms.agiso.messaging.shops = originalShops
  }
})
