import type { Cross, CrossParent, CrossingProject, PedigreeNode, PlannedCross } from "@/lib/api/types.gen";
import { getAuthToken } from "@/utils/token";
import {
  invalidateCrossPedigreeCache,
  loadCrossPedigreeSnapshot,
} from "./crossPedigreeCache";
import { mapCross, mapCrossingProject, mapPlannedCross } from "./mappers";
import {
  NONE_SELECT_VALUE,
  type CrossParentFormState,
  type CrossParentRow,
  type CrossPollinationEventRecord,
  type CrossRecord,
  type CrossingProjectDetail,
  type CrossingProjectQuery,
  type CrossingProjectRecord,
  type PedigreeEdgeFormState,
  type PedigreeEdgeRow,
  type PedigreeRecord,
  type PlannedCrossRecord,
  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;
}

type CrossingProjectPayload = Partial<Record<"name" | "description" | "program_id", unknown>>;
type PlannedCrossPayload = Partial<Record<"name" | "cross_type" | "status" | "crossing_project_id", unknown>>;
type CrossPayload = Partial<Record<"name" | "cross_type" | "crossing_project_id" | "planned_cross_id", unknown>>;
type PedigreePayload = Partial<Record<
  "germplasm_id" | "crossing_project_id" | "crossing_year" | "family_code" | "pedigree_string",
  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 null;
  return normalized;
};

const optionalNumber = (value: unknown) => {
  const normalized = optionalText(value);
  if (normalized === null) return null;
  const parsed = Number(normalized);
  return Number.isNaN(parsed) ? null : parsed;
};

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

const buildCrossParent = (
  parentType: unknown,
  germplasmId: unknown,
  observationUnitId: unknown,
): CrossParent | null => {
  const parentTypeValue = optionalText(parentType);
  const germplasmDbId = optionalText(germplasmId);
  const observationUnitDbId = optionalText(observationUnitId);
  if (!parentTypeValue && !germplasmDbId && !observationUnitDbId) return null;
  if (!parentTypeValue) throw new Error("请为已填亲本选择 parent_type");
  if (!germplasmDbId && !observationUnitDbId) throw new Error("亲本必须填写 germplasm 或 observation_unit 至少一项");
  return {
    parentType: parentTypeValue as CrossParent["parentType"],
    ...(germplasmDbId ? { germplasmDbId } : {}),
    ...(observationUnitDbId ? { observationUnitDbId } : {}),
  };
};

export { mapCross, mapCrossingProject, mapPlannedCross } from "./mappers";
export { invalidateCrossPedigreeCache, loadCrossPedigreeSnapshot } from "./crossPedigreeCache";

const invalidateAfterMutation = () => {
  invalidateCrossPedigreeCache();
};

export function normalizeCrossingProjectForm(record: CrossingProjectRecord): Record<string, unknown> {
  return {
    ...record,
    name: record.name ?? "",
    description: record.description ?? "",
    program_id: record.program_id && record.program_id !== NONE_SELECT_VALUE ? record.program_id : NONE_SELECT_VALUE,
  };
}

export function normalizePlannedCrossForm(record: PlannedCrossRecord): Record<string, unknown> {
  return {
    ...record,
    name: record.name ?? "",
    cross_type: record.cross_type && record.cross_type !== NONE_SELECT_VALUE ? record.cross_type : NONE_SELECT_VALUE,
    status: record.status && record.status !== NONE_SELECT_VALUE ? record.status : "TODO",
    crossing_project_id:
      record.crossing_project_id && record.crossing_project_id !== NONE_SELECT_VALUE
        ? record.crossing_project_id
        : NONE_SELECT_VALUE,
  };
}

