export class APIError extends Error {
  constructor(
    public readonly status: number,
    message: string,
  ) {
    super(message);
    this.name = "APIError";
  }
}

const CSMS_URL = process.env.NEXT_PUBLIC_CSMS_URL ?? "http://localhost:3001";

async function apiFetch<T>(path: string, init?: RequestInit): Promise<T> {
  const res = await fetch(`${CSMS_URL}${path}`, {
    ...init,
    headers: {
      "Content-Type": "application/json",
      ...init?.headers,
    },
    credentials: "include",
  });
  if (!res.ok) {
    const text = await res.text().catch(() => res.statusText);
    throw new APIError(res.status, `API ${path} failed (${res.status}): ${text}`);
  }
  return res.json() as Promise<T>;
}

// ── Types ──────────────────────────────────────────────────────────────────

export type Stats = {
  totalChargePoints: number;
  onlineChargePoints: number;
  activeTransactions: number;
  totalIdTags: number;
  todayEnergyWh: number;
  todayRevenue: number;
  totalUsers: number;
  todayTransactions: number;
};

export type UserStats = {
  totalIdTags: number;
  totalBalance: number;
  activeTransactions: number;
  totalTransactions: number;
  todayEnergyWh: number;
  todayTransactions: number;
};

export type ConnectorSummary = {
  id: string;
  connectorId: number;
  status: string;
  lastStatusAt: string | null;
};

export type ConnectorDetail = {
  id: string;
  connectorId: number;
  status: string;
  errorCode: string;
  info: string | null;
  vendorId: string | null;
  vendorErrorCode: string | null;
  lastStatusAt: string;
  createdAt: string;
  updatedAt: string;
};

export type ConnectionsStatus = {
  connectedIdentifiers: string[];
};

export type ChargePointConnectionStatus = "online" | "unavailable" | "offline";

export type ChargePoint = {
  id: string;
  chargePointIdentifier: string;
  deviceName: string | null;
  chargePointVendor: string | null;
  chargePointModel: string | null;
  registrationStatus: string;
  transportStatus: ChargePointConnectionStatus;
  lastHeartbeatAt: string | null;
  lastWsConnectedAt: string | null;
  lastWsDisconnectedAt: string | null;
  lastCommandStatus: "Accepted" | "Rejected" | "Error" | "Timeout" | null;
  lastCommandAt: string | null;
  lastBootNotificationAt: string | null;
  feePerKwh: number;
  pricingMode: "fixed" | "tou";
  connectors: ConnectorSummary[];
  chargePointStatus: string | null;
  chargePointErrorCode: string | null;
};

export type ChargePointDetail = {
  id: string;
  chargePointIdentifier: string;
  deviceName: string | null;
  chargePointVendor: string | null;
  chargePointModel: string | null;
  chargePointSerialNumber: string | null;
  firmwareVersion: string | null;
  iccid: string | null;
  imsi: string | null;
  meterSerialNumber: string | null;
  meterType: string | null;
  registrationStatus: string;
  heartbeatInterval: number | null;
  transportStatus: ChargePointConnectionStatus;
  lastHeartbeatAt: string | null;
  lastWsConnectedAt: string | null;
  lastWsDisconnectedAt: string | null;
  lastCommandStatus: "Accepted" | "Rejected" | "Error" | "Timeout" | null;
  lastCommandAt: string | null;
  lastBootNotificationAt: string | null;
  feePerKwh: number;
  pricingMode: "fixed" | "tou";
  createdAt: string;
  updatedAt: string;
  connectors: ConnectorDetail[];
  chargePointStatus: string | null;
  chargePointErrorCode: string | null;
};

