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

import { DebugEmlUploadError, uploadDebugEmlSuperAgentRun } from '@/services/debugEmlService'
import { setUnauthorizedHandler } from '@/services/httpClient'

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

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

describe('debugEmlService', () => {
  beforeEach(() => {
    vi.restoreAllMocks()
    setUnauthorizedHandler(null)
  })

  it('uploads an eml file with FormData and debug key header', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse({
        debug_run_id: '90001',
        source_message_id: '30001',
        source_provider: 'DEBUG_EML_UPLOAD',
        external_message_id: 'debug-eml-run-90001-abcdef123456',
        external_conversation_id: 'debug-thread-90001',
        original_eml_oss_url: 'https://oss.example/raw.eml',
        original_eml_sha256: 'sha256',
        uploaded_media: [],
        html_body_with_oss_urls: '<strong>raw</strong>',
        html_body_sanitized: '<strong>safe</strong>',
        html_sanitize_required: true,
        html_render_mode: 'SANITIZED_HTML',
        agentbus_like_payload: { schema_version: 'debug-eml-upload-v1' },
        superagent_session_id: 'session-1',
        superagent_run_id: 'run-1',
        superagent_raw_answer: '{"ok":true}',
        superagent_parsed_json: { ok: true },
        warnings: [],
        status: 'SUPERAGENT_SUCCEEDED',
      }),
    )
    const file = new File(['From: guest@example.test'], 'booking.eml', { type: 'message/rfc822' })

    const result = await uploadDebugEmlSuperAgentRun({
      hotelId: 'HOTEL-TEST',
      debugUploadKey: ' manual-debug-key ',
      runLabel: 'frontend-smoke',
      file,
    })

    expect(fetchMock).toHaveBeenCalledTimes(1)
    const [url, init] = fetchMock.mock.calls[0]!
    expect(url).toBe('/api/system/debug/eml-superagent-runs')
    expect(init).toMatchObject({
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'X-TH-Hotel-Debug-Upload-Key': 'manual-debug-key',
      },
    })
    expect(init?.headers).not.toHaveProperty('Content-Type')
    expect(init?.body).toBeInstanceOf(FormData)
    const formData = init?.body as FormData
    expect(formData.get('hotel_id')).toBe('HOTEL-TEST')
    expect(formData.get('run_label')).toBe('frontend-smoke')
    expect(formData.get('file')).toBe(file)
    expect(result.debug_run_id).toBe('90001')
  })

  it('throws a typed safe error for backend error_code responses', async () => {
    const unauthorizedHandler = vi.fn()
    setUnauthorizedHandler(unauthorizedHandler)
    vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse(
        {
          error_code: 'DEBUG_UPLOAD_KEY_INVALID',
          message: 'Debug 上传访问口令缺失或错误。',
        },
        401,
      ),
    )
    const file = new File(['From: guest@example.test'], 'booking.eml', { type: 'message/rfc822' })

    await expect(
      uploadDebugEmlSuperAgentRun({
        hotelId: 'HOTEL-TEST',
        debugUploadKey: 'wrong-key',
        file,
      }),
    ).rejects.toMatchObject({
      status: 401,
      errorCode: 'DEBUG_UPLOAD_KEY_INVALID',
      message: 'Debug 上传访问口令缺失或错误。',
    } satisfies Partial<DebugEmlUploadError>)
    expect(unauthorizedHandler).not.toHaveBeenCalled()
  })

  it('runs the shared unauthorized handler for auth session errors', async () => {
    const unauthorizedHandler = vi.fn()
    setUnauthorizedHandler(unauthorizedHandler)
    vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse(
        {
          error_code: 'AUTH_SESSION_INVALID',
          message: '登录已失效。',
        },
        401,
      ),
    )
    const file = new File(['From: guest@example.test'], 'booking.eml', { type: 'message/rfc822' })

    await expect(
      uploadDebugEmlSuperAgentRun({
        hotelId: 'HOTEL-TEST',
        debugUploadKey: 'manual-debug-key',
        file,
      }),
    ).rejects.toMatchObject({
      status: 401,
      errorCode: 'AUTH_SESSION_INVALID',
    } satisfies Partial<DebugEmlUploadError>)

    expect(unauthorizedHandler).toHaveBeenCalledOnce()
  })
})
