import { DEFAULT_LIST_PAGE, DEFAULT_LIST_PAGE_SIZE } from "@/constants/api";
import { getAuthToken } from "@/utils/token";

export interface CropRecord {
  id: string;
  crop_name: string | null;
  user_name?: string | null;
}

export interface CountryRecord {
  code_alpha3: string;
  code_alpha2: string | null;
  numeric_code: string | null;
  name_en: string;
  name_zh: string | null;
  is_active: boolean | null;
}

export interface DictionarySelectOption {
  value: string;
  label: string;
}

export interface PersonRecord {
  id: string;
  personDbId: string;
  firstName: string | null;
  middleName: string | null;
  lastName: string | null;
  emailAddress: string | null;
  phoneNumber: string | null;
  instituteName: string | null;
  mailingAddress: string | null;
  description: string | null;
  userID: string | null;
  additionalInfo?: Record<string, unknown>;
  externalReferences?: Array<Record<string, unknown>>;
}

export interface SeasonRecord {
  id: string;
  seasonDbId: string;
  seasonName: string | null;
  year: number | null;
}

export interface LocationRecord {
  id: string;
  locationDbId: string;
  locationName: string | null;
  locationType: string | null;
  countryCode: string | null;
  countryName: string | null;
  abbreviation: string | null;
  coordinateDescription: string | null;
  coordinateUncertainty: string | null;
  documentationURL: string | null;
  environmentType: string | null;
  exposure: string | null;
  instituteAddress: string | null;
  instituteName: string | null;
  parentLocationDbId: string | null;
  parentLocationName: string | null;
  siteStatus: string | null;
  slope: string | null;
  topography: string | null;
}

export interface OntologyRecord {
  id: string;
  ontologyDbId: string;
  ontology_name: string | null;
  ontologyName: string | null;
  version: string | null;
  documentationurl: string | null;
  documentationURL: string | null;
  authors: string | null;
  copyright: string | null;
  licence: string | null;
  description: string | null;
}

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 CropMutationItem {
  cropDbId: string;
  commonCropName: string;
}

type OntologyPayload = Partial<
  Record<
    "id" | "ontology_name" | "ontologyName" | "version" | "documentationurl" | "documentationURL" | "authors" | "copyright" | "licence" | "description",
    string | null
  >
>;

const emptyToNull = (value: unknown) => {
  const normalized = String(value ?? "").trim();
  return normalized ? normalized : null;
};

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>;
}

export function formatCountryOption(country: CountryRecord): DictionarySelectOption {
  const zh = country.name_zh?.trim();
  const label = zh ? `${zh} / ${country.code_alpha3}` : `${country.name_en} / ${country.code_alpha3}`;
  return { value: country.code_alpha3, label };
}

export async function listCountries(keyword?: string): Promise<CountryRecord[]> {
  const params = new URLSearchParams({ is_active: "true" });
  if (keyword?.trim()) {
    params.set("keyword", keyword.trim());
  }
  return request<CountryRecord[]>(`/api/dictionaries/countries?${params.toString()}`);
}

export async function listCrops(page = DEFAULT_LIST_PAGE, pageSize = DEFAULT_LIST_PAGE_SIZE): Promise<CropRecord[]> {
  const encodedPage = encodeURIComponent(String(page));
  const encodedPageSize = encodeURIComponent(String(pageSize));
  const response = await request<BrapiListResponse<string>>(`/brapi/v2/commoncropnames?page=${encodedPage}&pageSize=${encodedPageSize}`);
  return response.result.data.map((name) => ({ id: name, crop_name: name }));
}

export async function createCrop(payload: { crop_name: string }): Promise<CropRecord> {
  const response = await request<BrapiListResponse<CropMutationItem>>("/brapi/v2/commoncropnames/crops", {
    method: "POST",
    body: JSON.stringify({ commonCropName: payload.crop_name }),
  });
  const item = response.result.data[0];
  return {
    id: item?.cropDbId || payload.crop_name,
    crop_name: item?.commonCropName || payload.crop_name,
  };
}

export async function updateCrop(cropId: string, payload: { crop_name: string }): Promise<CropRecord> {
  const response = await request<BrapiListResponse<CropMutationItem>>(`/brapi/v2/commoncropnames/crops/${encodeURIComponent(cropId)}`, {
    method: "PUT",
    body: JSON.stringify({ commonCropName: payload.crop_name }),
  });
  const item = response.result.data[0];
  return {
    id: item?.cropDbId || cropId,
    crop_name: item?.commonCropName || payload.crop_name,
  };
}

