import { DEFAULT_LIST_PAGE_SIZE, DEFAULT_PAGE_QUERY } from "@/constants/api";
import { createCachedLoader, loadCommonCropNameOptions, type SelectOption as CachedSelectOption } from "@/services/dropdownCache";
import { getAuthToken } from "@/utils/token";
import { readAdditionalInfoString } from "./genomeMapUtils";
import {
  NONE_SELECT_VALUE,
  type GenomeMapDetail,
  type GenomeMapQuery,
  type GenomeMapRecord,
  type LinkageGroupQuery,
  type LinkageGroupRecord,
  type MarkerPositionQuery,
  type MarkerPositionRecord,
  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 GenomeMapPayload = Partial<Record<
  | "id"
  | "map_name"
  | "map_pui"
  | "common_crop_name"
  | "scientific_name"
  | "type"
  | "unit"
  | "comments"
  | "documentation_url"
  | "published_date",
  unknown
>>;

type LinkageGroupPayload = Partial<Record<
  "id" | "linkage_group_name" | "max_position",
  unknown
>>;

type MarkerPositionPayload = Partial<Record<
  "id" | "linkage_group_id" | "variant_id" | "position",
  unknown
>>;

interface VariantLookup {
  variantDbId?: string;
  variantId?: string;
  id?: string;
  variantNames?: string[] | null;
  variantName?: string | null;
}

const readVariantLabel = (item: VariantLookup) =>
  item.variantNames?.[0] || item.variantName || item.variantDbId || item.variantId || item.id || "";

const toValidSelectOptions = (options: SelectOption[]) =>
  options.filter((option) => Boolean(String(option.value ?? "").trim()));

const mapVariantOptions = (rows: VariantLookup[]): SelectOption[] =>
  toValidSelectOptions(rows.map((item) => {
    const value = String(item.variantDbId ?? item.variantId ?? item.id ?? "").trim();
    return { value, label: readVariantLabel(item) || value };
  }).filter((item) => item.value));

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 || `Request failed: ${response.status}`);
  }
  if (response.status === 204) {
    return undefined as T;
  }
  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) => {
  if (value === null || value === undefined || value === "") return null;
  const parsed = Number(value);
  if (Number.isNaN(parsed)) throw new Error("请输入有效数字");
  return parsed;
};

const requiredNumber = (value: unknown, message: string) => {
  const parsed = optionalNumber(value);
  if (parsed === null) throw new Error(message);
  return parsed;
};

const mapGenomeMap = (item: GenomeMapRecord): GenomeMapRecord => ({
  ...item,
  id: item.mapDbId || item.id,
  map_name: item.map_name ?? item.mapName ?? null,
  map_pui: item.map_pui ?? item.mapPUI ?? null,
  common_crop_name: item.common_crop_name ?? item.commonCropName ?? null,
  scientific_name: item.scientific_name ?? item.scientificName ?? null,
  documentation_url: item.documentation_url ?? item.documentationURL ?? null,
  published_date: item.published_date ?? (item.publishedDate ? String(item.publishedDate).slice(0, 10) : null),
  linkage_group_count: item.linkage_group_count ?? item.linkageGroupCount ?? null,
  marker_count: item.marker_count ?? item.markerCount ?? null,
});

const mapLinkageGroup = (item: Record<string, unknown>): LinkageGroupRecord => {
  const id = (
    readAdditionalInfoString(item, "linkageGroupDbId")
    || String(item.linkageGroupDbId ?? item.id ?? "")
  ).trim();
  const mapDbId = readAdditionalInfoString(item, "mapDbId") || String(item.mapDbId ?? item.map_db_id ?? "").trim();
  return {
    ...item,
    id,
    linkage_group_db_id: id,
    linkage_group_name: String(item.linkageGroupName ?? item.linkage_group_name ?? ""),
    max_position: (item.maxPosition ?? item.max_position) as number | null,
    marker_count: (item.markerCount ?? item.marker_count) as number | null,
    map_db_id: mapDbId || undefined,
  };
};

