import type {
  FlowAnalyticsDto,
  FlowClientsDto,
  FlowExportersDto,
  FlowMapHopsDto,
  FlowMonthlyDto,
  FlowPurgeDto,
  FlowStatsDto,
  TrafficFlowHostFile,
  TrafficFlowOverlayResult,
  TrafficFlowSettingsDto,
  TrafficFlowSettingsPatch,
} from "@mmapp/contracts/traffic-flow"
import { requestJson } from "@/shared/api/http-client"

export type { TrafficFlowHostFile }

export async function getTrafficFlowSettings(baseUrl: string): Promise<TrafficFlowSettingsDto> {
  return requestJson<TrafficFlowSettingsDto>(baseUrl, "/api/traffic/flow/settings")
}

export async function putTrafficFlowSettings(
  baseUrl: string,
  patch: TrafficFlowSettingsPatch,
): Promise<{ ok: boolean; settings: TrafficFlowSettingsDto }> {
  return requestJson(baseUrl, "/api/traffic/flow/settings", {
    method: "PUT",
    body: JSON.stringify(patch),
  })
}

export async function generateTrafficFlowKeys(baseUrl: string): Promise<{
  ok: boolean
  created: boolean
  publicKey: string
  settings: TrafficFlowSettingsDto
}> {
  return requestJson(baseUrl, "/api/traffic/flow/settings/generate-keys", { method: "POST" })
}

export async function getTrafficFlowHostFiles(baseUrl: string): Promise<{ files: TrafficFlowHostFile[] }> {
  return requestJson(baseUrl, "/api/traffic/flow/host-files")
}

export async function applyTrafficFlowOverlay(
  baseUrl: string,
  serverId: string | number,
  publicEndpoint?: string,
): Promise<TrafficFlowOverlayResult> {
  return requestJson(baseUrl, "/api/traffic/flow-overlay", {
    method: "POST",
    body: JSON.stringify({ serverId, publicEndpoint }),
  })
}

export async function getTrafficFlows(baseUrl: string, range = "5m"): Promise<FlowStatsDto> {
  return requestJson<FlowStatsDto>(baseUrl, `/api/traffic/flows?range=${encodeURIComponent(range)}`)
}

function flowQuery(params: {
  range?: string
  serverId?: string
  userId?: string
  iface?: string
  dedup?: boolean
  excludeMesh?: boolean
  excludeOverlay?: boolean
}): string {
  const q = new URLSearchParams()
  if (params.range) q.set("range", params.range)
  if (params.serverId) q.set("serverId", params.serverId)
  if (params.userId) q.set("userId", params.userId)
  if (params.iface && params.iface !== "__all__") q.set("iface", params.iface)
  if (params.dedup === false) q.set("dedup", "0")
  else if (params.dedup === true) q.set("dedup", "1")
  if (params.excludeMesh === false) q.set("excludeMesh", "0")
  else if (params.excludeMesh === true) q.set("excludeMesh", "1")
  if (params.excludeOverlay === false) q.set("excludeOverlay", "0")
  else if (params.excludeOverlay === true) q.set("excludeOverlay", "1")
  const s = q.toString()
  return s ? `?${s}` : ""
}

export async function getFlowExporters(baseUrl: string, range = "5m"): Promise<FlowExportersDto> {
  return requestJson<FlowExportersDto>(baseUrl, `/api/traffic/flow/exporters?range=${encodeURIComponent(range)}`)
}

export async function getFlowClients(baseUrl: string, range = "5m"): Promise<FlowClientsDto> {
  return requestJson<FlowClientsDto>(baseUrl, `/api/traffic/flow/clients?range=${encodeURIComponent(range)}`)
}

export async function getFlowMapHops(
  baseUrl: string,
  params: {
    range?: string
    serverId?: string
    userId?: string
    iface?: string
    dedup?: boolean
    excludeMesh?: boolean
    excludeOverlay?: boolean
  } = {},
): Promise<FlowMapHopsDto> {
  return requestJson<FlowMapHopsDto>(baseUrl, `/api/traffic/flow/map-hops${flowQuery({
    range: params.range ?? "5m",
    serverId: params.serverId,
    userId: params.userId,
    iface: params.iface,
    dedup: params.dedup,
    excludeMesh: params.excludeMesh,
    excludeOverlay: params.excludeOverlay,
  })}`)
}

export async function getFlowAnalytics(
  baseUrl: string,
  params: {
    range?: string
    serverId?: string
    userId?: string
    iface?: string
    dedup?: boolean
    excludeMesh?: boolean
    excludeOverlay?: boolean
  },
): Promise<FlowAnalyticsDto> {
  return requestJson<FlowAnalyticsDto>(baseUrl, `/api/traffic/flow/analytics${flowQuery(params)}`)
}

export async function getFlowMonthly(
  baseUrl: string,
  params: { month: string; serverId?: string },
): Promise<FlowMonthlyDto> {
  const q = new URLSearchParams()
  q.set("month", params.month)
  if (params.serverId) q.set("serverId", params.serverId)
  return requestJson<FlowMonthlyDto>(baseUrl, `/api/traffic/flow/monthly?${q.toString()}`)
}

export async function purgeTrafficFlowData(baseUrl: string): Promise<FlowPurgeDto> {
  return requestJson<FlowPurgeDto>(baseUrl, "/api/traffic/flow/purge", { method: "POST" })
}

export { flowQuery }
