import { normalizeBackendBaseUrl } from './backendAuth'

export interface BackendApiError {
  statusCode: number
  code: string
  message: string
  details?: unknown
}

export interface BackendAuthLoginResult {
  user?: {
    id?: string
    nickname?: string
    avatarUrl?: string
  }
  tokens: {
    accessToken: string
    refreshToken: string
  }
}

export interface BackendResolvedRelease {
  launchMode: string
  source: string
  eventId: string
  releaseId: string
  configLabel: string
  manifestUrl: string
  manifestChecksumSha256?: string | null
  routeCode?: string | null
}

export interface BackendCourseVariantSummary {
  id: string
  name: string
  description?: string | null
  routeCode?: string | null
  selectable?: boolean
}

export interface BackendLaunchVariantSummary {
  id: string
  name: string
  routeCode?: string | null
  assignmentMode?: string | null
}

export interface BackendRuntimeSummary {
  runtimeBindingId?: string | null
  placeId?: string | null
  placeName?: string | null
  mapId?: string | null
  mapName?: string | null
  tileReleaseId?: string | null
  courseSetId?: string | null
  courseVariantId?: string | null
  routeCode?: string | null
}

export interface BackendPresentationSummary {
  presentationId?: string | null
  templateKey?: string | null
  version?: string | null
}

export interface BackendContentBundleSummary {
  bundleId?: string | null
  bundleType?: string | null
  version?: string | null
}

export interface BackendEntrySessionSummary {
  id: string
  status: string
  eventId?: string
  eventName?: string
  releaseId?: string | null
  configLabel?: string | null
  routeCode?: string | null
  variantId?: string | null
  variantName?: string | null
  runtime?: BackendRuntimeSummary | null
  launchedAt?: string | null
  startedAt?: string | null
  endedAt?: string | null
  // 兼容前端旧字段名，避免联调过渡期多处判断
  sessionId?: string
  sessionStatus?: string
  eventDisplayName?: string
}

export interface BackendCardResult {
  id: string
  type: string
  title: string
  subtitle?: string | null
  coverUrl?: string | null
  displaySlot: string
  displayPriority: number
  event?: {
    id: string
    displayName: string
    summary?: string | null
  } | null
  htmlUrl?: string | null
}

export interface BackendEntryHomeResult {
  user: {
    id: string
    publicId: string
    status: string
    nickname?: string | null
    avatarUrl?: string | null
  }
  tenant: {
    id: string
    code: string
    name: string
  }
  channel: {
    id: string
    code: string
    type: string
    platformAppId?: string | null
    displayName: string
    status: string
    isDefault: boolean
  }
  cards: BackendCardResult[]
  ongoingSession?: BackendEntrySessionSummary | null
  recentSession?: BackendEntrySessionSummary | null
}

export interface BackendEventPlayResult {
  event: {
    id: string
    slug: string
    displayName: string
    summary?: string | null
    status: string
  }
  currentPresentation?: BackendPresentationSummary | null
  currentContentBundle?: BackendContentBundleSummary | null
  release?: {
    id: string
    configLabel: string
    manifestUrl: string
    manifestChecksumSha256?: string | null
    routeCode?: string | null
  } | null
  resolvedRelease?: BackendResolvedRelease | null
  play: {
    canLaunch: boolean
    primaryAction: string
    reason: string
    launchSource?: string
    assignmentMode?: string | null
    courseVariants?: BackendCourseVariantSummary[] | null
    ongoingSession?: BackendEntrySessionSummary | null
    recentSession?: BackendEntrySessionSummary | null
  }
}

export interface BackendLaunchResult {
  event: {
    id: string
    displayName: string
  }
  launch: {
    source: string
    resolvedRelease?: BackendResolvedRelease | null
    config: {
      configUrl: string
      configLabel: string
      configChecksumSha256?: string | null
      releaseId: string
      routeCode?: string | null
    }
    business: {
      source: string
      eventId: string
      sessionId: string
      sessionToken: string
      sessionTokenExpiresAt: string
      routeCode?: string | null
    }
    variant?: BackendLaunchVariantSummary | null
    runtime?: BackendRuntimeSummary | null
    presentation?: BackendPresentationSummary | null
    contentBundle?: BackendContentBundleSummary | null
  }
}

export interface BackendSessionFinishSummaryPayload {
  finalDurationSec?: number
  finalScore?: number
  completedControls?: number
  totalControls?: number
  distanceMeters?: number
  averageSpeedKmh?: number
  maxHeartRateBpm?: number
}

export interface BackendSessionResult {
  session: {
    id: string
    status: string
    clientType: string
    deviceKey: string
    routeCode?: string | null
    runtime?: BackendRuntimeSummary | null
    sessionTokenExpiresAt: string
    launchedAt: string
    startedAt?: string | null
    endedAt?: string | null
  }
  event: {
    id: string
    displayName: string
  }
  resolvedRelease?: BackendResolvedRelease | null
}

export interface BackendSessionResultView {
  session: BackendEntrySessionSummary
  result: {
    status: string
    finalDurationSec?: number
    finalScore?: number
    completedControls?: number
    totalControls?: number
    distanceMeters?: number
    averageSpeedKmh?: number
    maxHeartRateBpm?: number
    summary?: Record<string, unknown>
  }
}

type BackendEnvelope<T> = {
  data: T
}

type RequestOptions = {
  method: 'GET' | 'POST'
  baseUrl: string
  path: string
  authToken?: string
  body?: Record<string, unknown>
}

