import type { ReceptionStatus, TestRecord, TestStatus } from '@/stores/tests'
import { getAuthToken, request, type ApiResponse } from './request'

export type TestStatusCode = 'WAITING' | 'RUNNING' | 'PAUSED' | 'RUNNING_ABNORMAL' | 'COMPLETION_PENDING' | 'COMPLETED' | 'TERMINATED'
export type ReceptionStatusCode = 'NOT_STARTED' | 'RECEIVING' | 'PAUSED' | 'ENDED'

export interface TestListParams {
  pageNum: number
  pageSize: number
  testName?: string
  testTypeId?: number
  batteryNo?: string
  status?: string
  beginCreateTime?: string
  endCreateTime?: string
}

export interface TestPlanStepPayload {
  planStepId?: number
  cycleNo: number
  stepNo: number
  stepType: string
  stepName: string
  parameters: Record<string, unknown>
  sortOrder: number
}

export interface TestBatteryPayload {
  relationId?: number
  groupId: number
  groupName?: string | null
  batteryNo: string
  collectorId: number
  collectorName?: string | null
  binding: { bindingId?: number; channelId: number; expectedBarcode: string | null; claimStatus?: string; cabinetCode?: string | null; cabinetName?: string | null; displayNo?: string | null; devtype?: number | null; devid?: number | null; subdevid?: number | null; chlid?: number | null }
  collectorChannels: Array<{
    mappingId?: number
    measurementCode: string
    measurementName: string
    channelCode: string
  }>
  fields: Array<{ fieldId?: number; fieldName: string; fieldValue: string }>
}

export interface TestThresholdPayload {
  thresholdId?: number
  metricCode: string
  minValue: number | null
  maxValue: number | null
  unit: 'A' | 'V' | 'Ah' | 'Wh' | '℃'
  severity: string
}

export interface TestConfigurationPayload {
  testId?: number
  testName: string
  principalId: number
  testTypeId: number
  testPurpose: string
  monitorTimeoutMinutes: number
  remark: string | null
  batteries: TestBatteryPayload[]
  planSteps: TestPlanStepPayload[]
  thresholds: TestThresholdPayload[]
}

export interface TestConfigurationDetail extends TestConfigurationPayload {
  testId: number
  creatorId: number
  createTime?: string | null
  updateTime?: string | null
  creatorName: string | null
  principalName: string | null
  testTypeName: string | null
  testStatus: TestStatusCode
  receptionStatus: ReceptionStatusCode
  startedAtUtc?: string | null
  endedAtUtc?: string | null
  fieldSnapshots: Array<{
    snapshotId: number
    fieldDefinitionId: number
    fieldName: string
    fieldType: string
    fieldValue: string | null
  }>
  runtimeAttach?: boolean
  logicStepMappings: TestLogicStepMapping[]
}

export interface TestLogicStepMapping {
  logicalNo: number
  logicalName: string
  startStepNo: number
  endStepNo: number
}

export interface TestConfigurationOptions {
  users: Array<{ userId: number; userName: string; nickName: string | null }>
  testTypes: Array<{ testTypeId: number; testTypeName: string }>
  batteries: Array<{ relationId: number; groupId: number; groupName: string; batteryNo: string }>
  channels: Array<{ channelId: number; cabinetId: number; cabinetCode: string; cabinetName: string; adapterCode: string; devtype: number; devid: number; subdevid: number; chlid: number; displayNo: string | null }>
  collectors: Array<{ collectorId: number; collectorCode: string; collectorName: string; channelCount: number }>
}

interface TestDto {
  testId: number
  testName: string | null
  testTypeName: string | null
  principalName: string | null
  testPurpose: string | null
  testStatus: TestStatusCode | null
  receptionStatus: ReceptionStatusCode | null
  batteryNo: string | null
  createTime: string | null
  startedAtUtc: string | null
  endedAtUtc: string | null
  runtimeAttach?: boolean | null
  remark: string | null
  batteryCount: number | null
}

interface TestListResponse extends ApiResponse { total: number; rows: TestDto[] }
interface TestDetailResponse extends ApiResponse { data: TestConfigurationDetail }
interface TestOptionsResponse extends ApiResponse { data: TestConfigurationOptions }
export interface TestListResult { total: number; rows: TestRecord[] }

