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

export type TestStatusCode = 'WAITING' | 'RUNNING' | 'PAUSED' | 'COMPLETED'
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
  testBatteryId?: 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; fieldDefinitionId?: number; fieldName: string; fieldType?: 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?: number | null
  updateTime?: number | null
  creatorName: string | null
  principalName: string | null
  testTypeName: string | null
  testStatus: TestStatusCode
  receptionStatus: ReceptionStatusCode
  startedAtUtc?: number | null
  endedAtUtc?: number | null
  /** 历史兼容字段；新接口不返回测试字段快照，字段从 batteries[].fields 读取。 */
  fieldSnapshots?: Array<{
    snapshotId: number
    fieldDefinitionId: number
    fieldName: string
    fieldType: string
    fieldValue: string | null
  }>
  runtimeAttach?: boolean
  logicStepMappings: TestLogicStepMapping[]
  consoleDetail?: TestConsoleDetail | null
}

export interface TestConsoleDetail {
  experimentName: string | null
  batteryFields: string[]
  specialFields: string[]
  fieldValues: Record<string, Record<string, string>>
}

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: number | null
  startedAtUtc: number | null
  endedAtUtc: number | 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[] }

export const testStatusLabels: Record<string, TestStatus> = {
  WAITING: '待测试', RUNNING: '检测中', PAUSED: '暂停', COMPLETED: '检测完成',
  // 历史数据只作兼容展示，不会由新流程写入。
  RUNNING_ABNORMAL: '检测中', COMPLETION_PENDING: '检测完成', TERMINATED: '检测完成',
}
const receptionStatusMap: Record<ReceptionStatusCode, ReceptionStatus> = {
  NOT_STARTED: '未开始接收', RECEIVING: '接收中', PAUSED: '暂停接收', ENDED: '已结束接收',
}
function mapTest(item: TestDto): TestRecord {
  const status = item.testStatus ? testStatusLabels[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: formatBusinessTime(item.createTime), startedAt: formatBusinessTime(item.startedAtUtc),
    endedAt: formatBusinessTime(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', 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?: number
    sampleIntervalMs?: number
    /** 通道工作状态；读库来源下为 UNOBSERVABLE，界面按“无法观测”展示。 */
    workStatus?: string
    /** 来源里最近一次采样行的设备时间（毫秒）；没有采样行时为空。 */
    lastDataAt?: number | null
    measurements?: Array<Record<string, unknown>>
    units?: string[]
    [key: string]: unknown
  }
}

export interface TestLiveState {
  testId: number
  testStatus: TestStatusCode
  receptionStatus: ReceptionStatusCode
  updatedAt: number
  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 async function saveTestConsoleDetail(testId: number, detail: TestConsoleDetail): Promise<TestConfigurationDetail> {
  return (await request<TestDetailResponse>(`/system/test/${testId}/console-detail`, { method: 'PUT', body: JSON.stringify(detail) })).data
}

export interface PersistedTestRecord {
  id: number | string
  stableIdentity?: string
  sampleId?: number
  sourceType?: 'CABINET' | 'COLLECTOR' | 'SNAPSHOT' | string
  metricCode?: string
  metricValue?: number | string | null
  unit?: string | null
  collectorId?: number
  collectorCode?: string
  channelCode?: string
  recordNo: string
  batteryNo: string
  cycleNo: number
  stepNo: number
  stepName: string
  stepType?: string
  sequenceId: number
  cabinetSequenceId?: number | null
  relativeTimeSeconds?: number | string | null
  recordedAt?: number | null
  absoluteTime?: number | null
  deviceTime?: number | null
  collectorDeviceTime?: number | null
  captureSlot?: number | null
  serverReceivedAt?: number | null
  voltage: number | string | null
  current: number | string | null
  capacity: number | string | null
  energy: number | string | null
  temperature?: number | string | null
  positivePotential?: number | string | null
  negativePotential?: number | string | null
  extensionMeasurementsJson?: string | Record<string, unknown> | null
  sourceIdentity?: string
  sourceRecordId?: string
  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
  chargeMedianVoltage: number | string | null
  dischargeMedianVoltage: 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
  /** 来源类别：DEVICE 设备提供、AGGREGATED 本系统按工步层聚合、IMPORTED 授权文件导入。 */
  sourceKind?: 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 interface WarningExceptionRecord {
  exceptionId: number; testId: number; testName?: string; sourceType: string; sourceIdentity: string;
  exceptionType: 'THRESHOLD' | 'DEVICE_OFFLINE';
  metricCode: string; abnormalValue: number | null; unit: string; ruleSnapshot: string; severity: string;
  exceptionStatus: 'OPEN' | 'CLOSED'; firstOccurredAtUtc: number; lastOccurredAtUtc: number;
  occurrenceCount: number; handledByName?: string; handledAtUtc?: number | null; handlingNote?: string;
}
export async function getWarningExceptions(params: { testId?: number; status?: string } = {}): Promise<WarningExceptionRecord[]> {
  const query = new URLSearchParams(); if (params.testId) query.set('testId', String(params.testId)); if (params.status) query.set('status', params.status);
  const result = await request<ApiResponse & { rows?: WarningExceptionRecord[] }>(`/system/test-warning-exceptions/list?${query}`)
  return result.rows || []
}
export async function closeWarningException(exceptionId: number, handlingNote: string): Promise<WarningExceptionRecord> {
  const result = await request<ApiResponse & { data: WarningExceptionRecord }>(`/system/test-warning-exceptions/${exceptionId}/close`, { method: 'PUT', body: JSON.stringify({ handlingNote }) })
  return result.data
}

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

/** 订阅实时监控观测与提醒（接收中后端约 5 秒观测）；使用鉴权 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([401, 403].includes(response.status) ? '实时流权限不足' : `实时流连接失败（${response.status}）`)
      if (!response.headers.get('content-type')?.includes('text/event-stream')) throw new Error('实时流响应格式错误')
      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()
}