export async function deleteCrop(cropId: string): Promise<CropRecord> {
  const response = await request<BrapiListResponse<CropMutationItem>>(`/brapi/v2/commoncropnames/crops/${encodeURIComponent(cropId)}`, {
    method: "DELETE",
  });
  const item = response.result.data[0];
  return {
    id: item?.cropDbId || cropId,
    crop_name: item?.commonCropName || null,
  };
}

export function listPersons() {
  return request<BrapiListResponse<Omit<PersonRecord, "id">>>("/brapi/v2/people").then((response) =>
    response.result.data.map((person) => ({
      ...person,
      id: person.personDbId,
    }))
  );
}

export function createPerson(payload: Partial<Omit<PersonRecord, "id" | "personDbId">>) {
  return request<BrapiListResponse<Omit<PersonRecord, "id">>>("/brapi/v2/people", {
    method: "POST",
    body: JSON.stringify([payload]),
  }).then((response) => {
    const person = response.result.data[0];
    return {
      ...person,
      id: person.personDbId,
    };
  });
}

export function updatePerson(personDbId: string, payload: Partial<Omit<PersonRecord, "id" | "personDbId">>) {
  return request<BrapiSingleResponse<Omit<PersonRecord, "id">>>(`/brapi/v2/people/${encodeURIComponent(personDbId)}`, {
    method: "PUT",
    body: JSON.stringify(payload),
  }).then((response) => ({
    ...response.result,
    id: response.result.personDbId,
  }));
}

export function deletePerson(personDbId: string) {
  return request<BrapiSingleResponse<Omit<PersonRecord, "id">>>(`/brapi/v2/people/${encodeURIComponent(personDbId)}`, {
    method: "DELETE",
  }).then(() => undefined);
}

export function listSeasons() {
  return request<BrapiListResponse<Omit<SeasonRecord, "id">>>("/brapi/v2/seasons").then((response) =>
    response.result.data.map((season) => ({
      ...season,
      id: season.seasonDbId,
    }))
  );
}

export function createSeason(payload: Partial<Omit<SeasonRecord, "id" | "seasonDbId">>) {
  return request<BrapiListResponse<Omit<SeasonRecord, "id">>>("/brapi/v2/seasons", {
    method: "POST",
    body: JSON.stringify([payload]),
  }).then((response) => {
    const season = response.result.data[0];
    return {
      ...season,
      id: season.seasonDbId,
    };
  });
}

export function updateSeason(seasonDbId: string, payload: Partial<Omit<SeasonRecord, "id" | "seasonDbId">>) {
  return request<BrapiSingleResponse<Omit<SeasonRecord, "id">>>(`/brapi/v2/seasons/${encodeURIComponent(seasonDbId)}`, {
    method: "PUT",
    body: JSON.stringify(payload),
  }).then((response) => ({
    ...response.result,
    id: response.result.seasonDbId,
  }));
}

export function deleteSeason(seasonDbId: string) {
  return request<BrapiSingleResponse<Omit<SeasonRecord, "id">>>(`/brapi/v2/seasons/${encodeURIComponent(seasonDbId)}`, {
    method: "DELETE",
  }).then(() => undefined);
}

export function listLocations(page = DEFAULT_LIST_PAGE, pageSize = DEFAULT_LIST_PAGE_SIZE) {
  const encodedPage = encodeURIComponent(String(page));
  const encodedPageSize = encodeURIComponent(String(pageSize));
  return request<BrapiListResponse<Omit<LocationRecord, "id">>>(
    `/brapi/v2/locations?page=${encodedPage}&pageSize=${encodedPageSize}`,
  ).then((response) =>
    response.result.data.map((location) => ({
      ...location,
      id: location.locationDbId,
    })),
  );
}

export function getLocation(locationDbId: string) {
  return request<BrapiSingleResponse<Omit<LocationRecord, "id">>>(
    `/brapi/v2/locations/${encodeURIComponent(locationDbId)}`,
  ).then((response) => ({
    ...response.result,
    id: response.result.locationDbId,
  }));
}

export function createLocation(payload: Partial<Omit<LocationRecord, "id" | "locationDbId" | "parentLocationName">>) {
  return request<BrapiListResponse<Omit<LocationRecord, "id">>>("/brapi/v2/locations", {
    method: "POST",
    body: JSON.stringify([payload]),
  }).then((response) => {
    const location = response.result.data[0];
    return {
      ...location,
      id: location.locationDbId,
    };
  });
}

export function updateLocation(locationDbId: string, payload: Partial<Omit<LocationRecord, "id" | "locationDbId" | "parentLocationName">>) {
  return request<BrapiSingleResponse<Omit<LocationRecord, "id">>>(`/brapi/v2/locations/${encodeURIComponent(locationDbId)}`, {
    method: "PUT",
    body: JSON.stringify(payload),
  }).then((response) => ({
    ...response.result,
    id: response.result.locationDbId,
  }));
}

