import { getAuthToken } from "@/utils/token";
import {
  loadCommonCropNameOptions,
  loadPersonOptions,
  loadProgramOptions,
} from "@/services/dropdownCache";
import type { Contact, Trial, TrialNewRequestPublications } from "@/lib/api/types.gen";
import {
  mapContactsFromApi,
  mapPublicationsFromApi,
  normalizeContactsForSave,
  normalizePublicationsForSave,
  readTrialContacts,
  readTrialPublications,
} from "./components/trialRelationUtils";
import { NONE_SELECT_VALUE, type SelectOption, type TrialRecord } 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[];
  };
}

interface ProgramResponse {
  programDbId: string;
  programName: string | null;
  name: string | null;
  abbreviation: string | null;
}

interface PersonResponse {
  personDbId: string;
  firstName?: string | null;
  lastName?: string | null;
  emailAddress?: string | null;
}

type TrialPayload = Partial<Record<
  "id" | "trial_name" | "trial_description" | "trialpui" | "documentationurl" | "start_date" | "end_date" | "active" | "crop_id" | "program_id" | "trialContacts" | "trialPublications" | "contacts" | "publications",
  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 optionalBoolean = (value: unknown) => {
  const normalized = optionalText(value);
  if (normalized === null) return null;
  return normalized === "true" || normalized === "1" || normalized === "是" || normalized === "active";
};

const trialName = (payload: TrialPayload) => {
  const name = optionalText(payload.trial_name);
  if (!name) throw new Error("请填写试验名");
  return name;
};

export const mapTrial = (trial: Trial): TrialRecord => {
  const contacts = mapContactsFromApi(trial.contacts);
  const publications = mapPublicationsFromApi(trial.publications);

  return {
    ...trial,
    id: trial.trialDbId || "",
    trialDbId: trial.trialDbId || "",
    trialName: trial.trialName ?? null,
    trial_name: trial.trialName ?? null,
    trialDescription: trial.trialDescription ?? null,
    trial_description: trial.trialDescription ?? null,
    trialPUI: trial.trialPUI ?? null,
    trialpui: trial.trialPUI ?? null,
    documentationURL: trial.documentationURL ?? null,
    documentationurl: trial.documentationURL ?? null,
    startDate: trial.startDate ?? null,
    start_date: trial.startDate ?? null,
    endDate: trial.endDate ?? null,
    end_date: trial.endDate ?? null,
    cropDbId: null,
    crop_id: trial.commonCropName ?? null,
    cropName: trial.commonCropName ?? null,
    crop_name: trial.commonCropName ?? null,
    programDbId: trial.programDbId ?? null,
    program_id: trial.programDbId ?? null,
    programName: trial.programName ?? null,
    program_name: trial.programName ?? null,
    active: trial.active ?? null,
    contacts,
    publications,
    trialContacts: contacts,
    trialPublications: publications,
  };
};

const toRequestBody = (payload: TrialPayload) => {
  const programDbId = optionalText(payload.program_id);
  const commonCropName = optionalText(payload.crop_id);

  return {
    trialName: trialName(payload),
    trialDescription: optionalText(payload.trial_description),
    trialPUI: optionalText(payload.trialpui),
    documentationURL: optionalText(payload.documentationurl),
    startDate: optionalText(payload.start_date),
    endDate: optionalText(payload.end_date),
    active: optionalBoolean(payload.active),
    ...(programDbId ? { programDbId } : {}),
    ...(!programDbId && commonCropName ? { commonCropName } : {}),
    contacts: normalizeContactsForSave(readTrialContacts(payload as Record<string, unknown>)),
    publications: normalizePublicationsForSave(readTrialPublications(payload as Record<string, unknown>)),
  };
};

export async function fetchTrialRows(): Promise<TrialRecord[]> {
  const response = await request<BrapiListResponse<Trial>>("/brapi/v2/trials?page=0&pageSize=10");
  return response.result.data.map(mapTrial);
}

export async function fetchTrialDetail(trialDbId: string): Promise<TrialRecord> {
  const response = await request<BrapiSingleResponse<Trial>>(`/brapi/v2/trials/${encodeURIComponent(trialDbId)}`);
  return mapTrial(response.result);
}

export async function fetchTrialOptions(force = false): Promise<{ crops: SelectOption[]; programs: SelectOption[]; persons: SelectOption[] }> {
  const [crops, programs, people] = await Promise.all([
    loadCommonCropNameOptions(force),
    loadProgramOptions(force),
    loadPersonOptions(force),
  ]);

  return { crops, programs, persons: people };
}

export async function createTrialRow(payload: TrialPayload): Promise<TrialRecord> {
  const response = await request<BrapiListResponse<Trial>>("/brapi/v2/trials", {
    method: "POST",
    body: JSON.stringify([toRequestBody(payload)]),
  });
  return mapTrial(response.result.data[0]);
}

export async function updateTrialRow(id: string, payload: TrialPayload): Promise<TrialRecord> {
  const response = await request<BrapiSingleResponse<Trial>>(`/brapi/v2/trials/${encodeURIComponent(id)}`, {
    method: "PUT",
    body: JSON.stringify(toRequestBody(payload)),
  });
  return mapTrial(response.result);
}

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