export function normalizeCrossForm(record: CrossRecord): Record<string, unknown> {
  return {
    ...record,
    name: record.name ?? "",
    cross_type: record.cross_type && record.cross_type !== NONE_SELECT_VALUE ? record.cross_type : NONE_SELECT_VALUE,
    crossing_project_id:
      record.crossing_project_id && record.crossing_project_id !== NONE_SELECT_VALUE
        ? record.crossing_project_id
        : NONE_SELECT_VALUE,
    planned_cross_id:
      record.planned_cross_id && record.planned_cross_id !== NONE_SELECT_VALUE
        ? record.planned_cross_id
        : NONE_SELECT_VALUE,
  };
}

export function buildCrossParentFormState(
  crossId: string,
  planned: boolean,
  crossingProjectId: string | null,
  crossingProjectName: string | null,
  parent1: CrossParent | null | undefined,
  parent2: CrossParent | null | undefined,
): CrossParentFormState {
  return {
    cross_id: crossId,
    planned,
    crossing_project_id: crossingProjectId,
    crossing_project_name: crossingProjectName,
    parent1_type: parent1?.parentType ?? NONE_SELECT_VALUE,
    parent1_germplasm_id: parent1?.germplasmDbId ?? NONE_SELECT_VALUE,
    parent1_observation_unit_id: parent1?.observationUnitDbId ?? NONE_SELECT_VALUE,
    parent2_type: parent2?.parentType ?? NONE_SELECT_VALUE,
    parent2_germplasm_id: parent2?.germplasmDbId ?? NONE_SELECT_VALUE,
    parent2_observation_unit_id: parent2?.observationUnitDbId ?? NONE_SELECT_VALUE,
  };
}

const crossingProjectBody = (payload: CrossingProjectPayload) => {
  const programDbId = requiredText(payload.program_id, "请选择所属 Program");
  return {
    crossingProjectName: requiredText(payload.name, "请填写杂交项目名"),
    crossingProjectDescription: optionalText(payload.description),
    programDbId,
  };
};

const plannedCrossBody = (payload: PlannedCrossPayload) => ({
  plannedCrossName: requiredText(payload.name, "请填写计划杂交名"),
  crossingProjectDbId: requiredText(payload.crossing_project_id, "请选择杂交项目"),
  ...(optionalText(payload.cross_type) ? { crossType: optionalText(payload.cross_type) } : {}),
  ...(optionalText(payload.status) ? { status: optionalText(payload.status) } : { status: "TODO" }),
});

const crossBody = (payload: CrossPayload) => ({
  crossName: requiredText(payload.name, "请填写实际杂交名"),
  crossingProjectDbId: requiredText(payload.crossing_project_id, "请选择杂交项目"),
  ...(optionalText(payload.cross_type) ? { crossType: optionalText(payload.cross_type) } : {}),
  ...(optionalText(payload.planned_cross_id) ? { plannedCrossDbId: optionalText(payload.planned_cross_id) } : {}),
});

const mapPedigree = (node: PedigreeRecord & PedigreeNode): PedigreeRecord => {
  const germplasmId = node.germplasmDbId || node.germplasm_id || null;
  return {
    ...node,
    id: germplasmId || node.pedigreeNodeDbId || node.id,
    germplasmDbId: germplasmId,
    germplasm_id: germplasmId,
    germplasm_name: node.germplasm_name || node.germplasmName || null,
    crossing_project_id: node.crossing_project_id || node.crossingProjectDbId || null,
    crossing_project_name: node.crossing_project_name || node.crossingProjectName || null,
    crossing_year: node.crossing_year ?? node.crossingYear ?? null,
    family_code: node.family_code || node.familyCode || null,
    pedigree_string: node.pedigree_string || node.pedigreeString || null,
    parents: node.parents?.map((parent) => ({
      germplasmDbId: parent.germplasmDbId,
      germplasmName: parent.germplasmName,
      parentType: parent.parentType,
    })),
    siblings: node.siblings?.map((sibling) => ({
      germplasmDbId: sibling.germplasmDbId,
      germplasmName: sibling.germplasmName,
    })),
  };
};

