import { normalizePhone } from "./phone";
import type {
  CountryConfigResponse,
  CreateOnboardingRequest,
  DocumentType,
  DocumentUploadResponse,
  FarmerDashboardResponse,
  FarmerPreferencesRequest,
  FarmerPreferencesResponse,
  OnboardingSession,
  OnboardingStatusResponse,
  OnboardingStep,
  OtpSentResponse,
  ReferenceOption,
  ReferenceOptionType,
  StepPayload,
  UserMeResponse,
  VerifyResponse,
} from "./api-types";

const BASE = "/api";

async function request<T>(
  path: string,
  options: RequestInit = {},
): Promise<T> {
  const res = await fetch(`${BASE}${path}`, {
    ...options,
    headers: {
      "Content-Type": "application/json",
      ...options.headers,
    },
    credentials: "same-origin",
  });

  if (!res.ok) {
    const body = await res.json().catch(() => ({ message: res.statusText }));
    const message =
      (body as { message?: string }).message ??
      (body as { error?: { message?: string } }).error?.message ??
      (res.status === 401 ? "Unauthorized" : `Request failed: ${res.status}`);
    throw new Error(message);
  }

  if (res.status === 204) return undefined as T;
  return res.json();
}

async function uploadFile<T>(
  path: string,
  formData: FormData,
): Promise<T> {
  const res = await fetch(`${BASE}${path}`, {
    method: "POST",
    body: formData,
    credentials: "same-origin",
  });

  if (!res.ok) {
    const body = await res.json().catch(() => ({ message: res.statusText }));
    throw new Error(body.message || `Upload failed: ${res.status}`);
  }

  return res.json();
}

export const api = {
  auth: {
    requestOtp: (phone: string, countryCode = "UZ") =>
      request<OtpSentResponse>("/auth/otp", {
        method: "POST",
        body: JSON.stringify({ phone: normalizePhone(phone), countryCode }),
      }),
    verify: (phone: string, code: string, countryCode = "UZ") =>
      request<VerifyResponse>("/auth/verify", {
        method: "POST",
        body: JSON.stringify({ phone: normalizePhone(phone), code, countryCode }),
      }),
    me: () => request<UserMeResponse>("/auth/me"),
    logout: () => request<{ success: boolean }>("/auth/logout", { method: "POST" }),
  },

  onboarding: {
    createOrResume: (
      countryCode: CreateOnboardingRequest["countryCode"] = "UZ",
      channel: CreateOnboardingRequest["channel"] = "farmer",
      forceNew = false,
    ) =>
      request<OnboardingSession>(`/onboarding${forceNew ? "?forceNew=true" : ""}`, {
        method: "POST",
        body: JSON.stringify({ countryCode, channel }),
      }),
    get: (id: string) => request<OnboardingSession>(`/onboarding/${id}`),
    updateStep: <S extends OnboardingStep>(
      id: string,
      step: S,
      data: StepPayload<S>,
      markComplete = true,
    ) =>
      request<OnboardingSession>(`/onboarding/${id}/steps/${step}`, {
        method: "PATCH",
        body: JSON.stringify({ data, markComplete }),
      }),
    submit: (id: string) =>
      request<OnboardingSession>(`/onboarding/${id}/submit`, { method: "POST" }),
    status: (id: string) => request<OnboardingStatusResponse>(`/onboarding/${id}/status`),
  },

  documents: {
    upload: (sessionId: string, docType: DocumentType | string, file: File) => {
      const formData = new FormData();
      formData.append("sessionId", sessionId);
      formData.append("docType", docType);
      formData.append("file", file);
      return uploadFile<DocumentUploadResponse>("/documents/upload", formData);
    },
  },

  farmer: {
    dashboard: () => request<FarmerDashboardResponse>("/farmer/dashboard"),
    updatePreferences: (body: FarmerPreferencesRequest) =>
      request<FarmerPreferencesResponse>("/farmer/preferences", {
        method: "PATCH",
        body: JSON.stringify(body),
      }),
  },

  config: {
    getCountry: (code = "UZ") =>
      request<CountryConfigResponse>(`/config/country/${code}`),
  },

  reference: {
    options: (
      type?: ReferenceOptionType | string,
      countryCode = "UZ",
      extra?: { region?: string; locale?: string; institutionId?: string },
    ) => {
      const params = new URLSearchParams({ countryCode });
      if (type) params.set("type", type);
      if (extra?.region) params.set("region", extra.region);
      if (extra?.locale) params.set("locale", extra.locale);
      if (extra?.institutionId) params.set("institutionId", extra.institutionId);
      return request<ReferenceOption[]>(`/reference/options?${params.toString()}`);
    },
  },
};

export type { StepPayload, OnboardingStep } from "./api-types";
