type ApiRequestOptions = {
  method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
  body?: unknown;
  headers?: HeadersInit;
  raw?: boolean;
};

type ApiResponse<T = any> = {
  data: T;
  status: number;
  headers: Headers;
};

const API_BASE = "";

function getAdminToken(): string {
  if (typeof sessionStorage === "undefined") return "";
  return sessionStorage.getItem("nxtgauge_admin_access_token") || "";
}

function authHeaders(): Record<string, string> {
  const token = getAdminToken();
  if (!token) return {};
  return { Authorization: `Bearer ${token}` };
}

async function request<T = any>(path: string, options: ApiRequestOptions = {}): Promise<ApiResponse<T>> {
  const headers: HeadersInit = {
    Accept: "application/json",
    ...authHeaders(),
    ...options.headers,
  };

  const init: RequestInit = {
    method: options.method ?? "GET",
    credentials: "include",
    headers,
  };

  if (options.body !== undefined) {
    init.body = JSON.stringify(options.body);
    (init.headers as Record<string, string>)["Content-Type"] = "application/json";
  }

  const res = await fetch(`${API_BASE}${path}`, init);

  if (options.raw) {
    return { data: res as any, status: res.status, headers: res.headers };
  }

  const raw = await res.text();
  let data: any = null;
  try {
    data = raw ? JSON.parse(raw) : null;
  } catch {
    data = raw;
  }

  if (!res.ok) {
    const message =
      (data && typeof data === "object" && (data.message || data.error)) ||
      `Request failed (${res.status})`;
    throw new Error(message);
  }

  return { data: data as T, status: res.status, headers: res.headers };
}

export const api = {
  get: <T = any>(path: string, headers?: HeadersInit) => request<T>(path, { method: "GET", headers }),
  post: <T = any>(path: string, body?: unknown, headers?: HeadersInit) => request<T>(path, { method: "POST", body, headers }),
  put: <T = any>(path: string, body?: unknown, headers?: HeadersInit) => request<T>(path, { method: "PUT", body, headers }),
  patch: <T = any>(path: string, body?: unknown, headers?: HeadersInit) => request<T>(path, { method: "PATCH", body, headers }),
  delete: <T = any>(path: string, headers?: HeadersInit) => request<T>(path, { method: "DELETE", headers }),
};

// ──────────────────────────────────────────────────────────────────────────
// Invoices
// ──────────────────────────────────────────────────────────────────────────

export type InvoiceStatus = "DRAFT" | "ISSUED" | "PAID" | "VOID" | "REFUNDED";
export type InvoiceType = "TAX_INVOICE" | "BILL_OF_SUPPLY" | "CREDIT_NOTE" | "DEBIT_NOTE";

export interface AdminInvoiceSummary {
  id: string;
  invoice_number: string;
  payment_id: string;
  user_id: string;
  user_email: string | null;
  status: InvoiceStatus;
  currency: string;
  invoice_type: InvoiceType;
  subtotal: number;
  discount_amount: number;
  cgst_amount: number;
  sgst_amount: number;
  igst_amount: number;
  total: number;
  customer_name: string | null;
  customer_gstin: string | null;
  pdf_object_key: string | null;
  issued_at: string;
  paid_at: string | null;
}

export interface AdminInvoiceLine {
  line_number: number;
  description: string;
  hsn_sac_code: string | null;
  quantity: number;
  unit_price_paise: number;
  tax_rate_percent: number;
}

export interface AdminInvoiceDetail {
  invoice: AdminInvoiceSummary & {
    cgst_rate: number;
    sgst_rate: number;
    igst_rate: number;
    seller_name: string;
    seller_address: string;
    seller_gstin: string | null;
    seller_pan: string | null;
    seller_state_code: string | null;
    place_of_supply_state: string | null;
    customer_email: string | null;
    customer_phone: string | null;
    customer_billing_address: string | null;
    customer_state_code: string | null;
    discount_label: string | null;
    notes: string | null;
    voided_at: string | null;
    voided_by_user_id: string | null;
    void_reason: string | null;
    created_at: string;
    updated_at: string;
  };
  lines: AdminInvoiceLine[];
  totals: {
    subtotal: number;
    discount: number;
    taxable_value: number;
    cgst: number;
    sgst: number;
    igst: number;
    total_tax: number;
    total: number;
  };
}

export async function listAdminInvoices(params?: { status?: InvoiceStatus; page?: number; limit?: number }) {
  const qp = new URLSearchParams();
  if (params?.status) qp.set("status", params.status);
  if (params?.page) qp.set("page", String(params.page));
  if (params?.limit) qp.set("limit", String(params.limit));
  const q = qp.toString();
  return api.get<{ invoices: AdminInvoiceSummary[]; page: number; limit: number }>(
    `/api/admin/invoices${q ? `?${q}` : ""}`,
  );
}

export async function getAdminInvoice(id: string) {
  return api.get<AdminInvoiceDetail>(`/api/admin/invoices/${id}`);
}

export async function voidAdminInvoice(id: string, reason: string) {
  return api.post<{ message: string }>(`/api/admin/invoices/${id}/void`, { reason });
}

export async function markAdminInvoicePaid(id: string) {
  return api.post<{ message: string }>(`/api/admin/invoices/${id}/mark-paid`);
}