const mapMarkerPosition = (item: Record<string, unknown>): MarkerPositionRecord => {
  const id = readAdditionalInfoString(item, "markerPositionDbId")
    || String(item.markerPositionDbId ?? item.id ?? "");
  return {
    ...item,
    id,
    marker_position_db_id: id,
    linkage_group_db_id: readAdditionalInfoString(item, "linkageGroupDbId") ?? undefined,
    linkage_group_name: String(item.linkageGroupName ?? item.linkage_group_name ?? ""),
    variant_db_id: String(item.variantDbId ?? item.variant_db_id ?? ""),
    variant_name: String(item.variantName ?? item.variant_name ?? ""),
    position: (item.position ?? null) as number | null,
    map_db_id: String(item.mapDbId ?? item.map_db_id ?? ""),
    map_name: String(item.mapName ?? item.map_name ?? ""),
  };
};

const genomeMapBody = (payload: GenomeMapPayload) => ({
  mapDbId: optionalText(payload.id),
  mapName: requiredText(payload.map_name, "图谱名称不能为空"),
  commonCropName: optionalText(payload.common_crop_name),
  scientificName: optionalText(payload.scientific_name),
  type: optionalText(payload.type),
  unit: optionalText(payload.unit),
  comments: optionalText(payload.comments),
  documentationURL: optionalText(payload.documentation_url),
  publishedDate: optionalText(payload.published_date),
});

const linkageGroupBody = (payload: LinkageGroupPayload) => ({
  linkageGroupName: requiredText(payload.linkage_group_name, "连锁群名称不能为空"),
  maxPosition: optionalNumber(payload.max_position),
});

const markerPositionBody = (payload: MarkerPositionPayload) => ({
  markerPositionDbId: optionalText(payload.id),
  linkageGroupDbId: requiredText(payload.linkage_group_id, "请选择连锁群"),
  variantDbId: requiredText(payload.variant_id, "请选择 Variant"),
  position: requiredNumber(payload.position, "位置不能为空"),
});

export const normalizeGenomeMapFormData = (row: GenomeMapRecord) => ({
  id: row.id,
  map_name: row.map_name || "",
  map_pui: row.map_pui || "",
  common_crop_name: row.common_crop_name && row.common_crop_name !== NONE_SELECT_VALUE
    ? row.common_crop_name
    : NONE_SELECT_VALUE,
  scientific_name: row.scientific_name || "",
  type: row.type || "",
  unit: row.unit || "",
  comments: row.comments || "",
  documentation_url: row.documentation_url || "",
  published_date: row.published_date || "",
});

export const normalizeLinkageGroupFormData = (row: LinkageGroupRecord, includeMap = false) => ({
  id: row.id,
  linkage_group_name: row.linkage_group_name || "",
  max_position: row.max_position ?? "",
  ...(includeMap ? {
    map_db_id: row.map_db_id && row.map_db_id !== NONE_SELECT_VALUE
      ? row.map_db_id
      : NONE_SELECT_VALUE,
  } : {}),
});

export const normalizeMarkerPositionFormData = (row: MarkerPositionRecord) => ({
  id: row.id,
  linkage_group_id: row.linkage_group_db_id && row.linkage_group_db_id !== NONE_SELECT_VALUE
    ? row.linkage_group_db_id
    : NONE_SELECT_VALUE,
  variant_id: row.variant_db_id && row.variant_db_id !== NONE_SELECT_VALUE
    ? row.variant_db_id
    : NONE_SELECT_VALUE,
  position: row.position ?? "",
});

const mapListLoader = createCachedLoader(async () => {
  const response = await request<BrapiListResponse<GenomeMapRecord>>(`/brapi/v2/maps?${DEFAULT_PAGE_QUERY}`);
  return response.result.data.map(mapGenomeMap);
});

const allLinkageGroupsLoader = createCachedLoader(async () => {
  const maps = await mapListLoader.load();
  if (maps.length === 0) return [];
  const batches = await Promise.all(
    maps.map(async (map) => {
      try {
        const rows = await fetchLinkageGroupRows(map.id);
        return rows
          .filter((row) => row.id)
          .map((row) => ({
            ...row,
            map_db_id: row.map_db_id || map.id,
            map_name: map.map_name || map.id,
          }));
      } catch {
        return [];
      }
    }),
  );
  return batches.flat();
});