const statusMap: Record<TestStatusCode, TestStatus> = {
  WAITING: '待测试', RUNNING: '检测中', PAUSED: '暂停', RUNNING_ABNORMAL: '检测中（异常）',
  // 历史兼容状态统一按当前“停止即完成”语义展示。
  COMPLETION_PENDING: '检测完成', COMPLETED: '检测完成', TERMINATED: '检测完成',
}
const receptionStatusMap: Record<ReceptionStatusCode, ReceptionStatus> = {
  NOT_STARTED: '未开始接收', RECEIVING: '接收中', PAUSED: '暂停接收', ENDED: '已结束接收',
}
const legacyStatusMap: Record<string, TestStatusCode> = {
  '0': 'WAITING', '1': 'RUNNING', '2': 'RUNNING_ABNORMAL', '3': 'COMPLETED',
}

function mapTest(item: TestDto): TestRecord {
  const status = item.testStatus ? statusMap[item.testStatus] : '未知'
  const receptionStatus = item.receptionStatus ? receptionStatusMap[item.receptionStatus] : '未知'
  return {
    id: item.testId, name: item.testName || '-', type: item.testTypeName || '-', batteryNo: item.batteryNo || '-', batteryGroup: '-',
    batteryCount: Number(item.batteryCount) || 0, createdAt: item.createTime || '-', startedAt: item.startedAtUtc || '-',
    endedAt: item.endedAtUtc || '-', purpose: item.testPurpose || '-', owner: item.principalName || '-',
    remark: item.remark || '-', status, receptionStatus, editable: item.receptionStatus === 'NOT_STARTED',
  }
}

export async function getTestList(params: TestListParams): Promise<TestListResult> {
  const searchParams = new URLSearchParams()
  Object.entries(params).forEach(([key, value]) => {
    if (value === undefined || value === '') return
    if (key === 'status') searchParams.set('testStatus', legacyStatusMap[String(value)] || String(value))
    else searchParams.set(key, String(value))
  })
  const result = await request<TestListResponse>(`/system/test/list?${searchParams.toString()}`)
  return { total: Number(result.total) || 0, rows: (result.rows || []).map(mapTest) }
}

export async function getTestConfigurationOptions(): Promise<TestConfigurationOptions> {
  return (await request<TestOptionsResponse>('/system/test/options')).data
}

export async function getTestDetail(testId: number): Promise<TestConfigurationDetail> {
  return (await request<TestDetailResponse>(`/system/test/${testId}`)).data
}

export async function createTest(payload: TestConfigurationPayload): Promise<TestConfigurationDetail> {
  return (await request<TestDetailResponse>('/system/test', { method: 'POST', body: JSON.stringify(payload) })).data
}

export async function updateTest(payload: TestConfigurationPayload & { testId: number }): Promise<TestConfigurationDetail> {
  return (await request<TestDetailResponse>('/system/test', { method: 'PUT', body: JSON.stringify(payload) })).data
}

export async function deleteTests(testIds: number[]): Promise<void> {
  await request<ApiResponse>(`/system/test/${testIds.join(',')}`, { method: 'DELETE' })
}

/** 原子开始接收；后端确认全部来源后才会改变正式状态。 */
export async function startTestReception(testId: number): Promise<TestConfigurationDetail> {
  return (await request<TestDetailResponse>(`/system/test/${testId}/reception/start`, { method: 'POST' })).data
}

/** 暂停系统数据请求；设备不接收控制命令。 */
export async function pauseTestReception(testId: number): Promise<TestConfigurationDetail> {
  return (await request<TestDetailResponse>(`/system/test/${testId}/reception/pause`, { method: 'POST' })).data
}

/** 继续系统数据请求；恢复暂停后的实时请求。 */
export async function resumeTestReception(testId: number): Promise<TestConfigurationDetail> {
  return (await request<TestDetailResponse>(`/system/test/${testId}/reception/resume`, { method: 'POST' })).data
}

