import { API_ENDPOINTS } from '@/shared/constants/apiEndpoints';
import { api, apiClient } from '@/shared/utils/api';
import {
  isPaginatedResponse,
  type PaginatedResponse,
} from '@/shared/types/pagination.types';
import {
  type AssignTicketPayload,
  type CreateTicketPayload,
  type TicketDetail,
  type TicketListFilters,
  type TicketNote,
  type TicketReply,
  type TicketSummary,
  type UpdateTicketPayload,
  isTicketDetail,
  isTicketNote,
  isTicketReply,
  isTicketSummary,
  unwrapResource,
} from '@/features/tickets/types/ticket.types';

function buildQuery(filters: TicketListFilters): string {
  const params = new URLSearchParams();

  if (filters.page) params.set('page', String(filters.page));
  if (filters.per_page) params.set('per_page', String(filters.per_page));
  if (filters.search) params.set('search', filters.search);
  if (filters.status_id) params.set('status_id', filters.status_id);
  if (filters.priority_id) params.set('priority_id', filters.priority_id);
  if (filters.assignee_id) params.set('assignee_id', filters.assignee_id);
  if (filters.unassigned_only) params.set('unassigned_only', '1');
  if (filters.open_only) params.set('open_only', '1');
  if (filters.sort_by) params.set('sort_by', filters.sort_by);
  if (filters.sort_order) params.set('sort_order', filters.sort_order);

  const query = params.toString();
  return query ? `?${query}` : '';
}

export async function fetchTickets(
  filters: TicketListFilters = {},
): Promise<PaginatedResponse<TicketSummary>> {
  const raw: unknown = await api.get(`${API_ENDPOINTS.TICKETS.LIST}${buildQuery(filters)}`);

  if (!isPaginatedResponse(raw, isTicketSummary)) {
    throw new Error('Invalid tickets list response');
  }

  return raw;
}

export async function createTicket(payload: CreateTicketPayload): Promise<TicketSummary> {
  const raw: unknown = await api.post(API_ENDPOINTS.TICKETS.CREATE, payload);
  return unwrapResource(
    typeof raw === 'object' && raw !== null && 'data' in raw
      ? (raw as { data: unknown }).data
      : raw,
    isTicketSummary,
  );
}

export async function fetchTicket(ticketId: string): Promise<TicketDetail> {
  const raw: unknown = await api.get(API_ENDPOINTS.TICKETS.SHOW(ticketId));
  return unwrapResource(raw, isTicketDetail);
}

export async function updateTicket(
  ticketId: string,
  payload: UpdateTicketPayload,
): Promise<TicketSummary> {
  const raw: unknown = await api.put(API_ENDPOINTS.TICKETS.UPDATE(ticketId), payload);
  return unwrapResource(
    typeof raw === 'object' && raw !== null && 'data' in raw
      ? (raw as { data: unknown }).data
      : raw,
    isTicketSummary,
  );
}

export async function assignTicket(
  ticketId: string,
  payload: AssignTicketPayload,
): Promise<TicketSummary> {
  const raw: unknown = await api.post(API_ENDPOINTS.TICKETS.ASSIGN(ticketId), payload);
  return unwrapResource(
    typeof raw === 'object' && raw !== null && 'data' in raw
      ? (raw as { data: unknown }).data
      : raw,
    isTicketSummary,
  );
}

export async function unassignTicket(ticketId: string): Promise<TicketSummary> {
  const raw: unknown = await api.post(API_ENDPOINTS.TICKETS.UNASSIGN(ticketId));
  return unwrapResource(
    typeof raw === 'object' && raw !== null && 'data' in raw
      ? (raw as { data: unknown }).data
      : raw,
    isTicketSummary,
  );
}

export async function fetchTicketReplies(ticketId: string): Promise<TicketReply[]> {
  const raw: unknown = await api.get(API_ENDPOINTS.REPLIES.LIST(ticketId));

  if (Array.isArray(raw) && raw.every(isTicketReply)) {
    return raw;
  }

  if (
    typeof raw === 'object' &&
    raw !== null &&
    'data' in raw &&
    Array.isArray((raw as { data: unknown }).data)
  ) {
    const list = (raw as { data: unknown[] }).data;
    if (list.every(isTicketReply)) {
      return list;
    }
  }

  throw new Error('Invalid ticket replies response');
}

export async function createTicketReply(
  ticketId: string,
  content: string,
  attachments: File[] = [],
): Promise<TicketReply> {
  let raw: unknown;

  if (attachments.length > 0) {
    const formData = new FormData();
    formData.append('content', content);
    attachments.forEach((file) => {
      formData.append('attachments[]', file);
    });

    const response = await apiClient.post(API_ENDPOINTS.REPLIES.CREATE(ticketId), formData, {
      headers: { 'Content-Type': 'multipart/form-data' },
    });
    raw = response.data;
  } else {
    raw = await api.post(API_ENDPOINTS.REPLIES.CREATE(ticketId), { content });
  }

  return unwrapResource(
    typeof raw === 'object' && raw !== null && 'data' in raw
      ? (raw as { data: unknown }).data
      : raw,
    isTicketReply,
  );
}

export async function fetchTicketNotes(ticketId: string): Promise<TicketNote[]> {
  const raw: unknown = await api.get(API_ENDPOINTS.NOTES.LIST(ticketId));

  if (Array.isArray(raw) && raw.every(isTicketNote)) {
    return raw;
  }

  if (
    typeof raw === 'object' &&
    raw !== null &&
    'data' in raw &&
    Array.isArray((raw as { data: unknown }).data)
  ) {
    const list = (raw as { data: unknown[] }).data;
    if (list.every(isTicketNote)) {
      return list;
    }
  }

  throw new Error('Invalid ticket notes response');
}

export async function createTicketNote(
  ticketId: string,
  content: string,
): Promise<TicketNote> {
  const raw: unknown = await api.post(API_ENDPOINTS.NOTES.CREATE(ticketId), { content });
  return unwrapResource(
    typeof raw === 'object' && raw !== null && 'data' in raw
      ? (raw as { data: unknown }).data
      : raw,
    isTicketNote,
  );
}