const variantListLoader = createCachedLoader(async () => {
  const response = await request<BrapiListResponse<VariantLookup>>(
    `/brapi/v2/variants?pageToken=0&pageSize=${DEFAULT_LIST_PAGE_SIZE}`,
  );
  return mapVariantOptions(response.result?.data ?? []);
});

export function invalidateGenomeMapPageCache() {
  mapListLoader.invalidate();
  allLinkageGroupsLoader.invalidate();
  variantListLoader.invalidate();
}

const filterLinkageGroupRows = (rows: LinkageGroupRecord[], query?: LinkageGroupQuery) => {
  const nameFilter = String(query?.linkage_group_name ?? "").trim().toLowerCase();
  const mapFilter = optionalText(query?.map_db_id);
  return rows.filter((row) => {
    if (nameFilter && !String(row.linkage_group_name ?? "").toLowerCase().includes(nameFilter)) return false;
    if (mapFilter && row.map_db_id !== mapFilter) return false;
    return true;
  });
};

export async function loadLinkageGroupPageData(params: {
  query?: LinkageGroupQuery;
  force?: boolean;
} = {}) {
  const [maps, linkageGroups] = await Promise.all([
    mapListLoader.load(params.force),
    allLinkageGroupsLoader.load(params.force),
  ]);
  const mapOptions: SelectOption[] = maps.map((map) => ({
    value: map.id,
    label: map.map_name || map.id,
  }));
  return {
    options: { maps: mapOptions },
    rows: filterLinkageGroupRows(linkageGroups, params.query),
  };
}

const filterMapRows = (rows: GenomeMapRecord[], query?: GenomeMapQuery) => {
  const nameFilter = String(query?.map_name ?? "").trim().toLowerCase();
  const cropFilter = optionalText(query?.common_crop_name);
  const typeFilter = optionalText(query?.type);
  return rows.filter((row) => {
    if (nameFilter && !String(row.map_name ?? "").toLowerCase().includes(nameFilter)) return false;
    if (cropFilter && row.common_crop_name !== cropFilter) return false;
    if (typeFilter && row.type !== typeFilter) return false;
    return true;
  });
};

export async function loadGenomeMapPageData(params: {
  query?: GenomeMapQuery;
  force?: boolean;
} = {}) {
  const [maps, cropOptions] = await Promise.all([
    mapListLoader.load(params.force),
    loadCommonCropNameOptions(params.force),
  ]);
  const cropSelectOptions: SelectOption[] = cropOptions.map((item: CachedSelectOption) => ({
    value: item.value,
    label: item.label,
  }));
  return {
    options: { crops: cropSelectOptions },
    rows: filterMapRows(maps, params.query),
  };
}

export async function fetchGenomeMapDetail(mapDbId: string): Promise<GenomeMapDetail> {
  const [mapResponse, linkageResponse, markerResponse] = await Promise.all([
    request<BrapiSingleResponse<GenomeMapRecord>>(`/brapi/v2/maps/${encodeURIComponent(mapDbId)}`),
    request<BrapiListResponse<Record<string, unknown>>>(
      `/brapi/v2/maps/${encodeURIComponent(mapDbId)}/linkagegroups?${DEFAULT_PAGE_QUERY}`,
    ),
    request<BrapiListResponse<Record<string, unknown>>>(
      `/brapi/v2/markerpositions?mapDbId=${encodeURIComponent(mapDbId)}&${DEFAULT_PAGE_QUERY}`,
    ),
  ]);
  const map = mapGenomeMap(mapResponse.result);
  return {
    ...map,
    linkageGroups: linkageResponse.result.data.map(mapLinkageGroup),
    markerPositions: markerResponse.result.data.map(mapMarkerPosition),
  };
}

export async function fetchLinkageGroupRows(mapDbId: string): Promise<LinkageGroupRecord[]> {
  const response = await request<BrapiListResponse<Record<string, unknown>>>(
    `/brapi/v2/maps/${encodeURIComponent(mapDbId)}/linkagegroups?${DEFAULT_PAGE_QUERY}`,
  );
  return response.result.data.map(mapLinkageGroup);
}

