import { apiUrl } from "./api-base";

async function request<T>(path: string, options?: RequestInit): Promise<T> {
  const token = typeof window !== "undefined" ? localStorage.getItem("bbe_token") : null;
  const headers: HeadersInit = {
    "Content-Type": "application/json",
    ...(token ? { Authorization: `Bearer ${token}` } : {}),
    ...options?.headers,
  };

  const res = await fetch(apiUrl(path), { ...options, headers });
  if (!res.ok) {
    const error = await res.json().catch(() => ({ message: "Request failed" }));
    throw new Error(error.message || error.error || `HTTP ${res.status}`);
  }
  return res.json();
}

export const api = {
  // Auth
  getChallenge: (pubkey: string) =>
    request<{ challenge: string }>("/auth/challenge", {
      method: "POST",
      body: JSON.stringify({ pubkey }),
    }),
  verify: (pubkey: string, signedEvent: any) =>
    request<{
      token: string;
      user: {
        pubkey: string;
        role: string;
        isSuperAdmin?: boolean;
        permissions?: string[];
        username?: string;
      };
    }>("/auth/verify", {
      method: "POST",
      body: JSON.stringify({ pubkey, signedEvent }),
    }),
  getMe: () =>
    request<{
      pubkey: string;
      role: string;
      isSuperAdmin: boolean;
      permissions: string[];
      username?: string;
    }>("/auth/me"),

  // Posts
  getPosts: (params?: { category?: string; page?: number; limit?: number; all?: boolean }) => {
    const searchParams = new URLSearchParams();
    if (params?.category) searchParams.set("category", params.category);
    if (params?.page) searchParams.set("page", String(params.page));
    if (params?.limit) searchParams.set("limit", String(params.limit));
    if (params?.all) searchParams.set("all", "true");
    return request<{ posts: any[]; total: number }>(`/posts?${searchParams}`);
  },
  getPost: (slug: string) => request<any>(`/posts/${slug}`),
  getPostReactions: (slug: string) =>
    request<{ count: number; reactions: any[] }>(`/posts/${slug}/reactions`),
  getPostReplies: (slug: string) =>
    request<{ count: number; replies: any[] }>(`/posts/${slug}/replies`),
  importPost: (data: {
    nostrEventId: string;
    naddr?: string;
    title: string;
    excerpt?: string;
    authorPubkey: string;
    publishedAt?: number;
    tags?: string[];
  }) =>
    request<any>("/posts/import", { method: "POST", body: JSON.stringify(data) }),
  updatePost: (id: string, data: any) =>
    request<any>(`/posts/${id}`, { method: "PATCH", body: JSON.stringify(data) }),
  deletePost: (id: string) =>
    request<void>(`/posts/${id}`, { method: "DELETE" }),

  // Meetups
  getMeetups: (params?: { status?: string; admin?: boolean; organizerSlug?: string }) => {
    const searchParams = new URLSearchParams();
    if (params?.status) searchParams.set("status", params.status);
    if (params?.admin) searchParams.set("admin", "true");
    if (params?.organizerSlug) searchParams.set("organizerSlug", params.organizerSlug);
    const qs = searchParams.toString();
    return request<any[]>(`/meetups${qs ? `?${qs}` : ""}`);
  },
  getMeetup: (id: string) => request<any>(`/meetups/${id}`),
  createMeetup: (data: any) =>
    request<any>("/meetups", { method: "POST", body: JSON.stringify(data) }),
  updateMeetup: (id: string, data: any) =>
    request<any>(`/meetups/${id}`, { method: "PATCH", body: JSON.stringify(data) }),
  deleteMeetup: (id: string) =>
    request<void>(`/meetups/${id}`, { method: "DELETE" }),
  duplicateMeetup: (id: string) =>
    request<any>(`/meetups/${id}/duplicate`, { method: "POST" }),
  bulkMeetupAction: (action: string, ids: string[]) =>
    request<any>("/meetups/bulk", { method: "POST", body: JSON.stringify({ action, ids }) }),

  // Moderation
  getHiddenContent: () => request<any[]>("/moderation/hidden"),
  hideContent: (nostrEventId: string, reason?: string) =>
    request<any>("/moderation/hide", { method: "POST", body: JSON.stringify({ nostrEventId, reason }) }),
  unhideContent: (id: string) =>
    request<void>(`/moderation/unhide/${id}`, { method: "DELETE" }),
  getBlockedPubkeys: () => request<any[]>("/moderation/blocked"),
  blockPubkey: (pubkey: string, reason?: string) =>
    request<any>("/moderation/block", { method: "POST", body: JSON.stringify({ pubkey, reason }) }),
  unblockPubkey: (id: string) =>
    request<void>(`/moderation/unblock/${id}`, { method: "DELETE" }),

  // Users
  getUsers: () => request<any[]>("/users"),
  createUser: (pubkey: string) =>
    request<any>("/users", { method: "POST", body: JSON.stringify({ pubkey }) }),
  setUserRole: (pubkey: string, role: string | null) =>
    request<any>(`/users/${encodeURIComponent(pubkey)}/role`, {
      method: "PUT",
      body: JSON.stringify({ role }),
    }),
  updateUserUsername: (pubkey: string, username: string) =>
    request<any>(`/users/${encodeURIComponent(pubkey)}`, {
      method: "PATCH",
      body: JSON.stringify({ username }),
    }),

  // Roles and permissions
  getPermissionRegistry: () =>
    request<{ permissions: { key: string; label: string; group: string }[]; roles: string[] }>(
      "/admin/permissions"
    ),
  getRolePermissions: () =>
    request<{ roles: { role: string; permissions: string[] }[] }>("/admin/roles"),
  updateRolePermissions: (role: string, permissions: string[]) =>
    request<{ role: string; permissions: string[] }>(
      `/admin/roles/${encodeURIComponent(role)}/permissions`,
      { method: "PUT", body: JSON.stringify({ permissions }) }
    ),

  // API keys
  getApiKeys: () => request<any[]>("/api-keys"),
  createApiKey: (data: { name: string; permissions: string[] }) =>
    request<any>("/api-keys", { method: "POST", body: JSON.stringify(data) }),
  revokeApiKey: (id: string) =>
    request<any>(`/api-keys/${encodeURIComponent(id)}`, { method: "DELETE" }),

  // Categories
  getCategories: () => request<any[]>("/categories"),
  createCategory: (data: { name: string; slug: string }) =>
    request<any>("/categories", { method: "POST", body: JSON.stringify(data) }),
  updateCategory: (id: string, data: any) =>
    request<any>(`/categories/${id}`, { method: "PATCH", body: JSON.stringify(data) }),
  deleteCategory: (id: string) =>
    request<void>(`/categories/${id}`, { method: "DELETE" }),

  // Organizers
  getOrganizers: () => request<any[]>("/organizers"),
  getOrganizerBySlug: (slug: string) =>
    request<any>(`/organizers/by-slug/${encodeURIComponent(slug)}`),
  createOrganizer: (data: { name: string; slug: string }) =>
    request<any>("/organizers", { method: "POST", body: JSON.stringify(data) }),
  updateOrganizer: (id: string, data: { name?: string; slug?: string }) =>
    request<any>(`/organizers/${id}`, { method: "PATCH", body: JSON.stringify(data) }),
  deleteOrganizer: (id: string) =>
    request<void>(`/organizers/${id}`, { method: "DELETE" }),

  // Relays
  getPublicRelays: () => request<{ relays: string[] }>("/relays/public"),
  getRelays: () => request<any[]>("/relays"),
  addRelay: (data: { url: string; priority?: number }) =>
    request<any>("/relays", { method: "POST", body: JSON.stringify(data) }),
  updateRelay: (id: string, data: any) =>
    request<any>(`/relays/${id}`, { method: "PATCH", body: JSON.stringify(data) }),
  deleteRelay: (id: string) =>
    request<void>(`/relays/${id}`, { method: "DELETE" }),
  testRelay: (id: string) =>
    request<{ success: boolean }>(`/relays/${id}/test`, { method: "POST" }),

  // User Relays
  getUserRelays: () =>
    request<any[]>("/user-relays"),
  addUserRelay: (data: { url: string; read?: boolean; write?: boolean }) =>
    request<any>("/user-relays", { method: "POST", body: JSON.stringify(data) }),
  removeUserRelay: (id: string) =>
    request<void>(`/user-relays/${id}`, { method: "DELETE" }),
  importNip65Relays: () =>
    request<{ imported: number; total?: number; message?: string }>("/user-relays/import-nip65", { method: "POST" }),

  // Settings
  getSettings: () => request<Record<string, string>>("/settings"),
  getPublicSettings: () => request<Record<string, string>>("/settings/public"),
  updateSetting: (key: string, value: string) =>
    request<any>("/settings", { method: "PATCH", body: JSON.stringify({ key, value }) }),

  // Nostr tools
  fetchNostrEvent: (data: { eventId?: string; naddr?: string }) =>
    request<any>("/nostr/fetch", { method: "POST", body: JSON.stringify(data) }),
  refreshCache: () =>
    request<any>("/nostr/cache/refresh", { method: "POST" }),
  debugEvent: (eventId: string) =>
    request<any>(`/nostr/debug/${eventId}`),

  // Media
  uploadMedia: async (file: File) => {
    const token = typeof window !== "undefined" ? localStorage.getItem("bbe_token") : null;
    const formData = new FormData();
    formData.append("file", file);
    const res = await fetch(apiUrl("/media/upload"), {
      method: "POST",
      headers: token ? { Authorization: `Bearer ${token}` } : {},
      body: formData,
    });
    if (!res.ok) {
      const error = await res.json().catch(() => ({ message: "Upload failed" }));
      throw new Error(error.error || error.message || `HTTP ${res.status}`);
    }
    return res.json() as Promise<{ id: string; slug: string; url: string }>;
  },
  getMediaList: () => request<any[]>("/media"),
  getMedia: (id: string) => request<any>(`/media/${id}`),
  deleteMedia: (id: string) =>
    request<void>(`/media/${id}`, { method: "DELETE" }),
  updateMedia: (id: string, data: { title?: string; description?: string; altText?: string }) =>
    request<any>(`/media/${id}`, { method: "PATCH", body: JSON.stringify(data) }),

  // FAQs
  getFaqs: () => request<any[]>('/faqs'),
  getFaqsAll: () => request<any[]>('/faqs?all=true'),
  getAllFaqs: () => request<any[]>('/faqs/all'),
  createFaq: (data: { question: string; answer: string; showOnHomepage?: boolean }) =>
    request<any>('/faqs', { method: 'POST', body: JSON.stringify(data) }),
  updateFaq: (id: string, data: { question?: string; answer?: string; showOnHomepage?: boolean }) =>
    request<any>(`/faqs/${id}`, { method: 'PATCH', body: JSON.stringify(data) }),
  deleteFaq: (id: string) =>
    request<void>(`/faqs/${id}`, { method: 'DELETE' }),
  reorderFaqs: (items: { id: string; order: number }[]) =>
    request<any>('/faqs/reorder', { method: 'POST', body: JSON.stringify({ items }) }),

  // Profile (self)
  updateProfile: (data: { username?: string }) =>
    request<any>('/users/me', { method: 'PATCH', body: JSON.stringify(data) }),
  checkUsername: (username: string) =>
    request<{ available: boolean; reason?: string }>(
      `/users/me/username-check?username=${encodeURIComponent(username)}`
    ),

  // Submissions
  createSubmission: (data: { eventId?: string; naddr?: string; title: string }) =>
    request<any>("/submissions", { method: "POST", body: JSON.stringify(data) }),
  getMySubmissions: () =>
    request<any[]>("/submissions/mine"),
  getSubmissions: (status?: string) => {
    const params = status ? `?status=${status}` : "";
    return request<any[]>(`/submissions${params}`);
  },
  reviewSubmission: (id: string, data: { status: string; reviewNote?: string }) =>
    request<any>(`/submissions/${id}`, { method: "PATCH", body: JSON.stringify(data) }),

  // Message board (Lightning)
  getBoardConfig: () =>
    request<{ priceSats: number; bbeZapPubkey: string | null; bbeZapAddress: string | null }>(
      "/messages/config"
    ),
  createBoardInvoice: (data: {
    content: string;
    name?: string;
    pubkey?: string;
    profilePic?: string;
    postAsAnon?: boolean;
  }) =>
    request<{ payment_request: string; checking_id: string; payment_hash: string }>(
      "/messages/invoice",
      { method: "POST", body: JSON.stringify(data) }
    ),
  getBoardPaymentStatus: (paymentHash: string) =>
    request<{ paid: boolean; messageCreated: boolean }>(
      `/messages/payment/${encodeURIComponent(paymentHash)}/status`
    ),
  confirmBoardPayment: (paymentHash: string) =>
    request<{ ok: boolean; duplicate?: boolean; ignored?: string }>(
      `/messages/confirm/${encodeURIComponent(paymentHash)}`,
      { method: "POST" }
    ),
  getBoardMessages: () =>
    request<
      Array<{
        id: string;
        paymentHash: string;
        content: string;
        authorName: string;
        pubkey: string | null;
        profilePic: string | null;
        satsPaid: number;
        likeCount: number;
        createdAt: string;
      }>
    >("/messages"),
  likeBoardMessage: (id: string) =>
    request<{ likeCount: number }>(`/messages/${id}/like`, { method: "POST" }),
  getAdminBoardMessages: () => request<any[]>("/admin/messages"),
  hideBoardMessage: (id: string) =>
    request<any>(`/admin/messages/${id}/hide`, { method: "POST" }),
  deleteBoardMessage: (id: string) =>
    request<any>(`/admin/messages/${id}`, { method: "DELETE" }),
};