const pedigreeBody = (payload: PedigreePayload, requireGermplasm = false) => ({
  germplasmDbId: requireGermplasm
    ? requiredText(payload.germplasm_id, "请选择 Germplasm")
    : optionalText(payload.germplasm_id),
  crossingProjectDbId: optionalText(payload.crossing_project_id),
  crossingYear: optionalNumber(payload.crossing_year),
  familyCode: optionalText(payload.family_code),
  pedigreeString: optionalText(payload.pedigree_string),
});

export function normalizePedigreeForm(record: PedigreeRecord): Record<string, unknown> {
  return {
    ...record,
    germplasm_id:
      record.germplasm_id && record.germplasm_id !== NONE_SELECT_VALUE ? record.germplasm_id : NONE_SELECT_VALUE,
    crossing_project_id:
      record.crossing_project_id && record.crossing_project_id !== NONE_SELECT_VALUE
        ? record.crossing_project_id
        : NONE_SELECT_VALUE,
    crossing_year: record.crossing_year ?? "",
    family_code: record.family_code ?? "",
    pedigree_string: record.pedigree_string ?? "",
  };
}

export function flattenPedigreeEdges(nodes: PedigreeRecord[]): PedigreeEdgeRow[] {
  const rows: PedigreeEdgeRow[] = [];
  const seen = new Set<string>();

  for (const node of nodes) {
    const thisNodeId = node.germplasm_id;
    if (!thisNodeId) continue;

    for (const parent of node.parents ?? []) {
      const connectedNodeId = parent.germplasmDbId;
      if (!connectedNodeId) continue;
      const key = `parent:${thisNodeId}:${connectedNodeId}`;
      if (seen.has(key)) continue;
      seen.add(key);
      rows.push({
        id: key,
        edge_type: "parent",
        parent_type: parent.parentType ?? null,
        this_node_id: thisNodeId,
        this_node_name: node.germplasm_name,
        connected_node_id: connectedNodeId,
        connected_node_name: parent.germplasmName ?? null,
      });
    }

    for (const sibling of node.siblings ?? []) {
      const connectedNodeId = sibling.germplasmDbId;
      if (!connectedNodeId) continue;
      const [left, right] = [thisNodeId, connectedNodeId].sort();
      const key = `sibling:${left}:${right}`;
      if (seen.has(key)) continue;
      seen.add(key);
      rows.push({
        id: key,
        edge_type: "sibling",
        parent_type: null,
        this_node_id: thisNodeId,
        this_node_name: node.germplasm_name,
        connected_node_id: connectedNodeId,
        connected_node_name: sibling.germplasmName ?? null,
        read_only: true,
      });
    }
  }

  return rows;
}

const buildParentPayload = (
  germplasmDbId: string,
  parents: Array<{ germplasmDbId?: string; parentType?: string }>,
) => ({
  germplasmDbId,
  parents: parents
    .filter((parent) => parent.germplasmDbId)
    .map((parent) => ({
      germplasmDbId: parent.germplasmDbId,
      parentType: parent.parentType,
    })),
});

async function updatePedigreeParents(
  germplasmDbId: string,
  parents: Array<{ germplasmDbId?: string; parentType?: string }>,
): Promise<void> {
  await request<BrapiListResponse<PedigreeNode>>("/brapi/v2/pedigree", {
    method: "PUT",
    body: JSON.stringify({
      [germplasmDbId]: buildParentPayload(germplasmDbId, parents),
    }),
  });
  invalidateAfterMutation();
}

export async function fetchCrossPedigreeOptions(): Promise<{
  programs: SelectOption[];
  germplasm: SelectOption[];
  crossingProjects: SelectOption[];
  plannedCrosses: SelectOption[];
  observationUnits: SelectOption[];
  crosses: SelectOption[];
}> {
  const snapshot = await loadCrossPedigreeSnapshot();
  return {
    programs: snapshot.programs,
    germplasm: snapshot.germplasm,
    crossingProjects: snapshot.crossingProjectOptions,
    plannedCrosses: snapshot.plannedCrossOptions,
    observationUnits: snapshot.observationUnits,
    crosses: snapshot.crossOptions,
  };
}