const buildMarkerPositionQueryString = (query?: MarkerPositionQuery) => {
  const params = new URLSearchParams(DEFAULT_PAGE_QUERY);
  const mapDbId = optionalText(query?.map_db_id);
  const linkageGroupName = optionalText(query?.linkage_group_name);
  const variantDbId = optionalText(query?.variant_db_id);
  if (mapDbId) params.set("mapDbId", mapDbId);
  if (linkageGroupName) params.set("linkageGroupName", linkageGroupName);
  if (variantDbId) params.set("variantDbId", variantDbId);
  return params.toString();
};

const filterMarkerPositionRows = (
  rows: MarkerPositionRecord[],
  query?: MarkerPositionQuery,
  linkageGroupDbId?: string,
) => {
  const linkageGroupFilter = optionalText(linkageGroupDbId);
  return rows.filter((row) => {
    if (linkageGroupFilter && row.linkage_group_db_id !== linkageGroupFilter) return false;
    return true;
  });
};

export async function fetchMarkerPositionRowsByQuery(
  query?: MarkerPositionQuery,
  linkageGroupDbId?: string,
): Promise<MarkerPositionRecord[]> {
  const response = await request<BrapiListResponse<Record<string, unknown>>>(
    `/brapi/v2/markerpositions?${buildMarkerPositionQueryString(query)}`,
  );
  return filterMarkerPositionRows(
    response.result.data.map(mapMarkerPosition),
    query,
    linkageGroupDbId,
  );
}

export async function loadMarkerPositionFilterOptions(params: {
  mapDbId?: string;
} = {}) {
  const maps = await mapListLoader.load();
  const mapOptions: SelectOption[] = maps.map((map) => ({
    value: map.id,
    label: map.map_name || map.id,
  }));
  const mapFilter = optionalText(params.mapDbId);
  let linkageGroupOptions: SelectOption[] = [];
  if (mapFilter) {
    const rows = await fetchLinkageGroupRows(mapFilter);
    linkageGroupOptions = toValidSelectOptions(rows.map((row) => ({
      value: row.linkage_group_name || row.id,
      label: row.linkage_group_name || row.id,
    })));
  } else {
    const linkageGroups = await allLinkageGroupsLoader.load();
    linkageGroupOptions = toValidSelectOptions(linkageGroups.map((row) => ({
      value: row.linkage_group_name || row.id,
      label: row.map_name
        ? `${row.linkage_group_name || row.id} (${row.map_name})`
        : (row.linkage_group_name || row.id),
    })));
  }
  const variants = await variantListLoader.load();
  return {
    maps: mapOptions,
    linkageGroups: linkageGroupOptions,
    variants,
  };
}

export async function loadMarkerPositionPageData(params: {
  query?: MarkerPositionQuery;
} = {}) {
  const mapDbId = optionalText(params.query?.map_db_id) ?? undefined;
  const [options, rows] = await Promise.all([
    loadMarkerPositionFilterOptions({ mapDbId }),
    fetchMarkerPositionRowsByQuery(params.query),
  ]);
  return { options, rows };
}

export async function fetchLinkageGroupDetail(
  mapDbId: string,
  linkageGroupDbId: string,
): Promise<LinkageGroupRecord | null> {
  const rows = await fetchLinkageGroupRows(mapDbId);
  return rows.find((row) => row.id === linkageGroupDbId) ?? null;
}

export async function fetchMarkerPositionRows(mapDbId: string): Promise<MarkerPositionRecord[]> {
  return fetchMarkerPositionRowsByQuery({ map_db_id: mapDbId });
}

export async function fetchMarkerPositionsByVariantId(variantDbId: string): Promise<MarkerPositionRecord[]> {
  return fetchMarkerPositionRowsByQuery({ variant_db_id: variantDbId });
}

export async function fetchVariantOptions(force = false): Promise<SelectOption[]> {
  return variantListLoader.load(force);
}

export async function fetchAllLinkageGroupFormOptions(): Promise<SelectOption[]> {
  const linkageGroups = await allLinkageGroupsLoader.load();
  return toValidSelectOptions(linkageGroups.map((row) => ({
    value: row.id,
    label: row.map_name
      ? `${row.linkage_group_name || row.id} (${row.map_name})`
      : (row.linkage_group_name || row.id),
  })));
}

