import { getAuthToken } from "@/utils/token";
import { NONE_SELECT_VALUE, type ObservationVariableRecord, 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 CropResponse {
  id: string;
  crop_name: string | null;
}

interface OntologyResponse {
  ontologyDbId: string;
  ontologyName: string | null;
  ontology_name: string | null;
  version: string | null;
}

interface TraitResponse {
  traitDbId: string;
  traitName: string | null;
  trait_name: string | null;
}

interface MethodResponse {
  methodDbId: string;
  methodName: string | null;
  name: string | null;
}

interface ScaleResponse {
  scaleDbId: string;
  scaleName: string | null;
  scale_name: string | null;
  units: string | null;
}

type ObservationVariablePayload = Partial<Record<
  | "id"
  | "name"
  | "pui"
  | "default_value"
  | "documentationurl"
  | "growth_stage"
  | "institution"
  | "language"
  | "scientist"
  | "status"
  | "submission_timestamp"
  | "crop_id"
  | "ontology_id"
  | "trait_id"
  | "method_id"
  | "scale_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 requiredText = (value: unknown, message: string) => {
  const normalized = optionalText(value);
  if (!normalized) throw new Error(message);
  return normalized;
};

const mapObservationVariable = (variable: ObservationVariableRecord): ObservationVariableRecord => ({
  ...variable,
  id: variable.observationVariableDbId || variable.id,
  name: variable.name || variable.observation_variable_name || variable.observationVariableName,
  observation_variable_name: variable.observation_variable_name || variable.observationVariableName || variable.name,
  pui: variable.pui || variable.observationVariablePUI,
  default_value: variable.default_value || variable.defaultValue,
  documentationurl: variable.documentationurl || variable.documentationURL,
  growth_stage: variable.growth_stage || variable.growthStage,
  submission_timestamp: variable.submission_timestamp || variable.submissionTimestamp,
  crop_id: variable.crop_id || variable.cropDbId,
  ontology_id: variable.ontology_id || variable.ontologyDbId,
  ontology_name: variable.ontology_name || variable.ontologyName,
  trait_id: variable.trait_id || variable.traitDbId,
  trait_name: variable.trait_name || variable.traitName,
  method_id: variable.method_id || variable.methodDbId,
  method_name: variable.method_name || variable.methodName,
  scale_id: variable.scale_id || variable.scaleDbId,
  scale_name: variable.scale_name || variable.scaleName,
});

const toRequestBody = (payload: ObservationVariablePayload) => ({
  observationVariableName: requiredText(payload.name, "请填写变量名"),
  pui: optionalText(payload.pui),
  defaultValue: optionalText(payload.default_value),
  documentationurl: optionalText(payload.documentationurl),
  growthStage: optionalText(payload.growth_stage),
  institution: optionalText(payload.institution),
  language: optionalText(payload.language),
  scientist: optionalText(payload.scientist),
  status: optionalText(payload.status),
  submissionTimestamp: optionalText(payload.submission_timestamp),
  crop_id: optionalText(payload.crop_id),
  ontology_id: optionalText(payload.ontology_id),
  trait_id: requiredText(payload.trait_id, "请选择 Trait"),
  method_id: requiredText(payload.method_id, "请选择 Method"),
  scale_id: requiredText(payload.scale_id, "请选择 Scale"),
});

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

export async function fetchObservationVariableOptions(): Promise<{
  crops: SelectOption[];
  ontologies: SelectOption[];
  traits: SelectOption[];
  methods: SelectOption[];
  scales: SelectOption[];
}> {
  const [crops, ontologies, traits, methods, scales] = await Promise.all([
    request<CropResponse[]>("/api/dictionaries/crops"),
    request<BrapiListResponse<OntologyResponse>>("/brapi/v2/ontologies?page=0&pageSize=10"),
    request<BrapiListResponse<TraitResponse>>("/brapi/v2/traits?page=0&pageSize=10"),
    request<BrapiListResponse<MethodResponse>>("/brapi/v2/methods?page=0&pageSize=10"),
    request<BrapiListResponse<ScaleResponse>>("/brapi/v2/scales?page=0&pageSize=10"),
  ]);

  return {
    crops: crops.map((crop) => ({
      value: crop.id,
      label: crop.crop_name || crop.id,
    })),
    ontologies: ontologies.result.data.map((ontology) => ({
      value: ontology.ontologyDbId,
      label: `${ontology.ontologyName || ontology.ontology_name || ontology.ontologyDbId}${ontology.version ? ` / ${ontology.version}` : ""}`,
    })),
    traits: traits.result.data.map((trait) => ({
      value: trait.traitDbId,
      label: trait.traitName || trait.trait_name || trait.traitDbId,
    })),
    methods: methods.result.data.map((method) => ({
      value: method.methodDbId,
      label: method.methodName || method.name || method.methodDbId,
    })),
    scales: scales.result.data.map((scale) => ({
      value: scale.scaleDbId,
      label: `${scale.scaleName || scale.scale_name || scale.scaleDbId}${scale.units ? ` / ${scale.units}` : ""}`,
    })),
  };
}

export async function createObservationVariableRow(payload: ObservationVariablePayload): Promise<ObservationVariableRecord> {
  const response = await request<BrapiListResponse<ObservationVariableRecord>>("/brapi/v2/variables", {
    method: "POST",
    body: JSON.stringify({
      id: requiredText(payload.id, "请填写变�?ID"),
      ...toRequestBody(payload),
    }),
  });
  return mapObservationVariable(response.result.data[0]);
}

export async function updateObservationVariableRow(id: string, payload: ObservationVariablePayload): Promise<ObservationVariableRecord> {
  const requestedId = optionalText(payload.id);
  if (requestedId && requestedId !== id) {
    throw new Error("变量 ID 不支持直接修改，请删除后重新新增");
  }

  const response = await request<BrapiSingleResponse<ObservationVariableRecord>>(`/brapi/v2/variables/${encodeURIComponent(id)}`, {
    method: "PUT",
    body: JSON.stringify(toRequestBody(payload)),
  });
  return mapObservationVariable(response.result);
}

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