import { getAuthToken } from "@/utils/token";
import { loadGermplasmOptions, loadStudyOptions } from "@/services/dropdownCache";
import { NONE_SELECT_VALUE, type ObservationUnitRecord, 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 StudyResponse {
  studyDbId: string;
  studyName: string | null;
}

interface GermplasmResponse {
  germplasmDbId: string;
  germplasmName: string | null;
}

type ObservationUnitPayload = Partial<Record<
  | "id"
  | "observation_unit_name"
  | "study_id"
  | "germplasm_id"
  | "level"
  | "level_order"
  | "row"
  | "col",
  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 requiredText = (value: unknown, message: string) => {
  const normalized = optionalText(value);
  if (!normalized) throw new Error(message);
  return normalized;
};

const optionalNumber = (value: unknown) => {
  const text = optionalText(value);
  if (!text) return null;
  const number = Number(text);
  if (Number.isNaN(number)) return null;
  return number;
};

const mapObservationUnit = (unit: ObservationUnitRecord): ObservationUnitRecord => {
  const levelName = unit.observationLevel?.levelName ?? null;
  const levelOrder = unit.observationLevel?.levelOrder ?? null;
  return {
    ...unit,
    id: unit.observationUnitDbId || unit.id,
    observation_unit_name: unit.observation_unit_name || unit.observationUnitName,
    study_id: unit.study_id || unit.studyDbId,
    germplasm_id: unit.germplasm_id || unit.germplasmDbId,
    level: unit.level || levelName,
    level_order: unit.level_order ?? levelOrder,
    row: unit.row || unit.positionCoordinateY,
    col: unit.col || unit.positionCoordinateX,
  };
};

const toRequestBody = (payload: ObservationUnitPayload) => ({
  observationUnitName: requiredText(payload.observation_unit_name, "请填写观测单元名"),
  studyDbId: optionalText(payload.study_id),
  germplasmDbId: optionalText(payload.germplasm_id),
  observationLevel: {
    levelName: requiredText(payload.level, "请选择层级"),
    levelOrder: optionalNumber(payload.level_order) ?? 0,
  },
  positionCoordinateX: optionalText(payload.col),
  positionCoordinateY: optionalText(payload.row),
});

export async function fetchObservationUnitRows(): Promise<ObservationUnitRecord[]> {
  const response = await request<BrapiListResponse<ObservationUnitRecord>>("/brapi/v2/observationunits?page=0&pageSize=10");
  return response.result.data.map(mapObservationUnit);
}

export async function fetchObservationUnitOptions(force = false): Promise<{
  studies: SelectOption[];
  germplasms: SelectOption[];
}> {
  const [studies, germplasms] = await Promise.all([
    loadStudyOptions(force),
    loadGermplasmOptions(force),
  ]);

  return { studies, germplasms };
}

export async function createObservationUnitRow(payload: ObservationUnitPayload): Promise<ObservationUnitRecord> {
  const response = await request<BrapiListResponse<ObservationUnitRecord>>("/brapi/v2/observationunits", {
    method: "POST",
    body: JSON.stringify({
      observationUnitDbId: requiredText(payload.id, "请填写观测单�?ID"),
      ...toRequestBody(payload),
    }),
  });
  return mapObservationUnit(response.result.data[0]);
}

export async function updateObservationUnitRow(id: string, payload: ObservationUnitPayload): Promise<ObservationUnitRecord> {
  const requestedId = optionalText(payload.id);
  if (requestedId && requestedId !== id) {
    throw new Error("观测单元 ID 不支持直接修改，请删除后重新新增");
  }

  const response = await request<BrapiListResponse<ObservationUnitRecord>>("/brapi/v2/observationunits", {
    method: "PUT",
    body: JSON.stringify({
      observationUnitDbId: id,
      ...toRequestBody(payload),
    }),
  });
  return mapObservationUnit(response.result.data[0]);
}