export type Transaction = {
  id: number;
  chargePointIdentifier: string | null;
  chargePointDeviceName: string | null;
  connectorNumber: number | null;
  idTag: string;
  idTagStatus: string | null;
  idTagUserId: string | null;
  idTagUserName: string | null;
  startTimestamp: string;
  stopTimestamp: string | null;
  startMeterValue: number | null;
  stopMeterValue: number | null;
  energyWh: number | null;
  liveEnergyWh: number | null;
  estimatedCost: number | null;
  stopIdTag: string | null;
  stopReason: string | null;
  chargeAmount: number | null;
  electricityFee: number | null;
  serviceFee: number | null;
  remoteStopStatus: "Requested" | "Accepted" | "Rejected" | "Error" | "Timeout" | null;
  remoteStopRequestedAt: string | null;
  remoteStopRequestId: string | null;
};

export type IdTag = {
  idTag: string;
  status: string;
  expiryDate: string | null;
  parentIdTag: string | null;
  userId: string | null;
  balance: number;
  cardLayout: "center" | "around" | null;
  cardSkin: "line" | "circles" | "glow" | "vip" | "redeye" | null;
  createdAt: string;
};

export type UserRow = {
  id: string;
  name: string | null;
  email: string;
  emailVerified: boolean;
  username: string | null;
  role: string | null;
  banned: boolean | null;
  banReason: string | null;
  createdAt: string;
};

export type ChargePointCreated = ChargePoint & {
  /** 仅在创建时返回一次的明文密码，之后不可再查 */
  plainPassword: string;
};

export type ChargePointPasswordReset = {
  id: string;
  chargePointIdentifier: string;
  /** 仅在重置时返回一次的新明文密码 */
  plainPassword: string;
};

export type PaginatedTransactions = {
  data: Transaction[];
  total: number;
  page: number;
  totalPages: number;
};

export type PriceTier = "peak" | "valley" | "flat";

export type TariffSlot = {
  start: number;
  end: number;
  tier: PriceTier;
};

export type TierPricing = {
  /** 电价（元/kWh） */
  electricityPrice: number;
  /** 服务费（元/kWh） */
  serviceFee: number;
};

export type TariffConfig = {
  id?: string;
  slots: TariffSlot[];
  prices: Record<PriceTier, TierPricing>;
  createdAt?: string;
  updatedAt?: string;
};

export type Ocpp16jSettings = {
  heartbeatInterval: number;
};

export type SystemSettings = {
  ocpp16j: Ocpp16jSettings;
};

// ── API functions ──────────────────────────────────────────────────────────

export type ChartRange = "30d" | "7d" | "24h";

export type ChartDataPoint = {
  bucket: string;
  energyKwh: number;
  revenue: number;
  transactions: number;
  utilizationPct: number;
};