export async function fetchLinkageGroupOptions(mapDbId: string): Promise<SelectOption[]> {
  const rows = await fetchLinkageGroupRows(mapDbId);
  return toValidSelectOptions(rows.map((row) => ({
    value: row.id,
    label: row.linkage_group_name || row.id,
  })));
}

export async function createGenomeMapRow(payload: GenomeMapPayload) {
  invalidateGenomeMapPageCache();
  const response = await request<BrapiListResponse<GenomeMapRecord>>("/brapi/v2/maps", {
    method: "POST",
    body: JSON.stringify(genomeMapBody(payload)),
  });
  return mapGenomeMap(response.result.data[0]);
}

export async function updateGenomeMapRow(id: string, payload: GenomeMapPayload) {
  invalidateGenomeMapPageCache();
  const response = await request<BrapiSingleResponse<GenomeMapRecord>>(
    `/brapi/v2/maps/${encodeURIComponent(id)}`,
    { method: "PUT", body: JSON.stringify(genomeMapBody(payload)) },
  );
  return mapGenomeMap(response.result);
}

export async function deleteGenomeMapRow(id: string) {
  invalidateGenomeMapPageCache();
  await request(`/brapi/v2/maps/${encodeURIComponent(id)}`, { method: "DELETE" });
}

export async function createLinkageGroupRow(mapDbId: string, payload: LinkageGroupPayload) {
  invalidateGenomeMapPageCache();
  const response = await request<BrapiListResponse<Record<string, unknown>>>(
    `/brapi/v2/maps/${encodeURIComponent(mapDbId)}/linkagegroups`,
    { method: "POST", body: JSON.stringify(linkageGroupBody(payload)) },
  );
  return mapLinkageGroup(response.result.data[0]);
}

export async function createLinkageGroupRowFromPayload(payload: LinkageGroupPayload & { map_db_id?: unknown }) {
  const mapDbId = requiredText(payload.map_db_id, "请选择所属图谱");
  return createLinkageGroupRow(mapDbId, payload);
}

export async function updateLinkageGroupRow(
  mapDbId: string,
  linkageGroupDbId: string,
  payload: LinkageGroupPayload,
) {
  invalidateGenomeMapPageCache();
  const response = await request<BrapiListResponse<Record<string, unknown>>>(
    `/brapi/v2/maps/${encodeURIComponent(mapDbId)}/linkagegroups/${encodeURIComponent(linkageGroupDbId)}`,
    { method: "PUT", body: JSON.stringify(linkageGroupBody(payload)) },
  );
  return mapLinkageGroup(response.result.data[0]);
}

export async function deleteLinkageGroupRow(mapDbId: string, linkageGroupDbId: string) {
  invalidateGenomeMapPageCache();
  await request(
    `/brapi/v2/maps/${encodeURIComponent(mapDbId)}/linkagegroups/${encodeURIComponent(linkageGroupDbId)}`,
    { method: "DELETE" },
  );
}

export async function createMarkerPositionRow(payload: MarkerPositionPayload) {
  invalidateGenomeMapPageCache();
  const response = await request<BrapiListResponse<Record<string, unknown>>>("/brapi/v2/markerpositions", {
    method: "POST",
    body: JSON.stringify(markerPositionBody(payload)),
  });
  return mapMarkerPosition(response.result.data[0]);
}

export async function updateMarkerPositionRow(id: string, payload: MarkerPositionPayload) {
  invalidateGenomeMapPageCache();
  const response = await request<BrapiListResponse<Record<string, unknown>>>(
    `/brapi/v2/markerpositions/${encodeURIComponent(id)}`,
    { method: "PUT", body: JSON.stringify(markerPositionBody(payload)) },
  );
  return mapMarkerPosition(response.result.data[0]);
}

export async function deleteMarkerPositionRow(id: string) {
  invalidateGenomeMapPageCache();
  await request(`/brapi/v2/markerpositions/${encodeURIComponent(id)}`, { method: "DELETE" });
}