export function deleteLocation(locationDbId: string) {
  return request<BrapiSingleResponse<Omit<LocationRecord, "id">>>(`/brapi/v2/locations/${encodeURIComponent(locationDbId)}`, {
    method: "DELETE",
  }).then(() => undefined);
}

export function listOntologies(page = DEFAULT_LIST_PAGE, pageSize = DEFAULT_LIST_PAGE_SIZE) {
  const encodedPage = encodeURIComponent(String(page));
  const encodedPageSize = encodeURIComponent(String(pageSize));
  return request<BrapiListResponse<Omit<OntologyRecord, "id">>>(
    `/brapi/v2/ontologies?page=${encodedPage}&pageSize=${encodedPageSize}`,
  ).then((response) =>
    response.result.data.map((ontology) => ({
      ...ontology,
      id: ontology.ontologyDbId,
      ontologyName: ontology.ontologyName ?? ontology.ontology_name ?? null,
      ontology_name: ontology.ontologyName ?? ontology.ontology_name ?? null,
      documentationURL: ontology.documentationURL ?? ontology.documentationurl ?? null,
      documentationurl: ontology.documentationURL ?? ontology.documentationurl ?? null,
    })),
  );
}

export function getOntology(ontologyDbId: string) {
  return request<BrapiSingleResponse<Omit<OntologyRecord, "id">>>(
    `/brapi/v2/ontologies/${encodeURIComponent(ontologyDbId)}`,
  ).then((response) => ({
    ...response.result,
    id: response.result.ontologyDbId,
    ontologyName: response.result.ontologyName ?? response.result.ontology_name ?? null,
    ontology_name: response.result.ontologyName ?? response.result.ontology_name ?? null,
    documentationURL: response.result.documentationURL ?? response.result.documentationurl ?? null,
    documentationurl: response.result.documentationURL ?? response.result.documentationurl ?? null,
  }));
}

const toOntologyRequestBody = (payload: OntologyPayload) => ({
  ontologyName: emptyToNull(payload.ontologyName ?? payload.ontology_name),
  version: emptyToNull(payload.version),
  documentationURL: emptyToNull(payload.documentationURL ?? payload.documentationurl),
  authors: emptyToNull(payload.authors),
  copyright: emptyToNull(payload.copyright),
  licence: emptyToNull(payload.licence),
  description: emptyToNull(payload.description),
});

export function createOntology(payload: OntologyPayload) {
  const body = toOntologyRequestBody(payload);
  if (!body.ontologyName) {
    return Promise.reject(new Error("请填写本体名��?"));
  }
  return request<BrapiListResponse<Omit<OntologyRecord, "id">>>("/brapi/v2/ontologies", {
    method: "POST",
    body: JSON.stringify([body]),
  }).then((response) => {
    const ontology = response.result.data[0];
    if (!ontology) {
      throw new Error("新�?�本体失败：后�??��?返回数据");
    }
    return {
      ...ontology,
      id: ontology.ontologyDbId,
      ontologyName: ontology.ontologyName ?? ontology.ontology_name ?? null,
      ontology_name: ontology.ontologyName ?? ontology.ontology_name ?? null,
      documentationURL: ontology.documentationURL ?? ontology.documentationurl ?? null,
      documentationurl: ontology.documentationURL ?? ontology.documentationurl ?? null,
    };
  });
}

export function updateOntology(ontologyDbId: string, payload: Omit<OntologyPayload, "id">) {
  return request<BrapiSingleResponse<Omit<OntologyRecord, "id">>>(`/brapi/v2/ontologies/${encodeURIComponent(ontologyDbId)}`, {
    method: "PUT",
    body: JSON.stringify(toOntologyRequestBody(payload)),
  }).then((response) => ({
    ...response.result,
    id: response.result.ontologyDbId,
    ontologyName: response.result.ontologyName ?? response.result.ontology_name ?? null,
    ontology_name: response.result.ontologyName ?? response.result.ontology_name ?? null,
    documentationURL: response.result.documentationURL ?? response.result.documentationurl ?? null,
    documentationurl: response.result.documentationURL ?? response.result.documentationurl ?? null,
  }));
}

export function deleteOntology(ontologyDbId: string) {
  return request<BrapiSingleResponse<Omit<OntologyRecord, "id">>>(`/brapi/v2/ontologies/${encodeURIComponent(ontologyDbId)}`, {
    method: "DELETE",
  }).then(() => undefined);
}
