import { beforeEach, describe, expect, it, vi } from 'vitest'

import {
  convertReservationManualReviewTask,
  fetchReservationOrderDetail,
  fetchReservationOrders,
  fetchReservationTaskDetail,
  fetchReservationTaskList,
  fetchSourceMessageConversation,
  resolveReservationManualReviewTask,
} from '@/services/reservationService'
import { setReservationHotelIdProvider } from '@/config/reservationConfig'

const jsonHeaders = {
  headers: {
    get: (name: string) => (name.toLowerCase() === 'content-type' ? 'application/json' : null),
  },
}

function mockJsonResponse(payload: unknown): Response {
  return {
    ok: true,
    status: 200,
    json: async () => payload,
    text: async () => JSON.stringify(payload),
    ...jsonHeaders,
  } as Response
}

describe('reservationService real API mode', () => {
  beforeEach(() => {
    vi.restoreAllMocks()
    setReservationHotelIdProvider(null)
  })

  it('fetches the task list from the backend by default', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse({
        items: [
          {
            task_id: '10001',
            order_id: '20001',
            hotel_id: 'HOTEL-TEST',
            display_order_key: 'GRP-001',
            temporary_order_no: null,
            task_type: 'NEW_BOOKING',
            task_subtype: 'NEW_BOOKING',
            task_status: 'PENDING_CONFIRM',
            card_name: 'New Booking',
            queue_sequence: 1,
            queue_participation: true,
            can_process: true,
            readonly_reason_code: null,
            source_message_id: '30001',
            source_subject: 'Booking Request',
            created_at: '2026-07-08T03:00:00Z',
            updated_at: '2026-07-08T03:10:00Z',
          },
        ],
        page: {
          page_num: 1,
          page_size: 20,
          total: 1,
        },
      }),
    )

    const result = await fetchReservationTaskList({
      task_status: 'PENDING_CONFIRM',
      order_status: 'ACTIVE',
      page_num: 1,
      page_size: 20,
    })

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/reservation/tasks?task_status=PENDING_CONFIRM&order_status=ACTIVE&page_num=1&page_size=20',
      expect.objectContaining({ method: 'GET' }),
    )
    expect(result.items).toHaveLength(1)
    expect(result.items[0]?.source_subject).toBe('Booking Request')
  })

  it('passes task subtype and terminal task status filters to the backend', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse({
        items: [],
        page: {
          page_num: 1,
          page_size: 20,
          total: 0,
        },
      }),
    )

    await fetchReservationTaskList({
      task_subtype: 'RATE_CHANGE',
      task_status: 'FAILED',
      page_num: 1,
      page_size: 20,
    })

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/reservation/tasks?task_subtype=RATE_CHANGE&task_status=FAILED&page_num=1&page_size=20',
      expect.objectContaining({ method: 'GET' }),
    )
  })

  it('uses the selected auth hotel when available', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse({
        items: [],
        page: {
          page_num: 1,
          page_size: 20,
          total: 0,
        },
      }),
    )
    setReservationHotelIdProvider(() => 'HOTEL-BKK')

    await fetchReservationTaskList({
      page_num: 1,
      page_size: 20,
    })

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/reservation/tasks?hotel_id=HOTEL-BKK&page_num=1&page_size=20',
      expect.objectContaining({ method: 'GET' }),
    )
  })

  it('fetches the order list from the backend by default', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse({
        items: [
          {
            order_id: '20001',
            hotel_id: 'HOTEL-TEST',
            order_status: 'ACTIVE',
            display_order_key: 'GRP-001',
            temporary_order_no: null,
            confirmation_number: null,
            group_code: 'GRP-001',
            display_name: 'GRP-001',
            open_task_count: 2,
            next_processable_task_id: '10002',
            created_at: '2026-07-08T03:00:00Z',
            updated_at: '2026-07-08T03:10:00Z',
          },
        ],
        page: {
          page_num: 1,
          page_size: 20,
          total: 1,
        },
      }),
    )

    const result = await fetchReservationOrders({
      keyword: 'GRP-001',
      page_num: 1,
      page_size: 20,
    })

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/reservation/orders?keyword=GRP-001&page_num=1&page_size=20',
      expect.objectContaining({ method: 'GET' }),
    )
    expect(result.items[0]?.display_order_key).toBe('GRP-001')
    expect(result.items[0]?.next_processable_task_id).toBe('10002')
  })

  it('passes order status and business-key filters to the backend', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse({
        items: [],
        page: {
          page_num: 2,
          page_size: 10,
          total: 0,
        },
      }),
    )

    await fetchReservationOrders({
      order_status: 'LOGIC_DELETED',
      group_code: 'GRP-001',
      confirmation_number: 'CNF-001',
      keyword: 'VIP',
      page_num: 2,
      page_size: 10,
    })

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/reservation/orders?order_status=LOGIC_DELETED&group_code=GRP-001&confirmation_number=CNF-001&keyword=VIP&page_num=2&page_size=10',
      expect.objectContaining({ method: 'GET' }),
    )
  })

  it('converts a manual review task through the backend endpoint', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse({
        task_id: '10001',
        order_id: '20002',
        original_order_id: '20001',
        system_task_type: 'UPDATE_BOOKING',
        task_card_type: 'UPDATE_BOOKING',
        task_status: 'PENDING_CONFIRM',
        original_order_logic_deleted: true,
      }),
    )

    const result = await convertReservationManualReviewTask('10001', {
      target_task_type: 'UPDATE_BOOKING',
      target_order_id: '20002',
      reason: 'Matched by group code',
    })

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/reservation/tasks/10001/manual-review-conversions',
      expect.objectContaining({
        method: 'POST',
        headers: expect.objectContaining({
          'Content-Type': 'application/json',
        }),
        body: JSON.stringify({
          target_task_type: 'UPDATE_BOOKING',
          target_order_id: '20002',
          reason: 'Matched by group code',
        }),
      }),
    )
    expect(result.system_task_type).toBe('UPDATE_BOOKING')
    expect(result.original_order_logic_deleted).toBe(true)
  })

  it('resolves a type-known manual review task on the original card', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse({
        task_id: '10001',
        order_id: '20001',
        task_status: 'READY',
        review_status: 'RESOLVED',
        review_resolution: {
          confirmed_order_id: '20001',
          field_overrides: [
            {
              field_pointer: '/extracted_fields/room_items/0/pms_room_type_code',
              field_path: 'extracted_fields.room_items.0.pms_room_type_code',
              legacy_field_path: 'extracted_fields.pms_room_type_code',
              value: 'RM3',
            },
          ],
        },
        confirmed_payload: {
          field_values: {
            'extracted_fields.room_items.0.pms_room_type_code': 'RM3',
          },
          legacy_field_values: {
            'extracted_fields.pms_room_type_code': 'RM3',
          },
        },
        opera_operations: [],
      }),
    )

    const result = await resolveReservationManualReviewTask('10001', {
      confirmed_order_id: '20001',
      reason: '确认 PMS 房型代码',
      field_overrides: [
        {
          field_pointer: '/extracted_fields/room_items/0/pms_room_type_code',
          field_path: 'extracted_fields.room_items.0.pms_room_type_code',
          value: 'RM3',
        },
      ],
    })

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/reservation/tasks/10001/manual-review-resolutions',
      expect.objectContaining({
        method: 'POST',
        headers: expect.objectContaining({
          'Content-Type': 'application/json',
        }),
        body: JSON.stringify({
          confirmed_order_id: '20001',
          reason: '确认 PMS 房型代码',
          field_overrides: [
            {
              field_pointer: '/extracted_fields/room_items/0/pms_room_type_code',
              field_path: 'extracted_fields.room_items.0.pms_room_type_code',
              value: 'RM3',
            },
          ],
        }),
      }),
    )
    expect(result.task_status).toBe('READY')
    expect(result.review_status).toBe('RESOLVED')
  })

  it('fetches order detail from the backend by default', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse({
        order: {
          order_id: '20001',
          hotel_id: 'HOTEL-TEST',
          order_status: 'ACTIVE',
          temporary_order_no: null,
          confirmation_number: 'CNF123456',
          group_code: 'GRP-001',
          block_code: null,
          allotment_code: null,
          display_name: 'GRP-001',
          created_at: '2026-07-08T03:00:00Z',
          updated_at: '2026-07-08T03:10:00Z',
        },
        tasks: [],
        warnings: [],
      }),
    )

    const result = await fetchReservationOrderDetail('20001')

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/reservation/orders/20001?include_tasks=true&include_source_summary=true',
      expect.objectContaining({ method: 'GET' }),
    )
    expect(result.order.display_name).toBe('GRP-001')
  })

  it('fetches task detail from the backend by default', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse({
        task_id: '10001',
        order_id: '20001',
        source_message_id: '30001',
        system_task_type: 'NEW_BOOKING',
        task_card_type: 'NEW_BOOKING',
        task_status: 'PENDING_CONFIRM',
        field_contract_version: '20260708-3.0',
        draft_payload: null,
        confirmed_payload: null,
        availability: {
          blocked: false,
          read_only: false,
          editable: true,
          confirmable: true,
          executable: false,
          blocked_by_task_id: null,
          blocked_reason: null,
        },
        fields: [],
        opera_operations: [],
      }),
    )

    const result = await fetchReservationTaskDetail('10001')

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/reservation/tasks/10001',
      expect.objectContaining({ method: 'GET' }),
    )
    expect(result.task_id).toBe('10001')
  })

  it('fetches source message conversation from the backend by default', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse({
        conversation: {
          hotel_id: 'HOTEL-TEST',
          channel: 'EMAIL',
          external_conversation_id: 'thread-30001',
          subject: 'Booking Request',
          message_count: 2,
          first_received_at: '2026-07-08T02:00:00Z',
          last_received_at: '2026-07-08T03:00:00Z',
        },
        messages: [
          {
            id: '30001',
            external_message_id: 'msg-30001',
            external_conversation_id: 'thread-30001',
            sender_summary: 'guest@example.test',
            subject: 'Booking Request',
            received_at: '2026-07-08T02:00:00Z',
            source_sent_at: '2026-07-08T01:58:00Z',
            text_body: '完整邮件正文',
            html_body: '<p>完整邮件正文</p>',
            html_body_sanitized: '<p>完整邮件正文</p>',
            html_sanitize_required: true,
            html_render_mode: 'SANITIZED_HTML',
            inline_images: [],
            attachments: [],
            related_orders: [
              {
                order_id: '20001',
                display_order_key: 'GRP-001',
                order_status: 'ACTIVE',
              },
            ],
            related_tasks: [
              {
                task_id: '10001',
                order_id: '20001',
                task_type: 'NEW_BOOKING',
                task_subtype: 'NEW_BOOKING',
                task_status: 'PENDING_CONFIRM',
                card_name: 'New Booking',
              },
            ],
          },
        ],
      }),
    )

    const result = await fetchSourceMessageConversation('30001')

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/source-messages/30001/conversation',
      expect.objectContaining({ method: 'GET' }),
    )
    expect(result.conversation.external_conversation_id).toBe('thread-30001')
    expect(result.messages[0]?.text_body).toBe('完整邮件正文')
  })
})
