import assert from 'node:assert/strict'

import { apiRequest } from '../src/services/api.js'

async function testUsesCustomContentTypeHeader() {
  let capturedOptions = null

  global.fetch = async (_url, options) => {
    capturedOptions = options
    return {
      ok: true,
      async json() {
        return { ok: true }
      }
    }
  }

  await apiRequest('/knowledge/documents', {
    method: 'POST',
    body: 'payload',
    contentType: 'application/octet-stream'
  })

  assert.equal(capturedOptions.headers['Content-Type'], 'application/octet-stream')
}

async function testSupportsBlobResponses() {
  const blob = new Blob(['preview'])

  global.fetch = async () => ({
    ok: true,
    async blob() {
      return blob
    },
    async json() {
      throw new Error('json parser should not be used for blob responses')
    }
  })

  const payload = await apiRequest('/knowledge/documents/demo/content', {
    responseType: 'blob',
    contentType: null
  })

  assert.equal(payload, blob)
}

async function testInjectsBearerTokenWithoutUserControlledIdentityHeaders() {
  const sessionStorage = new Map([
    ['x-financial-auth-access-token', 'opaque-access-token'],
    ['x-financial-auth-expires-at', '2099-01-01T00:00:00.000Z'],
    [
      'x-financial-auth-user',
      JSON.stringify({
        username: 'admin',
        name: 'Admin User',
        employeePosition: 'System Manager',
        employeeGrade: 'M5',
        employeeNo: 'E-001',
        managerName: 'Approver User',
        roleCodes: ['manager'],
        isAdmin: true
      })
    ]
  ])

  global.window = {
    sessionStorage: {
      getItem(key) {
        return sessionStorage.get(key) ?? null
      }
    }
  }

  let capturedOptions = null

  global.fetch = async (_url, options) => {
    capturedOptions = options
    return {
      ok: true,
      async json() {
        return { ok: true }
      }
    }
  }

  await apiRequest('/knowledge/library')

  assert.equal(capturedOptions.headers.Authorization, 'Bearer opaque-access-token')
  assert.equal(capturedOptions.headers['x-auth-username'], undefined)
  assert.equal(capturedOptions.headers['x-auth-role-codes'], undefined)
  assert.equal(capturedOptions.headers['x-auth-is-admin'], undefined)
}

async function testLoginCanDisableBearerInjection() {
  const sessionStorage = new Map([
    ['x-financial-auth-access-token', 'stale-token'],
    ['x-financial-auth-expires-at', '2099-01-01T00:00:00.000Z']
  ])

  global.window = {
    sessionStorage: {
      getItem(key) {
        return sessionStorage.get(key) ?? null
      }
    }
  }

  let capturedOptions = null

  global.fetch = async (_url, options) => {
    capturedOptions = options
    return {
      ok: true,
      async json() {
        return { ok: true }
      }
    }
  }

  await apiRequest('/auth/login', {
    auth: false,
    handleUnauthorized: false,
    method: 'POST',
    body: '{}'
  })

  assert.equal(capturedOptions.headers.Authorization, undefined)
}

async function testRejectsCustomAuthorizationOverride() {
  const sessionStorage = new Map([
    ['x-financial-auth-access-token', 'server-issued-token'],
    ['x-financial-auth-expires-at', '2099-01-01T00:00:00.000Z']
  ])
  global.window = {
    sessionStorage: {
      getItem(key) {
        return sessionStorage.get(key) ?? null
      }
    }
  }
  let capturedOptions = null
  global.fetch = async (_url, options) => {
    capturedOptions = options
    return { ok: true, async json() { return { ok: true } } }
  }

  await apiRequest('/knowledge/library', {
    headers: { Authorization: 'Bearer attacker-token' }
  })

  assert.equal(capturedOptions.headers.Authorization, 'Bearer server-issued-token')
}

async function testUnauthorizedResponsePublishesSessionExpiredEvent() {
  const sessionStorage = new Map([
    ['x-financial-auth-access-token', 'expired-token'],
    ['x-financial-auth-expires-at', '2099-01-01T00:00:00.000Z']
  ])
  const events = []
  global.window = {
    sessionStorage: {
      getItem(key) {
        return sessionStorage.get(key) ?? null
      }
    },
    dispatchEvent(event) {
      events.push(event.type)
    }
  }
  global.fetch = async () => ({
    ok: false,
    status: 401,
    async json() {
      return { detail: '登录会话已失效。' }
    }
  })

  await assert.rejects(
    () => apiRequest('/auth/me'),
    (error) => {
      assert.equal(error.status, 401)
      assert.equal(error.code, 'AUTH_SESSION_EXPIRED')
      return true
    }
  )
  assert.deepEqual(events, ['x-financial:auth-expired'])
}

async function testFormatsValidationErrors() {
  global.fetch = async () => ({
    ok: false,
    async json() {
      return {
        detail: [
          {
            loc: ['body', 'email'],
            msg: 'value is not a valid email address'
          },
          {
            loc: ['body', 'password'],
            msg: 'String should have at least 5 characters'
          }
        ]
      }
    }
  })

  await assert.rejects(
    () => apiRequest('/employees/demo', { method: 'PATCH', body: '{}' }),
    (error) => {
      assert.equal(
        error.message,
        'email: value is not a valid email address；password: String should have at least 5 characters'
      )
      return true
    }
  )
}

async function testRejectsWithCustomTimeoutMessage() {
  global.fetch = async (_url, options) =>
    new Promise((_, reject) => {
      options.signal.addEventListener('abort', () => {
        const error = new Error('aborted')
        error.name = 'AbortError'
        reject(error)
      })
    })

  await assert.rejects(
    () =>
      apiRequest('/knowledge/library', {
        timeoutMs: 1,
        timeoutMessage: '知识问答整理超时，已停止等待。'
      }),
    (error) => {
      assert.equal(error.message, '知识问答整理超时，已停止等待。')
      assert.equal(error.code, 'REQUEST_TIMEOUT')
      return true
    }
  )
}

async function testPreservesStructuredPreReviewConflict() {
  const review = {
    review_id: 'review-conflict-001',
    decision: 'needs_fix',
    message: '住宿费超过标准，请先调整。',
    findings: [{ risk_id: 'risk-001', severity: 'high' }]
  }
  global.fetch = async () => ({
    ok: false,
    status: 409,
    async json() {
      return {
        detail: {
          code: 'PRE_REVIEW_NEEDS_FIX',
          message: '预审发现需整改风险。',
          review
        }
      }
    }
  })

  await assert.rejects(
    () => apiRequest('/reimbursements/claims/claim-001/submit', {
      method: 'POST',
      body: '{}'
    }),
    (error) => {
      assert.equal(error.status, 409)
      assert.equal(error.code, 'PRE_REVIEW_NEEDS_FIX')
      assert.equal(error.message, '预审发现需整改风险。')
      assert.deepEqual(error.review, review)
      assert.deepEqual(error.detail.review, review)
      assert.deepEqual(error.payload.detail.review, review)
      return true
    }
  )
}

async function run() {
  await testUsesCustomContentTypeHeader()
  await testSupportsBlobResponses()
  await testInjectsBearerTokenWithoutUserControlledIdentityHeaders()
  await testLoginCanDisableBearerInjection()
  await testRejectsCustomAuthorizationOverride()
  await testUnauthorizedResponsePublishesSessionExpiredEvent()
  await testFormatsValidationErrors()
  await testPreservesStructuredPreReviewConflict()
  await testRejectsWithCustomTimeoutMessage()
  console.log('api-request tests passed')
}

run().catch((error) => {
  console.error(error)
  process.exit(1)
})