export async function fetchCrossingProjectRows(query?: CrossingProjectQuery): Promise<CrossingProjectRecord[]> {
  const snapshot = await loadCrossPedigreeSnapshot();
  return filterCrossingProjectRows(snapshot.crossingProjects, query);
}

const filterCrossingProjectRows = (rows: CrossingProjectRecord[], query?: CrossingProjectQuery) => {
  const keyword = String(query?.keyword ?? "").trim().toLowerCase();
  const programId = optionalText(query?.program_id);
  return rows.filter((row) => {
    if (programId && row.program_id !== programId) return false;
    if (!keyword) return true;
    const haystack = [row.name, row.description, row.program_name]
      .map((value) => String(value ?? "").toLowerCase())
      .join(" ");
    return haystack.includes(keyword);
  });
};

export async function fetchCrossingProjectDetailExtended(id: string): Promise<CrossingProjectDetail> {
  const [project, pedigreeNodes] = await Promise.all([
    fetchCrossingProjectDetail(id),
    fetchPedigreeRows(),
  ]);
  const snapshot = await loadCrossPedigreeSnapshot(true);
  const plannedCrosses = snapshot.plannedCrosses.filter((row) => row.crossing_project_id === id);
  const actualCrosses = snapshot.actualCrosses.filter((row) => row.crossing_project_id === id);
  const relatedPedigreeNodes = pedigreeNodes.filter((row) => row.crossing_project_id === id);
  return {
    ...project,
    plannedCrosses,
    actualCrosses,
    pedigreeNodes: relatedPedigreeNodes,
  };
}

export async function fetchPlannedCrossDetail(plannedCrossDbId: string): Promise<PlannedCrossRecord> {
  const response = await request<BrapiListResponse<PlannedCross>>(
    `/brapi/v2/plannedcrosses?crossDbId=${encodeURIComponent(plannedCrossDbId)}&page=0&pageSize=1`,
  );
  const cross = response.result.data[0];
  if (!cross) throw new Error("计划杂交不存在");
  return mapPlannedCross(cross);
}

export async function fetchCrossDetail(crossDbId: string): Promise<CrossRecord> {
  const response = await request<BrapiListResponse<Cross>>(
    `/brapi/v2/crosses?crossDbId=${encodeURIComponent(crossDbId)}&page=0&pageSize=1`,
  );
  const cross = response.result.data[0];
  if (!cross) throw new Error("实际杂交不存在");
  return mapCross(cross);
}

const pollinationEventBody = (event: CrossPollinationEventRecord) => ({
  ...(optionalText(event.pollination_number) ? { pollinationNumber: optionalText(event.pollination_number) } : {}),
  ...(event.pollination_successful === null || event.pollination_successful === undefined
    ? {}
    : { pollinationSuccessful: event.pollination_successful }),
  ...(optionalText(event.pollination_time_stamp)
    ? { pollinationTimeStamp: optionalText(event.pollination_time_stamp) }
    : {}),
});

export function normalizePollinationEventForm(event: CrossPollinationEventRecord) {
  return {
    pollination_number: event.pollination_number ?? "",
    pollination_successful: event.pollination_successful === null ? "unknown" : String(event.pollination_successful),
    pollination_time_stamp: event.pollination_time_stamp ?? "",
  };
}

export function sortPollinationEvents(events: CrossPollinationEventRecord[]) {
  return [...events].sort((left, right) => {
    const leftTime = Date.parse(String(left.pollination_time_stamp ?? ""));
    const rightTime = Date.parse(String(right.pollination_time_stamp ?? ""));
    if (Number.isNaN(leftTime) && Number.isNaN(rightTime)) return 0;
    if (Number.isNaN(leftTime)) return 1;
    if (Number.isNaN(rightTime)) return -1;
    return rightTime - leftTime;
  });
}

