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

interface BrapiListResponse<T> {
  result: { data: T[] };
}

interface BrapiSingleResponse<T> {
  result: T;
}

type LocationPayload = Partial<Omit<LocationRecord, "id" | "locationDbId" | "parentLocationName">>;

const apiBase = () => {
  if (typeof window !== "undefined") return "";
  return process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8081";
};

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 emptyToNull = (value: unknown) => {
  const normalized = String(value ?? "").trim();
  return normalized ? normalized : null;
};

export const mapLocation = (location: Omit<LocationRecord, "id">): LocationRecord => ({
  ...location,
  id: location.locationDbId,
});

const toRequestBody = (payload: LocationPayload) => ({
  locationName: emptyToNull(payload.locationName),
  locationType: emptyToNull(payload.locationType),
  countryCode: emptyToNull(payload.countryCode),
  countryName: emptyToNull(payload.countryName),
  abbreviation: emptyToNull(payload.abbreviation),
  environmentType: emptyToNull(payload.environmentType),
  exposure: emptyToNull(payload.exposure),
  instituteName: emptyToNull(payload.instituteName),
  instituteAddress: emptyToNull(payload.instituteAddress),
  coordinateDescription: emptyToNull(payload.coordinateDescription),
  coordinateUncertainty: emptyToNull(payload.coordinateUncertainty),
  documentationURL: emptyToNull(payload.documentationURL),
  parentLocationDbId: emptyToNull(payload.parentLocationDbId),
  siteStatus: emptyToNull(payload.siteStatus),
  slope: emptyToNull(payload.slope),
  topography: emptyToNull(payload.topography),
});

export async function fetchLocationRows(page = DEFAULT_LIST_PAGE, pageSize = DEFAULT_LIST_PAGE_SIZE): Promise<LocationRecord[]> {
  const response = await request<BrapiListResponse<Omit<LocationRecord, "id">>>(
    `/brapi/v2/locations?page=${encodeURIComponent(String(page))}&pageSize=${encodeURIComponent(String(pageSize))}`,
  );
  return response.result.data.map(mapLocation);
}

export async function fetchLocationDetail(locationDbId: string): Promise<LocationRecord> {
  const response = await request<BrapiSingleResponse<Omit<LocationRecord, "id">>>(
    `/brapi/v2/locations/${encodeURIComponent(locationDbId)}`,
  );
  return mapLocation(response.result);
}

export async function createLocationRow(payload: LocationPayload): Promise<LocationRecord> {
  if (!emptyToNull(payload.locationName)) {
    throw new Error("???????");
  }
  const response = await request<BrapiListResponse<Omit<LocationRecord, "id">>>("/brapi/v2/locations", {
    method: "POST",
    body: JSON.stringify([toRequestBody(payload)]),
  });
  const location = response.result.data[0];
  if (!location) {
    throw new Error("??????????????");
  }
  return mapLocation(location);
}

export async function updateLocationRow(locationDbId: string, payload: LocationPayload): Promise<LocationRecord> {
  const response = await request<BrapiSingleResponse<Omit<LocationRecord, "id">>>(
    `/brapi/v2/locations/${encodeURIComponent(locationDbId)}`,
    {
      method: "PUT",
      body: JSON.stringify(toRequestBody(payload)),
    },
  );
  return mapLocation(response.result);
}

export async function deleteLocationRow(locationDbId: string): Promise<void> {
  await request<BrapiSingleResponse<Omit<LocationRecord, "id">>>(
    `/brapi/v2/locations/${encodeURIComponent(locationDbId)}`,
    { method: "DELETE" },
  );
}