export const api = {
  stats: {
    get: () => apiFetch<Stats | UserStats>("/api/stats"),
    chart: (range: ChartRange) =>
      apiFetch<ChartDataPoint[]>(`/api/stats/chart?range=${range}`),
  },
  chargePoints: {
    list: () => apiFetch<ChargePoint[]>("/api/charge-points"),
    get: (id: string) => apiFetch<ChargePointDetail>(`/api/charge-points/${id}`),
    connections: () => apiFetch<ConnectionsStatus>("/api/charge-points/connections"),
    create: (data: {
      chargePointIdentifier: string;
      chargePointVendor?: string;
      chargePointModel?: string;
      registrationStatus?: "Accepted" | "Pending" | "Rejected";
      feePerKwh?: number;
      pricingMode?: "fixed" | "tou";
      deviceName?: string;
    }) =>
      apiFetch<ChargePointCreated>("/api/charge-points", {
        method: "POST",
        body: JSON.stringify(data),
      }),
    update: (
      id: string,
      data: {
        feePerKwh?: number;
        pricingMode?: "fixed" | "tou";
        registrationStatus?: "Accepted" | "Pending" | "Rejected";
        chargePointVendor?: string;
        chargePointModel?: string;
        deviceName?: string | null;
      },
    ) =>
      apiFetch<ChargePoint>(`/api/charge-points/${id}`, {
        method: "PATCH",
        body: JSON.stringify(data),
      }),
    delete: (id: string) =>
      apiFetch<{ success: true }>(`/api/charge-points/${id}`, { method: "DELETE" }),
    resetPassword: (id: string) =>
      apiFetch<ChargePointPasswordReset>(`/api/charge-points/${id}/reset-password`, {
        method: "POST",
      }),
  },
  transactions: {
    list: (params?: {
      page?: number;
      limit?: number;
      status?: "active" | "completed";
      chargePointId?: string;
    }) => {
      const q = new URLSearchParams();
      if (params?.page) q.set("page", String(params.page));
      if (params?.limit) q.set("limit", String(params.limit));
      if (params?.status) q.set("status", params.status);
      if (params?.chargePointId) q.set("chargePointId", params.chargePointId);
      const qs = q.toString();
      return apiFetch<PaginatedTransactions>(`/api/transactions${qs ? "?" + qs : ""}`);
    },
    get: (id: number) => apiFetch<Transaction>(`/api/transactions/${id}`),
    stop: (id: number) =>
      apiFetch<Transaction & { online: boolean }>(`/api/transactions/${id}/stop`, {
        method: "POST",
      }),
    remoteStart: (data: { chargePointIdentifier: string; connectorId: number; idTag: string }) =>
      apiFetch<{ success: true }>("/api/transactions/remote-start", {
        method: "POST",
        body: JSON.stringify(data),
      }),
    delete: (id: number) =>
      apiFetch<{ success: true }>(`/api/transactions/${id}`, { method: "DELETE" }),
  },
  idTags: {
    list: () => apiFetch<IdTag[]>("/api/id-tags"),
    get: (idTag: string) => apiFetch<IdTag>(`/api/id-tags/${idTag}`),
    claim: () => apiFetch<IdTag>("/api/id-tags/claim", { method: "POST" }),
    create: (data: {
      idTag: string;
      status?: string;
      expiryDate?: string;
      parentIdTag?: string;
      userId?: string | null;
      balance?: number;
      cardLayout?: "center" | "around";
      cardSkin?: "line" | "circles" | "glow" | "vip" | "redeye";
    }) => apiFetch<IdTag>("/api/id-tags", { method: "POST", body: JSON.stringify(data) }),
    update: (
      idTag: string,
      data: {
        status?: string;
        expiryDate?: string | null;
        parentIdTag?: string | null;
        userId?: string | null;
        balance?: number;
        cardLayout?: "center" | "around" | null;
        cardSkin?: "line" | "circles" | "glow" | "vip" | "redeye" | null;
      },
    ) => apiFetch<IdTag>(`/api/id-tags/${idTag}`, { method: "PATCH", body: JSON.stringify(data) }),
    delete: (idTag: string) =>
      apiFetch<{ success: true }>(`/api/id-tags/${idTag}`, { method: "DELETE" }),
  },
  users: {
    list: () => apiFetch<UserRow[]>("/api/users"),
    create: (data: {
      name: string;
      email: string;
      password: string;
      username?: string;
      role?: string;
    }) =>
      apiFetch<{ user: UserRow }>("/api/auth/admin/create-user", {
        method: "POST",
        body: JSON.stringify(data),
      }),
    update: (
      id: string,
      data: {
        name?: string;
        username?: string | null;
        role?: string;
        banned?: boolean;
        banReason?: string | null;
      },
    ) => apiFetch<UserRow>(`/api/users/${id}`, { method: "PATCH", body: JSON.stringify(data) }),
  },
  setup: {
    create: (data: { name: string; email: string; username: string; password: string }) =>
      apiFetch<{ success: boolean }>("/api/setup", { method: "POST", body: JSON.stringify(data) }),
  },
  tariff: {
    get: () => apiFetch<TariffConfig | null>("/api/tariff"),
    put: (data: { slots: TariffSlot[]; prices: Record<PriceTier, TierPricing> }) =>
      apiFetch<TariffConfig>("/api/tariff", { method: "PUT", body: JSON.stringify(data) }),
  },
  settings: {
    get: () => apiFetch<SystemSettings>("/api/settings"),
    put: (data: SystemSettings) =>
      apiFetch<SystemSettings>("/api/settings", { method: "PUT", body: JSON.stringify(data) }),
  },
};