export function adminInvoiceHtmlUrl(id: string): string {
  return `/api/admin/invoices/${id}/html`;
}

// ──────────────────────────────────────────────────────────────────────────
// Pricing packages (admin)
// ──────────────────────────────────────────────────────────────────────────

export interface AdminPackage {
  id: string;
  name: string;
  description: string | null;
  package_type: string;
  role_key: string | null;
  applicable_roles: string[];
  tracecoins_amount: number;
  price: number;
  price_inr: number;
  duration_days: number | null;
  valid_from: string | null;
  valid_until: string | null;
  is_promotional: boolean;
  is_active: boolean;
  features: any;
  created_at: string;
  updated_at: string;
}

export interface CreatePackageInput {
  name: string;
  description?: string;
  package_type: string;
  applicable_roles?: string[];
  role_key?: string;
  tracecoins_amount: number;
  price: number;
  price_inr?: number;
  duration_days?: number;
  valid_from?: string;
  valid_until?: string;
  is_promotional?: boolean;
  is_active?: boolean;
  features?: any;
}

export interface UpdatePackageInput {
  name?: string;
  description?: string;
  applicable_roles?: string[];
  tracecoins_amount?: number;
  price?: number;
  price_inr?: number;
  duration_days?: number;
  valid_from?: string;
  valid_until?: string;
  is_promotional?: boolean;
  is_active?: boolean;
  features?: any;
}

export async function listAdminPackages(): Promise<AdminPackage[]> {
  const res = await api.get<{ packages: AdminPackage[] } | AdminPackage[]>(`/api/admin/tracecoin-packages`);
  const raw = res.data;
  return Array.isArray(raw) ? raw : (raw as { packages: AdminPackage[] }).packages ?? [];
}

export async function createAdminPackage(input: CreatePackageInput) {
  return api.post<AdminPackage>(`/api/admin/tracecoin-packages`, input);
}

export async function updateAdminPackage(id: string, input: UpdatePackageInput) {
  return api.patch<AdminPackage>(`/api/admin/tracecoin-packages/${id}`, input);
}

export async function deleteAdminPackage(id: string) {
  return api.delete<{ message?: string }>(`/api/admin/tracecoin-packages/${id}`);
}

// ──────────────────────────────────────────────────────────────────────────
// Credits (admin)
// ──────────────────────────────────────────────────────────────────────────

export type LedgerTypeFilter = "CREDIT" | "DEBIT" | "RESERVE" | "RELEASE" | "ADJUSTMENT";

export interface AdminLedgerEntry {
  id: string;
  wallet_id: string;
  user_id: string;
  user_email: string | null;
  entry_type: string;
  amount: number;
  balance_after: number | null;
  reason: string | null;
  reference_id: string | null;
  actor_user_id: string | null;
  metadata: any;
  created_at: string;
}

export interface AdminWallet {
  user_id: string;
  balance: number;
  reserved: number;
  available: number;
  updated_at: string;
}

export interface AdminReconcileRow {
  user_id: string;
  user_email: string | null;
  expected_balance: number;
  actual_balance: number;
  discrepancy: number;
}

export async function getAdminCreditBalance(userId: string) {
  return api.get<AdminWallet>(
    `/api/admin/credits/balance?userId=${encodeURIComponent(userId)}`,
  );
}

export async function getAdminCreditLedger(
  userId: string,
  params?: { page?: number; limit?: number; type?: LedgerTypeFilter },
) {
  const qp = new URLSearchParams();
  qp.set("userId", userId);
  if (params?.page) qp.set("page", String(params.page));
  if (params?.limit) qp.set("limit", String(params.limit));
  if (params?.type) qp.set("type", params.type);
  return api.get<{ entries: AdminLedgerEntry[]; page: number; limit: number }>(
    `/api/admin/credits/ledger?${qp.toString()}`,
  );
}

export interface AdminAdjustInput {
  user_id: string;
  amount: number;
  type: "ADD" | "DEDUCT";
  reason: string;
  reference_id?: string;
}

export async function adjustAdminCredits(input: AdminAdjustInput) {
  return api.post<{
    message: string;
    user_id: string;
    amount: number;
    balance: number;
    reserved: number;
    available: number;
    ledger_entry_id: string;
    audit_logged: boolean;
  }>(`/api/admin/credits/adjust`, input);
}

export async function reconcileAdminCredits(params?: { from?: string; to?: string }) {
  const qp = new URLSearchParams();
  if (params?.from) qp.set("from", params.from);
  if (params?.to) qp.set("to", params.to);
  const q = qp.toString();
  return api.get<{
    results: AdminReconcileRow[];
    from: string;
    to: string;
  }>(`/api/admin/credits/reconcile${q ? `?${q}` : ""}`);
}

export async function listAdminLedger(params?: {
  user_id?: string;
  page?: number;
  limit?: number;
}) {
  const qp = new URLSearchParams();
  if (params?.user_id) qp.set("user_id", params.user_id);
  if (params?.page) qp.set("page", String(params.page));
  if (params?.limit) qp.set("limit", String(params.limit));
  const q = qp.toString();
  return api.get<{ entries: AdminLedgerEntry[]; page: number; limit: number }>(
    `/api/admin/ledger${q ? `?${q}` : ""}`,
  );
}