export async function updateCrossPollinationEvents(
  crossId: string,
  events: CrossPollinationEventRecord[],
): Promise<CrossRecord> {
  const numbers = events
    .map((event) => optionalText(event.pollination_number))
    .filter(Boolean) as string[];
  if (new Set(numbers).size !== numbers.length) {
    throw new Error("同一 Cross 下授粉编号不能重复");
  }

  const response = await request<BrapiListResponse<Cross>>("/brapi/v2/crosses", {
    method: "PUT",
    body: JSON.stringify({
      [crossId]: {
        pollinationEvents: events.map(pollinationEventBody),
      },
    }),
  });
  invalidateAfterMutation();
  return mapCross(response.result.data[0]);
}

export async function fetchCrossingProjectDetail(id: string): Promise<CrossingProjectRecord> {
  const response = await request<BrapiSingleResponse<CrossingProject>>(
    `/brapi/v2/crossingprojects/${encodeURIComponent(id)}`,
  );
  return mapCrossingProject(response.result);
}

export async function createCrossingProjectRow(payload: CrossingProjectPayload): Promise<CrossingProjectRecord> {
  const response = await request<BrapiListResponse<CrossingProject>>("/brapi/v2/crossingprojects", {
    method: "POST",
    body: JSON.stringify([crossingProjectBody(payload)]),
  });
  invalidateAfterMutation();
  return mapCrossingProject(response.result.data[0]);
}

export async function updateCrossingProjectRow(id: string, payload: CrossingProjectPayload): Promise<CrossingProjectRecord> {
  const response = await request<BrapiSingleResponse<CrossingProject>>(
    `/brapi/v2/crossingprojects/${encodeURIComponent(id)}`,
    {
      method: "PUT",
      body: JSON.stringify(crossingProjectBody(payload)),
    },
  );
  invalidateAfterMutation();
  return mapCrossingProject(response.result);
}

export async function fetchPlannedCrossRows(): Promise<PlannedCrossRecord[]> {
  const snapshot = await loadCrossPedigreeSnapshot();
  return snapshot.plannedCrosses;
}

export async function createPlannedCrossRow(payload: PlannedCrossPayload): Promise<PlannedCrossRecord> {
  const response = await request<BrapiListResponse<PlannedCross>>("/brapi/v2/plannedcrosses", {
    method: "POST",
    body: JSON.stringify([plannedCrossBody(payload)]),
  });
  invalidateAfterMutation();
  return mapPlannedCross(response.result.data[0]);
}

export async function updatePlannedCrossRow(id: string, payload: PlannedCrossPayload): Promise<PlannedCrossRecord> {
  const response = await request<BrapiListResponse<PlannedCross>>("/brapi/v2/plannedcrosses", {
    method: "PUT",
    body: JSON.stringify({ [id]: plannedCrossBody(payload) }),
  });
  invalidateAfterMutation();
  return mapPlannedCross(response.result.data[0]);
}

export async function fetchCrossRows(): Promise<CrossRecord[]> {
  const snapshot = await loadCrossPedigreeSnapshot();
  return snapshot.actualCrosses;
}

export async function createCrossRow(payload: CrossPayload): Promise<CrossRecord> {
  const response = await request<BrapiListResponse<Cross>>("/brapi/v2/crosses", {
    method: "POST",
    body: JSON.stringify([crossBody(payload)]),
  });
  invalidateAfterMutation();
  const created = mapCross(response.result.data[0]);
  const plannedCrossId = optionalText(payload.planned_cross_id);
  if (plannedCrossId) {
    const snapshot = await loadCrossPedigreeSnapshot(true);
    const planned = snapshot.plannedCrosses.find((item) => item.id === plannedCrossId);
    if (planned && (planned.parent1 || planned.parent2)) {
      await updateCrossParents(buildCrossParentFormState(
        created.id,
        false,
        created.crossing_project_id,
        created.crossing_project_name,
        planned.parent1,
        planned.parent2,
      ));
      return fetchCrossDetail(created.id);
    }
  }
  return created;
}

