"use server";

import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";

import { apiBaseUrl, getAuthHeaders, getErrorMessage } from "@/lib";
import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper";
import { ManageGroupPayload, ProviderGroupsResponse } from "@/types/components";

export const getProviderGroups = async ({
  page = 1,
  query = "",
  sort = "",
  filters = {},
  pageSize = 10,
}: {
  page?: number;
  query?: string;
  sort?: string;
  filters?: Record<string, string | number>;
  pageSize?: number;
}): Promise<ProviderGroupsResponse | undefined> => {
  const headers = await getAuthHeaders({ contentType: false });

  if (isNaN(Number(page)) || page < 1)
    redirect("/providers?tab=provider-groups");

  const url = new URL(`${apiBaseUrl}/provider-groups`);

  if (page) url.searchParams.append("page[number]", page.toString());
  if (pageSize) url.searchParams.append("page[size]", pageSize.toString());
  if (query) url.searchParams.append("filter[search]", query);
  if (sort) url.searchParams.append("sort", sort);

  // Handle multiple filters
  Object.entries(filters).forEach(([key, value]) => {
    if (key !== "filter[search]") {
      url.searchParams.append(key, String(value));
    }
  });

  try {
    const response = await fetch(url.toString(), {
      headers,
    });

    return await handleApiResponse(response);
  } catch (error) {
    console.error("Error fetching provider groups:", error);
    return undefined;
  }
};

/**
 * Fetches all provider groups by iterating through every page.
 * Used to populate filter dropdowns (e.g. the Provider Group selector) without
 * the pagination cap that `getProviderGroups` applies for the management table.
 */
export const getAllProviderGroups = async (): Promise<
  ProviderGroupsResponse | undefined
> => {
  const pageSize = 100; // Larger page size to minimize API calls
  const maxPages = 50; // Safety limit: 50 pages × 100 = 5000 groups max
  let currentPage = 1;
  const allGroups: ProviderGroupsResponse["data"] = [];
  let lastResponse: ProviderGroupsResponse | undefined;
  let hasMorePages = true;

  try {
    const headers = await getAuthHeaders({ contentType: false });
    while (hasMorePages && currentPage <= maxPages) {
      const url = new URL(`${apiBaseUrl}/provider-groups`);
      url.searchParams.append("page[number]", currentPage.toString());
      url.searchParams.append("page[size]", pageSize.toString());

      const response = await fetch(url.toString(), { headers });
      const data = (await handleApiResponse(response)) as
        | ProviderGroupsResponse
        | { error: string; status?: number }
        | undefined;

      // A later page resolving to an API error payload must abort rather than
      // be treated as "no more pages", which would silently truncate groups.
      if (data && "error" in data) {
        console.error("Error fetching all provider groups:", data.error);
        return undefined;
      }

      if (!data?.data || data.data.length === 0) {
        hasMorePages = false;
        continue;
      }

      allGroups.push(...data.data);
      lastResponse = data;

      const totalPages = data.meta?.pagination?.pages || 1;
      if (currentPage >= totalPages) {
        hasMorePages = false;
      } else {
        currentPage++;
      }
    }

    if (hasMorePages && currentPage > maxPages) {
      console.error(
        `Error fetching all provider groups: exceeded max page limit (${maxPages})`,
      );
      return undefined;
    }

    if (lastResponse) {
      return {
        ...lastResponse,
        data: allGroups,
        meta: {
          ...lastResponse.meta,
          pagination: {
            ...lastResponse.meta?.pagination,
            page: 1,
            pages: 1,
            count: allGroups.length,
          },
        },
      };
    }

    return undefined;
  } catch (error) {
    console.error("Error fetching all provider groups:", error);
    return undefined;
  }
};

export const getProviderGroupInfoById = async (providerGroupId: string) => {
  const headers = await getAuthHeaders({ contentType: false });
  const url = new URL(`${apiBaseUrl}/provider-groups/${providerGroupId}`);

  try {
    const response = await fetch(url.toString(), {
      method: "GET",
      headers,
    });

    return await handleApiResponse(response);
  } catch (error) {
    handleApiError(error);
  }
};

export const createProviderGroup = async (formData: FormData) => {
  const headers = await getAuthHeaders({ contentType: true });

  const name = formData.get("name") as string;
  const providersJson = formData.get("providers") as string;
  const rolesJson = formData.get("roles") as string;

  // Parse JSON strings and handle empty cases
  const providers = providersJson ? JSON.parse(providersJson) : [];
  const roles = rolesJson ? JSON.parse(rolesJson) : [];

  // Prepare base payload
  const payload: any = {
    data: {
      type: "provider-groups",
      attributes: {
        name,
      },
      relationships: {},
    },
  };

  // Add relationships only if there are items
  if (providers.length > 0) {
    payload.data.relationships.providers = {
      data: providers,
    };
  }

  if (roles.length > 0) {
    payload.data.relationships.roles = {
      data: roles,
    };
  }

  const body = JSON.stringify(payload);

  try {
    const url = new URL(`${apiBaseUrl}/provider-groups`);
    const response = await fetch(url.toString(), {
      method: "POST",
      headers,
      body,
    });

    return await handleApiResponse(response, "/providers?tab=provider-groups");
  } catch (error) {
    handleApiError(error);
  }
};

export const updateProviderGroup = async (
  providerGroupId: string,
  formData: FormData,
) => {
  const headers = await getAuthHeaders({ contentType: true });

  const name = formData.get("name") as string;
  const providersJson = formData.get("providers") as string;
  const rolesJson = formData.get("roles") as string;

  const providers = providersJson ? JSON.parse(providersJson) : null;
  const roles = rolesJson ? JSON.parse(rolesJson) : null;

  const payload: Partial<ManageGroupPayload> = {
    data: {
      type: "provider-groups",
      id: providerGroupId,
      attributes: name ? { name } : undefined,
      relationships: {},
    },
  };

  // Add relationships only if changes are detected
  if (providers) {
    payload.data!.relationships!.providers = { data: providers };
  }

  if (roles) {
    payload.data!.relationships!.roles = { data: roles };
  }

  try {
    const url = `${apiBaseUrl}/provider-groups/${providerGroupId}`;
    const response = await fetch(url, {
      method: "PATCH",
      headers,
      body: JSON.stringify(payload),
    });

    return await handleApiResponse(response);
  } catch (error) {
    handleApiError(error);
  }
};

export const deleteProviderGroup = async (formData: FormData) => {
  const headers = await getAuthHeaders({ contentType: false });
  const providerGroupId = formData.get("id");

  if (!providerGroupId) {
    return {
      errors: [{ detail: "Provider Group ID is required." }],
    };
  }

  const url = new URL(`${apiBaseUrl}/provider-groups/${providerGroupId}`);

  try {
    const response = await fetch(url.toString(), {
      method: "DELETE",
      headers,
    });

    if (!response.ok) {
      try {
        const errorData = await response.json();
        throw new Error(
          errorData?.message || "Failed to delete the provider group",
        );
      } catch {
        throw new Error("Failed to delete the provider group");
      }
    }

    let data = null;
    if (response.status !== 204) {
      data = await response.json();
    }

    revalidatePath("/providers");
    return data || { success: true };
  } catch (error) {
    console.error("Error deleting provider group:", error);
    const message = getErrorMessage(error);
    return { errors: [{ detail: message }] };
  }
};
