/**
 * 风险服务契约测试
 * 直接导入真实服务方法，验证 URL 路径正确性
 * 修复了旧测试（endpoint-contract.test.ts）使用手写模拟导致的假绿问题
 */

import { describe, expect, it, vi, beforeEach } from 'vitest'
import { riskService } from '../risk'

// Mock fetch (authFetch 内部调用的是 fetch)
const mockFetch = vi.fn()
vi.stubGlobal('fetch', mockFetch)

describe('Risk Service Contract Tests - 真实服务 URL 验证', () => {
  beforeEach(() => {
    mockFetch.mockReset()
    mockFetch.mockResolvedValue({
      ok: true,
      json: async () => ({ code: 200, data: [] }),
      blob: async () => new Blob(['test'], { type: 'text/csv' })
    })
  })

  describe('风险告警接口 - /risks/alerts/*', () => {
    it('getAlerts 应使用 /risks/alerts 路径', async () => {
      await riskService.getAlerts({ page: 1, size: 10 })
      const calledUrl = mockFetch.mock.calls[0][0] as string
      expect(calledUrl).toMatch(/^\/api\/v1\/risks\/alerts/)
      expect(calledUrl).not.toMatch(/\/api\/v1\/risk\//)
    })

    it('getAlertById 应使用 /risks/alerts/:id 路径', async () => {
      await riskService.getAlertById(123)
      const calledUrl = mockFetch.mock.calls[0][0] as string
      expect(calledUrl).toMatch(/^\/api\/v1\/risks\/alerts\/123$/)
      expect(calledUrl).not.toMatch(/\/api\/v1\/risk\//)
    })

    it('handleAlert 应使用 /risks/alerts/:id/handle 路径', async () => {
      await riskService.handleAlert(123, { status: 'HANDLED', handleResult: 'test' })
      const calledUrl = mockFetch.mock.calls[0][0] as string
      expect(calledUrl).toMatch(/^\/api\/v1\/risks\/alerts\/123\/handle$/)
      expect(calledUrl).not.toMatch(/\/api\/v1\/risk\//)
    })

    it('batchHandleAlerts 应使用 /risks/alerts/batch-handle 路径', async () => {
      await riskService.batchHandleAlerts([1, 2, 3], { status: 'HANDLED', handleResult: 'test' })
      const calledUrl = mockFetch.mock.calls[0][0] as string
      expect(calledUrl).toMatch(/^\/api\/v1\/risks\/alerts\/batch-handle$/)
      expect(calledUrl).not.toMatch(/\/api\/v1\/risk\//)
    })

    it('getPendingAlertCount 应使用 /risks/alerts/pending-count 路径', async () => {
      await riskService.getPendingAlertCount()
      const calledUrl = mockFetch.mock.calls[0][0] as string
      expect(calledUrl).toMatch(/^\/api\/v1\/risks\/alerts\/pending-count$/)
      expect(calledUrl).not.toMatch(/\/api\/v1\/risk\//)
    })

    it('blockAlert 应使用 /risks/alerts/:id/block 路径', async () => {
      await riskService.blockAlert(123)
      const calledUrl = mockFetch.mock.calls[0][0] as string
      expect(calledUrl).toMatch(/^\/api\/v1\/risks\/alerts\/123\/block$/)
      expect(calledUrl).not.toMatch(/\/api\/v1\/risk\//)
    })

    it('releaseAlert 应使用 /risks/alerts/:id/release 路径', async () => {
      await riskService.releaseAlert(123)
      const calledUrl = mockFetch.mock.calls[0][0] as string
      expect(calledUrl).toMatch(/^\/api\/v1\/risks\/alerts\/123\/release$/)
      expect(calledUrl).not.toMatch(/\/api\/v1\/risk\//)
    })
  })

  describe('风控规则接口 - /risks/rules/*', () => {
    it('getRules 应使用 /risks/rules 路径', async () => {
      await riskService.getRules({ page: 1, size: 10 })
      const calledUrl = mockFetch.mock.calls[0][0] as string
      expect(calledUrl).toMatch(/^\/api\/v1\/risks\/rules/)
      expect(calledUrl).not.toMatch(/\/api\/v1\/risk\//)
    })

    it('createRule 应使用 POST /risks/rules 路径', async () => {
      await riskService.createRule({ name: 'test', riskType: 'CHEAT', condition: 'test', action: 'BLOCK', priority: 1 })
      const calledUrl = mockFetch.mock.calls[0][0] as string
      expect(calledUrl).toMatch(/^\/api\/v1\/risks\/rules$/)
      expect(mockFetch.mock.calls[0][1]?.method).toBe('POST')
      expect(calledUrl).not.toMatch(/\/api\/v1\/risk\//)
    })

    it('updateRule 应使用 PUT /risks/rules/:id 路径', async () => {
      await riskService.updateRule(123, { name: 'test', riskType: 'CHEAT', condition: 'test', action: 'BLOCK', priority: 1 })
      const calledUrl = mockFetch.mock.calls[0][0] as string
      expect(calledUrl).toMatch(/^\/api\/v1\/risks\/rules\/123$/)
      expect(mockFetch.mock.calls[0][1]?.method).toBe('PUT')
      expect(calledUrl).not.toMatch(/\/api\/v1\/risk\//)
    })

    it('deleteRule 应使用 DELETE /risks/rules/:id 路径', async () => {
      await riskService.deleteRule(123)
      const calledUrl = mockFetch.mock.calls[0][0] as string
      expect(calledUrl).toMatch(/^\/api\/v1\/risks\/rules\/123$/)
      expect(mockFetch.mock.calls[0][1]?.method).toBe('DELETE')
      expect(calledUrl).not.toMatch(/\/api\/v1\/risk\//)
    })

    it('toggleRule 应使用 POST /risks/rules/:id/toggle 路径', async () => {
      await riskService.toggleRule(123, false)
      const calledUrl = mockFetch.mock.calls[0][0] as string
      expect(calledUrl).toMatch(/^\/api\/v1\/risks\/rules\/123\/toggle$/)
      expect(mockFetch.mock.calls[0][1]?.method).toBe('POST')
      expect(calledUrl).not.toMatch(/\/api\/v1\/risk\//)
    })

    it('toggleRule 应正确传递 enabled 参数', async () => {
      await riskService.toggleRule(123, true)
      const body = mockFetch.mock.calls[0][1]?.body
      const parsedBody = JSON.parse(body)
      expect(parsedBody.enabled).toBe(true)
    })

    it('exportRules 应使用 /risks/rules/export 路径', async () => {
      await riskService.exportRules()
      const calledUrl = mockFetch.mock.calls[0][0] as string
      expect(calledUrl).toMatch(/^\/api\/v1\/risks\/rules\/export$/)
      expect(calledUrl).not.toMatch(/\/api\/v1\/risk\//)
    })
  })

  describe('字段协议 - riskType 兼容性', () => {
    it('createRule 应发送 riskType 字段（不是 type）', async () => {
      await riskService.createRule({ name: 'test', riskType: 'CHEAT', condition: 'test', action: 'BLOCK', priority: 1 })
      const body = mockFetch.mock.calls[0][1]?.body
      const parsedBody = JSON.parse(body)
      expect(parsedBody).toHaveProperty('riskType')
      expect(parsedBody.riskType).toBe('CHEAT')
    })
  })
})