export async function updateCrossRow(id: string, payload: CrossPayload): Promise<CrossRecord> {
  const response = await request<BrapiListResponse<Cross>>("/brapi/v2/crosses", {
    method: "PUT",
    body: JSON.stringify({ [id]: crossBody(payload) }),
  });
  invalidateAfterMutation();
  return mapCross(response.result.data[0]);
}

export async function fetchCrossParentRows(): Promise<CrossParentRow[]> {
  const snapshot = await loadCrossPedigreeSnapshot();
  return snapshot.parentRows;
}

export async function updateCrossParents(payload: CrossParentFormState): Promise<void> {
  const crossId = requiredText(payload.cross_id, "请选择所属 Cross");
  const parent1 = buildCrossParent(
    payload.parent1_type,
    payload.parent1_germplasm_id,
    payload.parent1_observation_unit_id,
  );
  const parent2 = buildCrossParent(
    payload.parent2_type,
    payload.parent2_germplasm_id,
    payload.parent2_observation_unit_id,
  );

  const body = {
    crossingProjectDbId: payload.crossing_project_id ?? undefined,
    ...(parent1 ? { parent1 } : {}),
    ...(parent2 ? { parent2 } : {}),
  };

  if (payload.planned) {
    await request<BrapiListResponse<PlannedCross>>("/brapi/v2/plannedcrosses", {
      method: "PUT",
      body: JSON.stringify({ [crossId]: body }),
    });
    invalidateAfterMutation();
    return;
  }

  await request<BrapiListResponse<Cross>>("/brapi/v2/crosses", {
    method: "PUT",
    body: JSON.stringify({ [crossId]: body }),
  });
  invalidateAfterMutation();
}

const PEDIGREE_LIST_PAGE_SIZE = 500;

async function fetchAllPedigreeRows(query = ""): Promise<PedigreeRecord[]> {
  const response = await request<BrapiListResponse<PedigreeRecord & PedigreeNode>>(
    `/brapi/v2/pedigree?page=0&pageSize=${PEDIGREE_LIST_PAGE_SIZE}${query}`,
  );
  return response.result.data.map(mapPedigree);
}

export async function fetchPedigreeRows(): Promise<PedigreeRecord[]> {
  return fetchAllPedigreeRows();
}

export async function fetchPedigreeRowsWithRelations(): Promise<PedigreeRecord[]> {
  return fetchAllPedigreeRows("&includeParents=true&includeProgeny=false&includeSiblings=true");
}

export async function fetchPedigreeNodeByGermplasm(germplasmDbId: string): Promise<PedigreeRecord | null> {
  const response = await request<BrapiListResponse<PedigreeRecord & PedigreeNode>>(
    `/brapi/v2/pedigree?germplasmDbId=${encodeURIComponent(germplasmDbId)}&page=0&pageSize=1&includeParents=true&includeProgeny=true&includeSiblings=true`,
  );
  const node = response.result.data[0];
  return node ? mapPedigree(node) : null;
}

export async function fetchPedigreeDetail(id: string): Promise<PedigreeRecord> {
  const byGermplasm = await fetchPedigreeNodeByGermplasm(id);
  if (byGermplasm) return byGermplasm;
  const rows = await fetchPedigreeRows();
  const found = rows.find((row) => row.id === id || row.germplasm_id === id);
  if (!found) throw new Error("系谱节点不存在");
  return found;
}

export async function createPedigreeRow(payload: PedigreePayload): Promise<PedigreeRecord> {
  const response = await request<BrapiListResponse<PedigreeRecord & PedigreeNode>>("/brapi/v2/pedigree", {
    method: "POST",
    body: JSON.stringify([pedigreeBody(payload, true)]),
  });
  invalidateAfterMutation();
  return mapPedigree(response.result.data[0]);
}

