import type { Passenger } from '@edr/types';

import { apiClient } from '@/lib/api-client';

type ConversationDto = Passenger.PassengerSupportConversationDto;
type MessageDto = Passenger.PassengerSupportMessageDto;
type ListResult = Passenger.PassengerSupportConversationListResult;
type MessageListResult = Passenger.PassengerSupportMessageListResult;

export interface ListParams {
  status?: string;
  search?: string;
  page?: number;
  limit?: number;
}

export interface ListMessagesParams {
  /** Opaque cursor from the previous page's `nextCursor`. */
  before?: string;
  limit?: number;
}

/** What the composer hands over: text, files, or both (never neither). */
export interface SendMessageInput {
  text?: string;
  attachments?: File[];
}

/**
 * A message with files goes as multipart so the server can persist them against
 * the message it creates in the same request; text-only stays JSON.
 */
function toRequestBody(input: SendMessageInput): FormData | { text?: string } {
  if (!input.attachments?.length) return { text: input.text };

  const form = new FormData();
  if (input.text) form.append('text', input.text);
  for (const file of input.attachments) form.append('attachments', file);
  return form;
}

/**
 * `apiClient` pins `Content-Type: application/json` on every request. Axios
 * reads that header in `transformRequest` and, seeing JSON, runs FormData
 * through `formDataToJSON` — the files would be silently dropped and the server
 * would store an empty message. Clearing the header (rather than setting
 * `multipart/form-data` by hand, which omits the boundary) is what lets the
 * browser generate a proper boundary of its own.
 */
const multipartConfig = { headers: { 'Content-Type': undefined } };

/** Passenger backoffice (agent) support-chat REST calls (client unwraps envelope). */
export const supportApi = {
  listConversations: (params: ListParams = {}) =>
    apiClient.get<ListResult>('/support/agent/conversations', { params }),
  listMessages: (id: string, params: ListMessagesParams = {}) =>
    apiClient.get<MessageListResult>(`/support/agent/conversations/${id}/messages`, { params }),
  sendMessage: (id: string, input: SendMessageInput) => {
    const body = toRequestBody(input);
    return apiClient.post<MessageDto>(
      `/support/agent/conversations/${id}/messages`,
      body,
      body instanceof FormData ? multipartConfig : undefined,
    );
  },
  /**
   * Attachment bytes, fetched through this client so the bearer token rides along
   * — the guard reads `Authorization` only, so a direct `<img src>` would 401.
   *
   * `relativeUrl` is the DTO's `url` (`/support/attachments/:id`); the passenger
   * API has no global prefix, so it appends to the client's baseURL as-is.
   */
  fetchAttachment: async (relativeUrl: string): Promise<Blob> => {
    const data = await apiClient.getRaw<Blob>(relativeUrl, { responseType: 'blob' });
    return data;
  },
  setStatus: (id: string, status: string) =>
    apiClient.patch<ConversationDto>(`/support/agent/conversations/${id}/status`, { status }),
  markRead: (id: string) =>
    apiClient.post<{ unreadCount: number }>(`/support/agent/conversations/${id}/read`),
  unreadCount: () => apiClient.get<{ unreadCount: number }>('/support/agent/unread-count'),
};
