import { fetchBreedingMethodOptions } from "../breeding-method/api";
import { DEFAULT_SEARCH_PAGE_BODY } from "@/constants/api";
import { loadCommonCropNameOptions } from "@/services/dropdownCache";
import { getAuthToken } from "@/utils/token";
import { NONE_SELECT_VALUE, type GermplasmQuery, type GermplasmRecord, 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 CommonCropNamesResponse {
  result: {
    data: string[];
  };
}

type GermplasmPayload = Partial<Record<
  | "germplasm_name"
  | "default_display_name"
  | "accession_number"
  | "germplasmpui"
  | "documentationurl"
  | "genus"
  | "species"
  | "species_authority"
  | "subtaxa"
  | "subtaxa_authority"
  | "country_of_origin_code"
  | "acquisition_date"
  | "acquisition_source_code"
  | "biological_status_of_accession_code"
  | "collection"
  | "mls_status"
  | "seed_source"
  | "seed_source_description"
  | "germplasm_preprocessing"
  | "crop_id"
  | "breeding_method_id",
  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 germplasmName = (payload: GermplasmPayload) => {
  const name = optionalText(payload.germplasm_name);
  if (!name) throw new Error("请填写种质名");
  return name;
};

const mapGermplasm = (germplasm: GermplasmRecord): GermplasmRecord => ({
  ...germplasm,
  id: germplasm.germplasmDbId || germplasm.id,
  germplasm_name: germplasm.germplasm_name || germplasm.germplasmName,
  default_display_name: germplasm.default_display_name || germplasm.defaultDisplayName,
  accession_number: germplasm.accession_number || germplasm.accessionNumber,
  germplasmpui: germplasm.germplasmpui || germplasm.germplasmPUI,
  documentationurl: germplasm.documentationurl || germplasm.documentationURL,
  species_authority: germplasm.species_authority || germplasm.speciesAuthority,
  subtaxa_authority: germplasm.subtaxa_authority || germplasm.subtaxaAuthority,
  country_of_origin_code: germplasm.country_of_origin_code || germplasm.countryOfOriginCode,
  acquisition_date: germplasm.acquisition_date || germplasm.acquisitionDate,
  acquisition_source_code: germplasm.acquisition_source_code ?? germplasm.acquisitionSourceCode,
  biological_status_of_accession_code:
    germplasm.biological_status_of_accession_code ?? germplasm.biologicalStatusOfAccessionCode,
  mls_status: germplasm.mls_status ?? germplasm.mlsStatus,
  seed_source: germplasm.seed_source || germplasm.seedSource,
  seed_source_description: germplasm.seed_source_description || germplasm.seedSourceDescription,
  germplasm_preprocessing: germplasm.germplasm_preprocessing || germplasm.germplasmPreprocessing,
  crop_id: germplasm.crop_id || germplasm.commonCropName || germplasm.cropDbId,
  crop_name: germplasm.crop_name || germplasm.commonCropName || germplasm.cropName,
  breeding_method_id: germplasm.breeding_method_id || germplasm.breedingMethodDbId,
  breeding_method_name: germplasm.breeding_method_name || germplasm.breedingMethodName,
});

const toRequestBody = (payload: GermplasmPayload) => ({
  germplasmName: germplasmName(payload),
  defaultDisplayName: optionalText(payload.default_display_name),
  accessionNumber: optionalText(payload.accession_number),
  germplasmPUI: optionalText(payload.germplasmpui),
  documentationurl: optionalText(payload.documentationurl),
  genus: optionalText(payload.genus),
  species: optionalText(payload.species),
  species_authority: optionalText(payload.species_authority),
  subtaxa: optionalText(payload.subtaxa),
  subtaxa_authority: optionalText(payload.subtaxa_authority),
  countryOfOriginCode: optionalText(payload.country_of_origin_code),
  country_of_origin_code: optionalText(payload.country_of_origin_code),
  acquisitionDate: optionalText(payload.acquisition_date),
  acquisition_source_code: optionalNumber(payload.acquisition_source_code),
  biological_status_of_accession_code: optionalNumber(payload.biological_status_of_accession_code),
  collection: optionalText(payload.collection),
  mls_status: optionalNumber(payload.mls_status),
  seed_source: optionalText(payload.seed_source),
  seed_source_description: optionalText(payload.seed_source_description),
  germplasm_preprocessing: optionalText(payload.germplasm_preprocessing),
  ...(optionalText(payload.crop_id) ? { commonCropName: optionalText(payload.crop_id) } : {}),
  breedingMethodDbId: optionalText(payload.breeding_method_id),
});

const buildGermplasmSearchBody = (query?: GermplasmQuery) => {
  const body: Record<string, unknown> = { ...DEFAULT_SEARCH_PAGE_BODY };
  const crop = optionalText(query?.crop_id);
  const synonym = optionalText(query?.synonym);
  if (crop) body.commonCropNames = [crop];
  if (synonym) body.synonyms = [synonym];
  return body;
};

const filterGermplasmRows = (rows: GermplasmRecord[], query?: GermplasmQuery) => {
  if (!query) return rows;

  const nameFilter = optionalText(query.germplasm_name)?.toLowerCase();
  const accessionFilter = optionalText(query.accession_number)?.toLowerCase();
  const puiFilter = optionalText(query.germplasmpui)?.toLowerCase();
  const cropFilter = optionalText(query.crop_id);

  return rows.filter((row) => {
    if (cropFilter && row.crop_id !== cropFilter && row.crop_name !== cropFilter && row.commonCropName !== cropFilter) {
      return false;
    }
    if (nameFilter && !String(row.germplasm_name ?? row.default_display_name ?? "").toLowerCase().includes(nameFilter)) {
      return false;
    }
    if (accessionFilter && !String(row.accession_number ?? "").toLowerCase().includes(accessionFilter)) {
      return false;
    }
    if (puiFilter && !String(row.germplasmpui ?? "").toLowerCase().includes(puiFilter)) {
      return false;
    }
    return true;
  });
};

export async function fetchGermplasmRows(query?: GermplasmQuery): Promise<GermplasmRecord[]> {
  const crop = optionalText(query?.crop_id);
  const synonym = optionalText(query?.synonym);
  const useSearch = Boolean(crop || synonym);

  let rows: GermplasmRecord[];
  if (useSearch) {
    const response = await request<BrapiListResponse<GermplasmRecord>>("/brapi/v2/search/germplasm", {
      method: "POST",
      body: JSON.stringify(buildGermplasmSearchBody(query)),
    });
    rows = response.result.data.map(mapGermplasm);
  } else {
    const response = await request<BrapiListResponse<GermplasmRecord>>("/brapi/v2/germplasm?page=0&pageSize=1000");
    rows = response.result.data.map(mapGermplasm);
  }

  return filterGermplasmRows(rows, query);
}

export async function fetchGermplasmDetail(id: string): Promise<GermplasmRecord> {
  const response = await request<BrapiSingleResponse<GermplasmRecord>>(
    `/brapi/v2/germplasm/${encodeURIComponent(id)}`,
  );
  return mapGermplasm(response.result);
}

export function normalizeGermplasmFormData(record: GermplasmRecord): Record<string, unknown> {
  const cropId = record.crop_id || record.commonCropName || "";
  const breedingMethodId = record.breeding_method_id || record.breedingMethodDbId || "";

  return {
    ...record,
    crop_id: cropId && cropId !== NONE_SELECT_VALUE ? cropId : NONE_SELECT_VALUE,
    breeding_method_id:
      breedingMethodId && breedingMethodId !== NONE_SELECT_VALUE ? breedingMethodId : NONE_SELECT_VALUE,
  };
}

export async function fetchGermplasmOptions(force = false): Promise<{
  crops: SelectOption[];
  breedingMethods: SelectOption[];
}> {
  const [cropsResult, breedingMethodsResult] = await Promise.allSettled([
    loadCommonCropNameOptions(force),
    fetchBreedingMethodOptions(force),
  ]);

  const crops = cropsResult.status === "fulfilled" ? cropsResult.value : [];
  const breedingMethods = breedingMethodsResult.status === "fulfilled"
    ? breedingMethodsResult.value
    : [];

  return { crops, breedingMethods };
}

export async function createGermplasmRow(payload: GermplasmPayload): Promise<GermplasmRecord> {
  const response = await request<BrapiListResponse<GermplasmRecord>>("/brapi/v2/germplasm", {
    method: "POST",
    body: JSON.stringify([toRequestBody(payload)]),
  });
  return mapGermplasm(response.result.data[0]);
}

export async function updateGermplasmRow(id: string, payload: GermplasmPayload): Promise<GermplasmRecord> {
  const response = await request<BrapiSingleResponse<GermplasmRecord>>(`/brapi/v2/germplasm/${encodeURIComponent(id)}`, {
    method: "PUT",
    body: JSON.stringify(toRequestBody(payload)),
  });
  return mapGermplasm(response.result);
}

export async function deleteGermplasmRow(id: string): Promise<void> {
  await request<BrapiSingleResponse<GermplasmRecord>>(`/brapi/v2/germplasm/${encodeURIComponent(id)}`, {
    method: "DELETE",
  });
}
