"use client";

import {
  useMutation,
  useQuery,
  type UseMutationOptions,
  type UseMutationResult,
  type UseQueryOptions,
  type UseQueryResult,
} from "@tanstack/react-query";

// ✅ Generic utilities from lib
import {
  apiClient,
  queryKeys,
  getDataOrDefault,
  getDataOrThrow,
  type QueryParams,
} from "@/lib/api";

// ✅ Single consolidated import from domain
import {
  // Types
  type Invoice,
  type InvoiceList,
  type InvoiceSsoLink,
  type InvoiceQueryParams,
  // Schemas
  invoiceSchema,
  invoiceListSchema,
} from "@customer-portal/domain/billing";

import { type PaymentMethodList } from "@customer-portal/domain/payments";
import { useAuthSession } from "@/features/auth/services/auth.store";

// Constants
const EMPTY_INVOICE_LIST: InvoiceList = {
  invoices: [],
  pagination: {
    page: 1,
    totalItems: 0,
    totalPages: 0,
  },
};

const EMPTY_PAYMENT_METHODS: PaymentMethodList = {
  paymentMethods: [],
  totalCount: 0,
};

// Type helpers for React Query
type InvoicesQueryKey = ReturnType<typeof queryKeys.billing.invoices>;
type InvoiceQueryKey = ReturnType<typeof queryKeys.billing.invoice>;
type PaymentMethodsQueryKey = ReturnType<typeof queryKeys.billing.paymentMethods>;

type InvoicesQueryOptions = Omit<
  UseQueryOptions<InvoiceList, Error, InvoiceList, InvoicesQueryKey>,
  "queryKey" | "queryFn"
>;

type InvoiceQueryOptions = Omit<
  UseQueryOptions<Invoice, Error, Invoice, InvoiceQueryKey>,
  "queryKey" | "queryFn"
>;

type PaymentMethodsQueryOptions = Omit<
  UseQueryOptions<PaymentMethodList, Error, PaymentMethodList, PaymentMethodsQueryKey>,
  "queryKey" | "queryFn"
>;

type SsoLinkMutationOptions = UseMutationOptions<
  InvoiceSsoLink,
  Error,
  { invoiceId: number; target?: "view" | "download" | "pay" }
>;

// Helper functions
function toQueryParams(params: InvoiceQueryParams): QueryParams {
  const query: QueryParams = {};
  for (const [key, value] of Object.entries(params)) {
    if (value === undefined) {
      continue;
    }
    if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
      query[key] = value;
    }
  }
  return query;
}

// API functions
async function fetchInvoices(params?: InvoiceQueryParams): Promise<InvoiceList> {
  const query = params ? toQueryParams(params) : undefined;
  const response = await apiClient.GET<InvoiceList>(
    "/api/invoices",
    query ? { params: { query } } : undefined
  );
  const data = getDataOrDefault(response, EMPTY_INVOICE_LIST);
  return invoiceListSchema.parse(data);
}

async function fetchInvoice(id: string): Promise<Invoice> {
  const response = await apiClient.GET<Invoice>("/api/invoices/{id}", {
    params: { path: { id } },
  });
  const invoice = getDataOrThrow(response, "Invoice not found");
  return invoiceSchema.parse(invoice);
}

async function fetchPaymentMethods(): Promise<PaymentMethodList> {
  const response = await apiClient.GET<PaymentMethodList>("/api/invoices/payment-methods");
  return getDataOrDefault(response, EMPTY_PAYMENT_METHODS);
}

// Exported hooks
export function useInvoices(
  params?: InvoiceQueryParams,
  options?: InvoicesQueryOptions
): UseQueryResult<InvoiceList, Error> {
  const { isAuthenticated } = useAuthSession();
  const queryKeyParams = params ? { ...params } : undefined;
  return useQuery({
    queryKey: queryKeys.billing.invoices(queryKeyParams),
    queryFn: () => fetchInvoices(params),
    enabled: isAuthenticated,
    ...options,
  });
}

export function useInvoice(
  id: string,
  options?: InvoiceQueryOptions
): UseQueryResult<Invoice, Error> {
  const { isAuthenticated } = useAuthSession();
  return useQuery({
    queryKey: queryKeys.billing.invoice(id),
    queryFn: () => fetchInvoice(id),
    enabled: isAuthenticated && Boolean(id),
    ...options,
  });
}

export function usePaymentMethods(
  options?: PaymentMethodsQueryOptions
): UseQueryResult<PaymentMethodList, Error> {
  const { isAuthenticated } = useAuthSession();
  return useQuery({
    queryKey: queryKeys.billing.paymentMethods(),
    queryFn: fetchPaymentMethods,
    enabled: isAuthenticated,
    ...options,
  });
}

export function useCreateInvoiceSsoLink(
  options?: SsoLinkMutationOptions
): UseMutationResult<
  InvoiceSsoLink,
  Error,
  { invoiceId: number; target?: "view" | "download" | "pay" }
> {
  return useMutation({
    mutationFn: async ({ invoiceId, target }) => {
      const response = await apiClient.POST<InvoiceSsoLink>("/api/invoices/{id}/sso-link", {
        params: {
          path: { id: invoiceId },
          query: target ? { target } : undefined,
        },
      });
      return getDataOrThrow(response, "Failed to create SSO link");
    },
    ...options,
  });
}

export function useCreatePaymentMethodsSsoLink(
  options?: UseMutationOptions<InvoiceSsoLink, Error, void>
): UseMutationResult<InvoiceSsoLink, Error, void> {
  return useMutation({
    mutationFn: async () => {
      const response = await apiClient.POST<InvoiceSsoLink>("/auth/sso-link", {
        body: { destination: "index.php?rp=/account/paymentmethods" },
      });
      return getDataOrThrow(response, "Failed to create payment methods SSO link");
    },
    ...options,
  });
}
