import { apiClient } from "./client";
import type { OptionFilter } from "@/lib/registry/components/input/use-option-loader";

export type StatsAggregation =
  | "count"
  | "sum"
  | "avg"
  | "min"
  | "max"
  | "distinctCount";

/**
 * AggregateRequest — 백엔드 `/api/table-management/tables/{tableName}/aggregate` body.
 *
 * filters 는 `OptionFilter[]` 와 동일한 모양으로 보낸다. 단, `value_type` / `field_ref` /
 * `user_field` 는 호출자가 미리 실제 값으로 치환해서 `value` 만 남긴 상태여야 한다 — 백엔드는
 * 그 외 필드를 무시한다.
 */
export interface AggregateRequest {
  aggregation: StatsAggregation;
  columnName?: string;
  filters?: Array<Pick<OptionFilter, "column" | "operator" | "value">>;
}

export interface AggregateResponse {
  value: number;
}

/**
 * aggregateTableStat — 단일 stat 카드 값을 백엔드에서 계산해 가져온다.
 *
 * 디자인 모드 / 빈 tableName 가드는 호출자가 책임진다.
 * 실패 시 axios error 가 그대로 throw 됨 — 상위 hook 에서 카드 단위 fallback.
 */
export async function aggregateTableStat(
  tableName: string,
  request: AggregateRequest,
): Promise<AggregateResponse> {
  const res = await apiClient.post(
    `/table-management/tables/${encodeURIComponent(tableName)}/aggregate`,
    request,
  );
  const body = res.data;
  // ApiResponse<{ value: number }> wrapper. value 는 number 또는 numeric string 가능.
  const payload = (body?.data ?? body) as { value?: unknown };
  const raw = payload?.value;
  const value =
    typeof raw === "number"
      ? raw
      : typeof raw === "string" && raw.trim() !== ""
        ? Number(raw)
        : 0;
  return { value: Number.isFinite(value) ? value : 0 };
}

/**
 * AggregateGroupRequest — Phase G.3 canonical chart 컴포넌트가 사용하는
 * `/aggregate-group` body.
 *
 * 백엔드가 `GROUP BY <groupBy>` 후 각 그룹마다 단일 집계 값을 계산해 row 배열로 반환.
 * `valueColumn` 는 `aggregation === "count"` 일 때 생략 가능. distinctCount / sum /
 * avg / min / max 는 valueColumn 필수 (백엔드 측 가드).
 */
export interface AggregateGroupRequest {
  aggregation: StatsAggregation;
  groupBy: string;
  valueColumn?: string;
  filters?: Array<Pick<OptionFilter, "column" | "operator" | "value">>;
  limit?: number;
  orderDir?: "asc" | "desc";
}

export interface AggregateGroupRow {
  /** GROUP BY 컬럼의 raw 값. null 가능. */
  group: string | number | null;
  /** 집계 결과 (숫자). */
  value: number;
}

export interface AggregateGroupResponse {
  rows: AggregateGroupRow[];
}

/**
 * aggregateTableGroup — 그룹별 집계.
 *
 * 호출자는 디자인 모드 / 빈 tableName / 빈 groupBy 가드를 책임진다. 실패는 axios
 * error 로 throw 된다.
 */
export async function aggregateTableGroup(
  tableName: string,
  request: AggregateGroupRequest,
): Promise<AggregateGroupResponse> {
  const res = await apiClient.post(
    `/table-management/tables/${encodeURIComponent(tableName)}/aggregate-group`,
    request,
  );
  const body = res.data;
  const payload = (body?.data ?? body) as { rows?: unknown };
  const rawRows = Array.isArray(payload?.rows) ? (payload!.rows as any[]) : [];
  const rows: AggregateGroupRow[] = rawRows.map((r) => {
    const v = r?.value;
    const num =
      typeof v === "number"
        ? v
        : typeof v === "string" && v.trim() !== ""
          ? Number(v)
          : 0;
    return {
      group: r?.group ?? null,
      value: Number.isFinite(num) ? num : 0,
    };
  });
  return { rows };
}

/**
 * SelectRowsRequest — Phase G.3.1 canonical cardList / groupedTable 가 사용하는
 * `/select-rows` body.
 *
 * 단순 SELECT — 필터 / 정렬 / limit 만 적용해서 raw row 들을 받는다. column 단일
 * 집계가 아니라 multi-column row 가 필요한 view 컴포넌트용.
 */
export interface SelectRowsOrderBy {
  column: string;
  direction?: "asc" | "desc";
}

export interface SelectRowsRequest {
  columns?: string[];
  filters?: Array<Pick<OptionFilter, "column" | "operator" | "value">>;
  orderBy?: SelectRowsOrderBy[];
  limit?: number;
  offset?: number;
}

export interface SelectRowsResponse {
  rows: Record<string, any>[];
}

/**
 * selectTableRows — multi-column row 들을 받아오는 가벼운 SELECT.
 *
 * 호출자는 디자인 모드 / 빈 tableName 가드를 책임진다. 실패는 axios error 로 throw.
 */
export async function selectTableRows(
  tableName: string,
  request: SelectRowsRequest,
): Promise<SelectRowsResponse> {
  const res = await apiClient.post(
    `/table-management/tables/${encodeURIComponent(tableName)}/select-rows`,
    request,
  );
  const body = res.data;
  const payload = (body?.data ?? body) as { rows?: unknown };
  const rawRows = Array.isArray(payload?.rows)
    ? (payload!.rows as Record<string, any>[])
    : [];
  return { rows: rawRows };
}