function requestBackend<T>(options: RequestOptions): Promise<T> {
  const url = `${normalizeBackendBaseUrl(options.baseUrl)}${options.path}`
  const header: Record<string, string> = {}
  if (options.body) {
    header['Content-Type'] = 'application/json'
  }
  if (options.authToken) {
    header.Authorization = `Bearer ${options.authToken}`
  }

  return new Promise<T>((resolve, reject) => {
    wx.request({
      url,
      method: options.method,
      header,
      data: options.body,
      success: (response) => {
        const statusCode = typeof response.statusCode === 'number' ? response.statusCode : 0
        const data = response.data as BackendEnvelope<T> | { error?: { code?: string; message?: string; details?: unknown } }
        if (statusCode >= 200 && statusCode < 300 && data && typeof data === 'object' && 'data' in data) {
          resolve((data as BackendEnvelope<T>).data)
          return
        }

        const errorPayload = data && typeof data === 'object' && 'error' in data
          ? (data as { error?: { code?: string; message?: string; details?: unknown } }).error
          : undefined
        reject({
          statusCode,
          code: errorPayload && errorPayload.code ? errorPayload.code : 'backend_error',
          message: errorPayload && errorPayload.message ? errorPayload.message : `request failed: ${statusCode}`,
          details: errorPayload && errorPayload.details ? errorPayload.details : response.data,
        } as BackendApiError)
      },
      fail: (error) => {
        reject({
          statusCode: 0,
          code: 'network_error',
          message: error && error.errMsg ? error.errMsg : 'network request failed',
        } as BackendApiError)
      },
    })
  })
}

export function loginWechatMini(input: {
  baseUrl: string
  code: string
  deviceKey: string
  clientType?: string
}): Promise<BackendAuthLoginResult> {
  return requestBackend<BackendAuthLoginResult>({
    method: 'POST',
    baseUrl: input.baseUrl,
    path: '/auth/login/wechat-mini',
    body: {
      code: input.code,
      clientType: input.clientType || 'wechat',
      deviceKey: input.deviceKey,
    },
  })
}

export function getEventPlay(input: {
  baseUrl: string
  eventId: string
  accessToken: string
}): Promise<BackendEventPlayResult> {
  return requestBackend<BackendEventPlayResult>({
    method: 'GET',
    baseUrl: input.baseUrl,
    path: `/events/${encodeURIComponent(input.eventId)}/play`,
    authToken: input.accessToken,
  })
}

export function getEntryHome(input: {
  baseUrl: string
  accessToken: string
  channelCode: string
  channelType: string
}): Promise<BackendEntryHomeResult> {
  const query = `channelCode=${encodeURIComponent(input.channelCode)}&channelType=${encodeURIComponent(input.channelType)}`
  return requestBackend<BackendEntryHomeResult>({
    method: 'GET',
    baseUrl: input.baseUrl,
    path: `/me/entry-home?${query}`,
    authToken: input.accessToken,
  })
}

export function launchEvent(input: {
  baseUrl: string
  eventId: string
  accessToken: string
  releaseId?: string
  variantId?: string
  clientType: string
  deviceKey: string
}): Promise<BackendLaunchResult> {
  const body: Record<string, unknown> = {
    clientType: input.clientType,
    deviceKey: input.deviceKey,
  }
  if (input.releaseId) {
    body.releaseId = input.releaseId
  }
  if (input.variantId) {
    body.variantId = input.variantId
  }
  return requestBackend<BackendLaunchResult>({
    method: 'POST',
    baseUrl: input.baseUrl,
    path: `/events/${encodeURIComponent(input.eventId)}/launch`,
    authToken: input.accessToken,
    body,
  })
}

export function startSession(input: {
  baseUrl: string
  sessionId: string
  sessionToken: string
}): Promise<BackendSessionResult> {
  return requestBackend<BackendSessionResult>({
    method: 'POST',
    baseUrl: input.baseUrl,
    path: `/sessions/${encodeURIComponent(input.sessionId)}/start`,
    body: {
      sessionToken: input.sessionToken,
    },
  })
}

export function finishSession(input: {
  baseUrl: string
  sessionId: string
  sessionToken: string
  status: 'finished' | 'failed' | 'cancelled'
  summary: BackendSessionFinishSummaryPayload
}): Promise<BackendSessionResult> {
  return requestBackend<BackendSessionResult>({
    method: 'POST',
    baseUrl: input.baseUrl,
    path: `/sessions/${encodeURIComponent(input.sessionId)}/finish`,
    body: {
      sessionToken: input.sessionToken,
      status: input.status,
      summary: input.summary,
    },
  })
}

export function getSessionResult(input: {
  baseUrl: string
  accessToken: string
  sessionId: string
}): Promise<BackendSessionResultView> {
  return requestBackend<BackendSessionResultView>({
    method: 'GET',
    baseUrl: input.baseUrl,
    path: `/sessions/${encodeURIComponent(input.sessionId)}/result`,
    authToken: input.accessToken,
  })
}

export function getMyResults(input: {
  baseUrl: string
  accessToken: string
  limit?: number
}): Promise<BackendSessionResultView[]> {
  const limit = typeof input.limit === 'number' ? input.limit : 20
  return requestBackend<BackendSessionResultView[]>({
    method: 'GET',
    baseUrl: input.baseUrl,
    path: `/me/results?limit=${encodeURIComponent(String(limit))}`,
    authToken: input.accessToken,
  })
}
