import { getAuthToken } from "@/utils/token";
import type { ListDetails, ListNewRequest, ListSummary } from "@/lib/api/types.gen";
import { NONE_SELECT_VALUE, type ListRecord, type ListType, type SelectOption } from "./types";

interface BrapiPagination {
  currentPage: number;
  pageSize: number;
  totalCount: number;
  totalPages: number;
}

interface BrapiListResponse<T> {
  metadata: {
    pagination: BrapiPagination;
    status: Array<Record<string, unknown>>;
    datafiles: Array<Record<string, unknown>>;
  };
  result: {
    data: T[];
  };
}

interface BrapiSingleResponse<T> {
  metadata: {
    pagination: BrapiPagination;
    status: Array<Record<string, unknown>>;
    datafiles: Array<Record<string, unknown>>;
  };
  result: T;
}

interface PersonResponse {
  personDbId: string;
  firstName?: string | null;
  lastName?: string | null;
  emailAddress?: string | null;
}

type ListPayload = Partial<Record<
  | "listName"
  | "list_name"
  | "listType"
  | "list_type"
  | "listDescription"
  | "list_description"
  | "listSource"
  | "list_source"
  | "listOwnerName"
  | "list_owner_name"
  | "listOwnerPersonDbId"
  | "list_owner_person_id"
  | "data",
  unknown
>>;

const apiBase = () => {
  if (typeof window !== "undefined") return "";
  return process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000";
};

async function request<T>(path: string, init?: RequestInit): Promise<T> {
  const token = getAuthToken();
  const response = await fetch(`${apiBase()}${path}`, {
    ...init,
    headers: {
      "Content-Type": "application/json",
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      ...(init?.headers || {}),
    },
  });

  if (!response.ok) {
    const detail = await response.text();
    throw new Error(detail || `请求失败：${response.status}`);
  }
  return response.json() as Promise<T>;
}

const optionalText = (value: unknown) => {
  const normalized = String(value ?? "").trim();
  if (!normalized || normalized === NONE_SELECT_VALUE) return undefined;
  return normalized;
};

const requiredText = (value: unknown, message: string) => {
  const normalized = optionalText(value);
  if (!normalized) throw new Error(message);
  return normalized;
};

const requiredListType = (value: unknown): ListType => {
  const normalized = optionalText(value);
  if (!normalized) throw new Error("请选择列表类型");
  return normalized as ListType;
};

export const mapListRecord = (list: ListSummary | ListDetails): ListRecord => ({
  ...list,
  id: list.listDbId || "",
  list_name: list.listName ?? null,
  list_description: list.listDescription ?? null,
  list_source: list.listSource ?? null,
  list_owner_name: list.listOwnerName ?? null,
  list_owner_person_id: list.listOwnerPersonDbId ?? null,
  list_type: list.listType ?? null,
  date_created: list.dateCreated ?? null,
  date_modified: list.dateModified ?? null,
  data: "data" in list && list.data ? list.data : [],
});

const toRequestBody = (payload: ListPayload, data?: string[]): ListNewRequest => ({
  listName: requiredText(payload.listName ?? payload.list_name, "???????"),
  listType: requiredListType(payload.listType ?? payload.list_type),
  listDescription: optionalText(payload.listDescription ?? payload.list_description),
  listSource: optionalText(payload.listSource ?? payload.list_source),
  listOwnerName: optionalText(payload.listOwnerName ?? payload.list_owner_name),
  listOwnerPersonDbId: optionalText(payload.listOwnerPersonDbId ?? payload.list_owner_person_id),
  ...(data !== undefined ? { data } : {}),
});

export async function fetchListRows(): Promise<ListRecord[]> {
  const response = await request<BrapiListResponse<ListSummary>>("/brapi/v2/lists?page=0&pageSize=10");
  return response.result.data.map(mapListRecord);
}

export async function fetchListDetail(listDbId: string): Promise<ListRecord> {
  const response = await request<BrapiSingleResponse<ListDetails>>(`/brapi/v2/lists/${encodeURIComponent(listDbId)}`);
  return mapListRecord(response.result);
}

export async function fetchPersonOptions(): Promise<SelectOption[]> {
  const response = await request<BrapiListResponse<PersonResponse>>("/brapi/v2/people?page=0&pageSize=10");
  return response.result.data.map((person) => {
    const name = [person.firstName, person.lastName].filter(Boolean).join(" ").trim();
    const label = name
      ? `${name}${person.emailAddress ? ` / ${person.emailAddress}` : ""}`
      : person.personDbId;
    return { value: person.personDbId, label };
  });
}

export async function createListRow(payload: ListPayload): Promise<ListRecord> {
  const response = await request<BrapiListResponse<ListSummary>>("/brapi/v2/lists", {
    method: "POST",
    body: JSON.stringify([toRequestBody(payload)]),
  });
  return mapListRecord(response.result.data[0]);
}

export async function updateListRow(listDbId: string, payload: ListPayload, data?: string[]): Promise<ListRecord> {
  const response = await request<BrapiSingleResponse<ListDetails>>(`/brapi/v2/lists/${encodeURIComponent(listDbId)}`, {
    method: "PUT",
    body: JSON.stringify(toRequestBody(payload, data)),
  });
  return mapListRecord(response.result);
}

export async function appendListItems(listDbId: string, items: string[]): Promise<ListRecord> {
  const response = await request<BrapiSingleResponse<ListDetails>>(`/brapi/v2/lists/${encodeURIComponent(listDbId)}/items`, {
    method: "POST",
    body: JSON.stringify(items),
  });
  return mapListRecord(response.result);
}

export async function replaceListItems(listDbId: string, items: string[]): Promise<ListRecord> {
  const detail = await fetchListDetail(listDbId);
  return updateListRow(
    listDbId,
    {
      listName: detail.listName,
      listType: detail.listType,
      listDescription: detail.listDescription,
      listSource: detail.listSource,
      listOwnerName: detail.listOwnerName,
      listOwnerPersonDbId: detail.listOwnerPersonDbId,
    },
    items,
  );
}

export function normalizeNewItems(existing: string[], incoming: string[]): string[] {
  const seen = new Set(existing.map((item) => item.trim()).filter(Boolean));
  const duplicates: string[] = [];
  const added: string[] = [];

  for (const raw of incoming) {
    const item = raw.trim();
    if (!item) continue;
    if (seen.has(item)) {
      duplicates.push(item);
      continue;
    }
    seen.add(item);
    added.push(item);
  }

  if (duplicates.length > 0) {
    throw new Error(`以下列表项已存在：${duplicates.join("、")}`);
  }
  if (added.length === 0) {
    throw new Error("请至少填写一个有效的列表");
  }
  return added;
}
