import { Collection } from "@discordjs/collection";
import { connectWiseApi } from "../../../constants";
import {
  CWActivity,
  CWActivitySummary,
  CWCreateActivity,
  CWPatchOperation,
} from "./activity.types";

export const activityCw = {
  /**
   * Count Activities
   *
   * Returns the total number of activities in ConnectWise.
   * Optionally accepts CW conditions string for filtered counts.
   */
  countItems: async (conditions?: string): Promise<number> => {
    const query = conditions
      ? `/sales/activities/count?conditions=${encodeURIComponent(conditions)}`
      : "/sales/activities/count";
    const response = await connectWiseApi.get(query);
    return response.data.count;
  },

  /**
   * Fetch All Activity Summaries
   *
   * Lightweight fetch returning only id and _info (for lastUpdated comparison).
   * Paginates through all activities.
   */
  fetchAllSummaries: async (): Promise<
    Collection<number, CWActivitySummary>
  > => {
    const allItems = new Collection<number, CWActivitySummary>();
    const pageSize = 1000;

    const count = await activityCw.countItems();
    const totalPages = Math.ceil(count / pageSize);

    for (let page = 0; page < totalPages; page++) {
      const response = await connectWiseApi.get(
        `/sales/activities?page=${page + 1}&pageSize=${pageSize}&fields=id,_info`,
      );
      const items: CWActivitySummary[] = response.data;

      for (const item of items) {
        allItems.set(item.id, item);
      }
    }

    return allItems;
  },

  /**
   * Fetch All Activities (Full)
   *
   * Fetches all activities with complete data. Paginates through
   * the full list. Optionally accepts CW conditions string for filtering.
   */
  fetchAll: async (
    conditions?: string,
  ): Promise<Collection<number, CWActivity>> => {
    const allItems = new Collection<number, CWActivity>();
    const pageSize = 1000;

    const count = await activityCw.countItems(conditions);
    const totalPages = Math.ceil(count / pageSize);

    for (let page = 0; page < totalPages; page++) {
      const conditionsParam = conditions
        ? `&conditions=${encodeURIComponent(conditions)}`
        : "";
      const response = await connectWiseApi.get(
        `/sales/activities?page=${page + 1}&pageSize=${pageSize}${conditionsParam}`,
      );
      const items: CWActivity[] = response.data;

      for (const item of items) {
        allItems.set(item.id, item);
      }
    }

    return allItems;
  },

  /**
   * Fetch Single Activity
   *
   * Fetches a single activity by its ConnectWise ID.
   */
  fetch: async (id: number): Promise<CWActivity> => {
    const response = await connectWiseApi.get(`/sales/activities/${id}`);
    return response.data;
  },

  /**
   * Fetch Activities by Company
   *
   * Fetches all activities associated with a specific ConnectWise company ID.
   */
  fetchByCompany: async (
    cwCompanyId: number,
  ): Promise<Collection<number, CWActivity>> => {
    return activityCw.fetchAll(`company/id=${cwCompanyId}`);
  },

  /**
   * Fetch Activities by Opportunity
   *
   * Fetches all activities associated with a specific opportunity ID.
   */
  fetchByOpportunity: async (
    opportunityId: number,
  ): Promise<Collection<number, CWActivity>> => {
    return activityCw.fetchAll(`opportunity/id=${opportunityId}`);
  },

  /**
   * Fetch Activities by Opportunity (Direct)
   *
   * Lightweight single-call variant that skips the count request.
   * Fetches up to 1000 activities in a single GET — sufficient for
   * virtually all opportunities. Used by the background cache refresh
   * to avoid doubling CW API calls.
   */
  fetchByOpportunityDirect: async (
    opportunityId: number,
  ): Promise<CWActivity[]> => {
    const conditions = encodeURIComponent(`opportunity/id=${opportunityId}`);
    const response = await connectWiseApi.get(
      `/sales/activities?pageSize=1000&conditions=${conditions}`,
    );
    return response.data;
  },

  /**
   * Create Activity
   *
   * Creates a new activity in ConnectWise.
   */
  create: async (activity: CWCreateActivity): Promise<CWActivity> => {
    const response = await connectWiseApi.post("/sales/activities", activity);
    return response.data;
  },

  /**
   * Update Activity (PATCH)
   *
   * Updates an existing activity using JSON Patch operations.
   */
  update: async (
    id: number,
    operations: CWPatchOperation[],
  ): Promise<CWActivity> => {
    const response = await connectWiseApi.patch(
      `/sales/activities/${id}`,
      operations,
    );
    return response.data;
  },

  /**
   * Replace Activity (PUT)
   *
   * Replaces an entire activity record in ConnectWise.
   */
  replace: async (
    id: number,
    activity: CWCreateActivity,
  ): Promise<CWActivity> => {
    const response = await connectWiseApi.put(
      `/sales/activities/${id}`,
      activity,
    );
    return response.data;
  },

  /**
   * Delete Activity
   *
   * Deletes an activity by its ConnectWise ID.
   */
  delete: async (id: number): Promise<void> => {
    await connectWiseApi.delete(`/sales/activities/${id}`);
  },
};
