import type { Cross, CrossParent, CrossingProject, PlannedCross } from "@/lib/api/types.gen";
import {
  loadGermplasmOptions,
  loadObservationUnitOptions,
  loadProgramOptions,
} from "@/services/dropdownCache";
import { getAuthToken } from "@/utils/token";
import {
  mapCross,
  mapCrossingProject,
  mapPlannedCross,
} from "./mappers";
import type {
  CrossParentRow,
  CrossRecord,
  CrossingProjectRecord,
  PlannedCrossRecord,
  SelectOption,
} from "./types";

interface BrapiListResponse<T> {
  result: { data: T[] };
}

export interface CrossPedigreeSnapshot {
  programs: SelectOption[];
  germplasm: SelectOption[];
  observationUnits: SelectOption[];
  crossingProjectOptions: SelectOption[];
  plannedCrossOptions: SelectOption[];
  crossOptions: SelectOption[];
  crossingProjects: CrossingProjectRecord[];
  plannedCrosses: PlannedCrossRecord[];
  actualCrosses: CrossRecord[];
  parentRows: CrossParentRow[];
}

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 flattenCrossParents = (
  crossId: string,
  crossName: string | null,
  planned: boolean,
  crossingProjectId: string | null,
  crossingProjectName: string | null,
  parent: CrossParent | null | undefined,
  slot: "parent1" | "parent2",
): CrossParentRow | null => {
  if (!parent) return null;
  const hasData = parent.parentType || parent.germplasmDbId || parent.observationUnitDbId;
  if (!hasData) return null;
  return {
    id: `${crossId}:${slot}`,
    cross_id: crossId,
    cross_name: crossName,
    planned,
    parent_slot: slot,
    parent_type: parent.parentType ?? null,
    germplasm_id: parent.germplasmDbId ?? null,
    germplasm_name: parent.germplasmName ?? null,
    observation_unit_id: parent.observationUnitDbId ?? null,
    observation_unit_name: parent.observationUnitName ?? null,
    crossing_project_id: crossingProjectId,
    crossing_project_name: crossingProjectName,
  };
};

function buildParentRows(planned: PlannedCrossRecord[], actual: CrossRecord[]): CrossParentRow[] {
  const rows: CrossParentRow[] = [];

  for (const cross of planned) {
    const p1 = flattenCrossParents(
      cross.id, cross.name, true, cross.crossing_project_id, cross.crossing_project_name, cross.parent1, "parent1",
    );
    const p2 = flattenCrossParents(
      cross.id, cross.name, true, cross.crossing_project_id, cross.crossing_project_name, cross.parent2, "parent2",
    );
    if (p1) rows.push(p1);
    if (p2) rows.push(p2);
  }

  for (const cross of actual) {
    const p1 = flattenCrossParents(
      cross.id, cross.name, false, cross.crossing_project_id, cross.crossing_project_name, cross.parent1, "parent1",
    );
    const p2 = flattenCrossParents(
      cross.id, cross.name, false, cross.crossing_project_id, cross.crossing_project_name, cross.parent2, "parent2",
    );
    if (p1) rows.push(p1);
    if (p2) rows.push(p2);
  }

  return rows;
}

async function fetchSnapshotFromNetwork(): Promise<CrossPedigreeSnapshot> {
  const [programs, germplasm, crossingProjects, plannedCrosses, actualCrosses, observationUnits] = await Promise.all([
    loadProgramOptions(),
    loadGermplasmOptions(),
    request<BrapiListResponse<CrossingProject>>("/brapi/v2/crossingprojects?page=0&pageSize=10"),
    request<BrapiListResponse<PlannedCross>>("/brapi/v2/plannedcrosses?page=0&pageSize=10"),
    request<BrapiListResponse<Cross>>("/brapi/v2/crosses?page=0&pageSize=10"),
    loadObservationUnitOptions().catch(() => [] as SelectOption[]),
  ]);

  const crossingProjectRows = (crossingProjects.result?.data ?? []).map(mapCrossingProject);
  const plannedRows = (plannedCrosses.result?.data ?? []).map(mapPlannedCross);
  const actualRows = (actualCrosses.result?.data ?? []).map(mapCross);

  return {
    programs,
    germplasm,
    observationUnits,
    crossingProjectOptions: crossingProjectRows.map((project) => ({
      value: project.id,
      label: project.name || project.id,
    })),
    plannedCrossOptions: plannedRows.map((cross) => ({
      value: cross.id,
      label: cross.name || cross.id,
    })),
    crossOptions: [...plannedRows, ...actualRows].map((cross) => ({
      value: cross.id,
      label: `${cross.planned ? "[计划] " : "[实际] "}${cross.name || cross.id}`,
    })),
    crossingProjects: crossingProjectRows,
    plannedCrosses: plannedRows,
    actualCrosses: actualRows,
    parentRows: buildParentRows(plannedRows, actualRows),
  };
}

let cachedSnapshot: CrossPedigreeSnapshot | null = null;
let inflightSnapshot: Promise<CrossPedigreeSnapshot> | null = null;

export function invalidateCrossPedigreeCache() {
  cachedSnapshot = null;
  inflightSnapshot = null;
}

export async function loadCrossPedigreeSnapshot(force = false): Promise<CrossPedigreeSnapshot> {
  if (!force && cachedSnapshot) return cachedSnapshot;
  if (!force && inflightSnapshot) return inflightSnapshot;

  inflightSnapshot = fetchSnapshotFromNetwork()
    .then((snapshot) => {
      cachedSnapshot = snapshot;
      inflightSnapshot = null;
      return snapshot;
    })
    .catch((error) => {
      inflightSnapshot = null;
      throw error;
    });

  return inflightSnapshot;
}

export function getCrossPedigreeSnapshot(): CrossPedigreeSnapshot | null {
  return cachedSnapshot;
}