/** 人工停止测试并将本次接收标记为检测完成。 */
export async function stopTest(testId: number): Promise<TestConfigurationDetail> {
  return (await request<TestDetailResponse>(`/system/test/${testId}/stop`, { method: 'POST' })).data
}

/** 人工结束接收的独立动作接口；保留 stopTest 兼容旧页面调用。 */
export async function endTestReception(testId: number): Promise<TestConfigurationDetail> {
  return (await request<TestDetailResponse>(`/system/test/${testId}/reception/end`, { method: 'POST' })).data
}

export interface LiveSource {
  sourceType: 'CABINET_CHANNEL' | 'COLLECTOR' | string
  sourceId: number
  batteryNo: string
  deviceStatus: string
  latestSnapshot: {
    source?: string
    unit?: string
    observedAt?: string
    sampleIntervalMs?: number
    measurements?: Array<Record<string, unknown>>
    units?: string[]
    [key: string]: unknown
  }
}

export interface TestLiveState {
  testId: number
  testStatus: TestStatusCode
  receptionStatus: ReceptionStatusCode
  updatedAt: string
  sources: LiveSource[]
  exceptions: Array<Record<string, unknown>>
  testPlan?: BtsTestSnapshot | null
}

export interface BtsTestPlanRow {
  rowType: 'STEP' | 'CYCLE' | 'END' | string
  stepNo: number
  cyclePosition: number | null
  stepName: string
  durationSeconds: number
  voltageV: number | null
  executionStatus: string
  cycleCount: number | null
  recordCount: number | null
}

export interface BtsTestSnapshot {
  currentCycleNo: number
  currentStepNo: number
  plannedCycleCount: number
  rows: BtsTestPlanRow[]
}

export async function saveLogicStepMappings(testId: number, mappings: TestLogicStepMapping[]): Promise<TestConfigurationDetail> {
  return (await request<TestDetailResponse>(`/system/test/${testId}/logic-step-mappings`, { method: 'PUT', body: JSON.stringify(mappings) })).data
}

interface TestLiveStateResponse extends ApiResponse { data: TestLiveState }

export async function getTestLiveState(testId: number): Promise<TestLiveState> {
  return (await request<TestLiveStateResponse>(`/system/test/${testId}/live-state`)).data
}

export interface BtsRecord {
  sequenceId: number
  deviceTime: string
  currentA: number
  voltageV: number
  capacityAh: number
  energyWh: number
  cycleNo: number
  stepNo: number
  stepName: string
  stepType: string
}

export interface BtsStepRecord {
  cycleNo: number
  stepNo: number
  cyclePosition: number
  stepName: string
  stepType: string
  recordCount: number
  startedAt: string
  endedAt: string
  capacityAh: number
  energyWh: number
  durationSeconds: number
  startVoltageV: number
  endVoltageV: number
  chargePeakVoltageV: number
  dischargeValleyVoltageV: number
}

export interface BtsCycleRecord {
  recordNo: string
  cycleNo: number
  recordCount: number
  startedAt: string
  endedAt: string
  chargeCapacityAh: number
  dischargeCapacityAh: number
  chargeEnergyWh: number
  dischargeEnergyWh: number
  efficiency: number
}

async function getSimulatorChannelData<T>(deviceId: number, channelId: number, kind: 'records' | 'steps' | 'cycles'): Promise<T[]> {
  const token = getAuthToken()
  const response = await fetch(`${import.meta.env.VITE_API_BASE_URL || '/dev-api'}/dev/bts-simulator/devices/${deviceId}/channels/${channelId}/${kind}`, { headers: token ? { Authorization: `Bearer ${token}` } : undefined })
  if (!response.ok) throw new Error(`检测柜${kind}数据加载失败（${response.status}）`)
  const result = await response.json() as T[]
  return Array.isArray(result) ? result : []
}

export function getBtsRecords(deviceId: number, channelId: number): Promise<BtsRecord[]> {
  return getSimulatorChannelData<BtsRecord>(deviceId, channelId, 'records')
}

export function getBtsSteps(deviceId: number, channelId: number): Promise<BtsStepRecord[]> {
  return getSimulatorChannelData<BtsStepRecord>(deviceId, channelId, 'steps')
}