export async function updatePedigreeRow(id: string, payload: PedigreePayload): Promise<PedigreeRecord> {
  const germplasmDbId = optionalText(payload.germplasm_id) || id;
  const response = await request<BrapiListResponse<PedigreeRecord & PedigreeNode>>("/brapi/v2/pedigree", {
    method: "PUT",
    body: JSON.stringify({
      [germplasmDbId]: {
        ...pedigreeBody({ ...payload, germplasm_id: germplasmDbId }),
        germplasmDbId,
      },
    }),
  });
  invalidateAfterMutation();
  return mapPedigree(response.result.data[0]);
}

export async function fetchPedigreeEdgeRows(scopeGermplasmDbId?: string): Promise<PedigreeEdgeRow[]> {
  const nodes = await fetchPedigreeRowsWithRelations();
  const rows = flattenPedigreeEdges(nodes);
  if (!scopeGermplasmDbId) return rows;
  return rows.filter(
    (row) => row.this_node_id === scopeGermplasmDbId || row.connected_node_id === scopeGermplasmDbId,
  );
}

export function buildPedigreeEdgeFormState(row?: PedigreeEdgeRow): PedigreeEdgeFormState {
  return {
    edge_type: row?.edge_type ?? "parent",
    parent_type: row?.parent_type && row.parent_type !== NONE_SELECT_VALUE ? row.parent_type : NONE_SELECT_VALUE,
    this_node_id: row?.this_node_id ?? NONE_SELECT_VALUE,
    connected_node_id: row?.connected_node_id ?? NONE_SELECT_VALUE,
  };
}

export async function upsertPedigreeEdge(payload: PedigreeEdgeFormState, originalId?: string): Promise<void> {
  const edgeType = requiredText(payload.edge_type, "请选择关系类型");
  const thisNodeId = requiredText(payload.this_node_id, "请选择当前材料");
  const connectedNodeId = requiredText(payload.connected_node_id, "请选择关联材料");
  if (thisNodeId === connectedNodeId) {
    throw new Error("当前材料与关联材料不能相同");
  }
  if (edgeType === "sibling") {
    throw new Error("同胞关系由共享亲本自动推断，请通过 parent 关系维护");
  }

  const nodes = await fetchPedigreeRowsWithRelations();
  const childGermplasmId = edgeType === "parent" ? thisNodeId : connectedNodeId;
  const parentGermplasmId = edgeType === "parent" ? connectedNodeId : thisNodeId;
  const parentType = requiredText(payload.parent_type, "parent/child 关系请选择 parent_type");

  const childNode = nodes.find((node) => node.germplasm_id === childGermplasmId);
  const existingParents = childNode?.parents ?? [];
  let nextParents = existingParents.map((parent) => ({
    germplasmDbId: parent.germplasmDbId,
    parentType: parent.parentType,
  }));

  if (originalId) {
    const [, , oldConnectedNodeId] = originalId.split(":");
    if (oldConnectedNodeId) {
      nextParents = nextParents.filter((parent) => parent.germplasmDbId !== oldConnectedNodeId);
    }
  }

  nextParents = nextParents.filter((parent) => parent.germplasmDbId !== parentGermplasmId);
  nextParents.push({ germplasmDbId: parentGermplasmId, parentType });

  await updatePedigreeParents(childGermplasmId, nextParents);
}

export async function removePedigreeEdge(edgeId: string): Promise<void> {
  const [edgeType, thisNodeId, connectedNodeId] = edgeId.split(":");
  if (edgeType !== "parent" || !thisNodeId || !connectedNodeId) {
    throw new Error("仅支持删除 parent 关系");
  }

  const nodes = await fetchPedigreeRowsWithRelations();
  const childNode = nodes.find((node) => node.germplasm_id === thisNodeId);
  const nextParents = (childNode?.parents ?? [])
    .filter((parent) => parent.germplasmDbId !== connectedNodeId)
    .map((parent) => ({
      germplasmDbId: parent.germplasmDbId,
      parentType: parent.parentType,
    }));

  await updatePedigreeParents(thisNodeId, nextParents);
}
