import type {
  HelpSection,
  CreateHelpSectionPayload,
  UpdateHelpSectionPayload
} from "@/domain/entities/help-section";
import type {
  HelpSectionsPaginatorMeta,
  HelpSectionsResponse,
  HelpSectionFindAllOptions,
  HelpSectionRepository
} from "@/domain/repositories/help-section.repository";
import { apiClient } from "@/infrastructure/api/api-client";

function isPlainObject(v: unknown): v is Record<string, unknown> {
  return typeof v === "object" && v !== null && !Array.isArray(v);
}

function pickNumber(...candidates: unknown[]): number | undefined {
  for (const c of candidates) {
    if (typeof c === "number" && Number.isFinite(c)) return c;
    if (typeof c === "string" && c !== "" && !Number.isNaN(Number(c))) return Number(c);
  }
  return undefined;
}

/**
 * Mirrors the help-categories normalizer. Backend `HelpSectionCollection`
 * follows the same shape convention as `HelpSectionCollection` /
 * `HelpCategoryCollection` (custom toArray with camelCase pagination keys),
 * but we accept Laravel default / project paginated formats as a fallback.
 */
function normalize(raw: unknown): HelpSectionsResponse {
  let body: unknown = raw;
  if (
    isPlainObject(body) &&
    "data" in body &&
    body.data !== undefined &&
    ("status" in body || "message" in body)
  ) {
    body = body.data;
  }

  if (Array.isArray(body)) {
    return { data: body as HelpSection[] };
  }

  if (!isPlainObject(body)) {
    return { data: [] };
  }

  const items =
    (Array.isArray(body.help_sections) ? (body.help_sections as HelpSection[]) : undefined) ??
    (Array.isArray(body.data) ? (body.data as HelpSection[]) : undefined) ??
    (Array.isArray(body.items) ? (body.items as HelpSection[]) : undefined) ??
    [];

  const rawMeta = isPlainObject(body.meta) ? body.meta : undefined;
  const innerMeta = isPlainObject(rawMeta?.pagination) ? rawMeta!.pagination : undefined;

  const current_page = pickNumber(
    body.currentPage,
    body.current_page,
    rawMeta?.current_page,
    innerMeta?.current_page,
  );
  const last_page = pickNumber(
    body.lastPage,
    body.last_page,
    body.totalPages,
    body.total_pages,
    rawMeta?.last_page,
    innerMeta?.last_page,
    rawMeta?.total_pages,
  );
  const per_page = pickNumber(body.per_page, body.perPage, rawMeta?.per_page, innerMeta?.per_page);
  const total = pickNumber(body.total, body.count, rawMeta?.total, innerMeta?.total);

  const hasAnyMeta =
    current_page !== undefined ||
    last_page !== undefined ||
    per_page !== undefined ||
    total !== undefined;

  if (!hasAnyMeta) {
    return { data: items };
  }

  const meta: HelpSectionsPaginatorMeta = {
    current_page: current_page ?? 1,
    last_page: last_page ?? 1,
    per_page: per_page ?? items.length,
    total: total ?? items.length,
  };

  const links: Record<string, string | null> | undefined =
    typeof body.previousPageUrl !== "undefined" || typeof body.nextPageUrl !== "undefined"
      ? {
          prev: (body.previousPageUrl as string | null | undefined) ?? null,
          next: (body.nextPageUrl as string | null | undefined) ?? null,
        }
      : isPlainObject(body.links)
        ? (body.links as Record<string, string | null>)
        : undefined;

  return { data: items, meta, links };
}

export class HelpSectionRepositoryImpl implements HelpSectionRepository {
  async findAll(options?: HelpSectionFindAllOptions): Promise<HelpSectionsResponse> {
    const params: Record<string, string | number> = {};

    if (options?.all) {
      params.per_page = "all";
    } else if (options) {
      if (options.page) params.page = options.page;
      if (options.per_page) params.per_page = options.per_page;
      if (options.search) params.search = options.search;

      const sortBy = options.sort_by ?? options.order_by;
      const sortDir =
        options.sort_dir ?? (options.order ? (options.order.toLowerCase() as "asc" | "desc") : undefined);
      if (sortBy) params.sort_by = sortBy;
      if (sortDir) params.sort_dir = sortDir;
    }

    const response = await apiClient.get("/help-sections", { params });
    return normalize(response.data);
  }

  async findById(id: string | number): Promise<HelpSection> {
    const response = await apiClient.get(`/help-sections/${id}`);
    return response.data?.data || response.data;
  }

  async create(payload: CreateHelpSectionPayload): Promise<HelpSection> {
    const response = await apiClient.post("/help-sections", payload);
    return response.data?.data || response.data;
  }

  async update(id: string | number, payload: UpdateHelpSectionPayload): Promise<HelpSection> {
    const response = await apiClient.put(`/help-sections/${id}`, payload);
    return response.data?.data || response.data;
  }

  async delete(id: string | number): Promise<void> {
    await apiClient.delete(`/help-sections/${id}`);
  }
}