export function getBtsCycles(deviceId: number, channelId: number): Promise<BtsCycleRecord[]> {
  return getSimulatorChannelData<BtsCycleRecord>(deviceId, channelId, 'cycles')
}

export interface PersistedTestRecord {
  id: number | string
  stableIdentity?: string
  recordNo: string
  batteryNo: string
  cycleNo: number
  stepNo: number
  stepName: string
  stepType?: string
  sequenceId: number
  recordedAt: string
  absoluteTime: string
  deviceTime?: string
  serverReceivedAt?: string
  voltage: number | string | null
  current: number | string | null
  capacity: number | string | null
  energy: number | string | null
  deviceId: number
  channelId: number
  adapterId?: number
  adapterCode?: string
  devtype?: number
  subdevid?: number
}

export interface PersistedTestStep extends PersistedTestRecord {
  actualStepLabel: string
  stepDuration: number | string | null
  startVoltage: number | string | null
  endVoltage: number | string | null
  chargePeakVoltage: number | string | null
  dischargeValleyVoltage: number | string | null
}

export interface PersistedTestCycle extends PersistedTestRecord {
  chargeCapacity: number | string | null
  dischargeCapacity: number | string | null
  efficiency: number | string | null
  chargeEnergy: number | string | null
  dischargeEnergy: number | string | null
}

async function getPersistedTestData<T>(testId: number, kind: 'records' | 'steps' | 'cycles'): Promise<T[]> {
  const result = await request<ApiResponse & { data?: T[] }>(`/system/test/${testId}/data/${kind}`)
  return Array.isArray(result.data) ? result.data : []
}

export function getPersistedTestRecords(testId: number): Promise<PersistedTestRecord[]> {
  return getPersistedTestData<PersistedTestRecord>(testId, 'records')
}

export function getPersistedTestSteps(testId: number): Promise<PersistedTestStep[]> {
  return getPersistedTestData<PersistedTestStep>(testId, 'steps')
}

export function getPersistedTestCycles(testId: number): Promise<PersistedTestCycle[]> {
  return getPersistedTestData<PersistedTestCycle>(testId, 'cycles')
}

export type TestLiveEvent = 'snapshot' | 'device-status' | 'reception-status' | 'test-status' | 'exception' | 'heartbeat'

/** 使用 fetch 流读取鉴权 SSE；调用返回函数关闭连接，断线由页面决定是否重连。 */
export function openTestLiveStream(testId: number, onEvent: (event: TestLiveEvent, data: unknown) => void,
  onError: (error: Error) => void): () => void {
  const controller = new AbortController()
  const token = getAuthToken()
  void (async () => {
    try {
      const response = await fetch(`${import.meta.env.VITE_API_BASE_URL || '/dev-api'}/system/test/${testId}/live`, {
        headers: token ? { Authorization: `Bearer ${token}`, Accept: 'text/event-stream' } : { Accept: 'text/event-stream' },
        signal: controller.signal,
      })
      if (!response.ok || !response.body) throw new Error(response.status === 401 ? '实时流权限不足' : `实时流连接失败（${response.status}）`)
      const reader = response.body.getReader()
      const decoder = new TextDecoder()
      let buffer = ''
      let eventName: TestLiveEvent = 'snapshot'
      let data = ''
      while (true) {
        const chunk = await reader.read()
        if (chunk.done) throw new Error('实时流已断开')
        buffer += decoder.decode(chunk.value, { stream: true })
        const lines = buffer.split(/\r?\n/)
        buffer = lines.pop() || ''
        for (const line of lines) {
          if (line.startsWith('event:')) eventName = line.slice(6).trim() as TestLiveEvent
          else if (line.startsWith('data:')) data += line.slice(5).trim()
          else if (line === '' && data) {
            try { onEvent(eventName, JSON.parse(data)) } catch { onError(new Error('实时流数据格式错误')) }
            eventName = 'snapshot'
            data = ''
          }
        }
      }
    } catch (error) {
      if (!controller.signal.aborted) onError(error instanceof Error ? error : new Error('实时流连接失败'))
    }
  })()
  return () => controller.abort()
}
