import type { Freight, PaginatedResponse } from "@edr/types";
import { endpoint } from "@/utils/endpoint";
import type {
  CreateFileUploadFieldDto,
  CreateFileUploadSettingDto,
  FileUploadField,
  FileUploadSetting,
  UpdateFileUploadFieldDto,
  UpdateFileUploadSettingDto,
} from "@/types/fileUploadSettings";
import {
  bookingsService,
  BookingListFilter,
  CreateBookingPayload,
  GeneratePriceResponse,
} from "./bookings.service";
import { consignmentsService } from "./consignments.service";
import { trackingService } from "./tracking.service";
import { fileUploadSettingsService } from "./fileUploadSettings.service";
import { dropdownSettingsService } from "./dropdownSettings.service";
import { authService } from "./auth.service";
import { companiesService } from "./companies.service";
import {
  CreateDropdownOptionDto,
  CreateDropdownSettingDto,
  DropdownOption,
  DropdownSetting,
  UpdateDropdownOptionDto,
  UpdateDropdownSettingDto,
} from "@/types/dropdownSettings";
import type {
  CompanyInfoResponse,
  CreateCompanyPayload,
} from "./companies.service";
import type { ProfileResponse, UpdateProfilePayload } from "@/types/profile";
import type {
  AuthUser,
  GenerateVerificationCodePayload,
  LoginPayload,
  LoginResponse,
  OtpPayload,
  OtpResponse,
  SetPasswordPayload,
  SignupPayload,
  SignupResponse,
} from "@/types/auth";

// ---------------------------------------------------------------------------
// API definition
// ---------------------------------------------------------------------------

export const api = {
  auth: {
    login: endpoint<LoginPayload, LoginResponse>(
      "auth",
      "login",
      authService.login,
    ),
    createUser: endpoint<SignupPayload, SignupResponse>(
      "auth",
      "createUser",
      authService.createUser,
    ),
    getMyInfo: endpoint<void, AuthUser>(
      "auth",
      "getMyInfo",
      authService.getMyInfo,
    ),
    generateVerificationCode: endpoint<GenerateVerificationCodePayload, string>(
      "auth",
      "generateVerificationCode",
      authService.generateVerificationCode,
    ),
    setPassword: endpoint<SetPasswordPayload, void>(
      "auth",
      "setPassword",
      authService.setPassword,
    ),
    sendOTP: endpoint<OtpPayload, OtpResponse>(
      "auth",
      "sendOTP",
      authService.sendOTP,
    ),
    verifyOTP: endpoint<OtpPayload, OtpResponse>(
      "auth",
      "verifyOTP",
      authService.verifyOTP,
    ),
    logout: endpoint<void, void>("auth", "logout", authService.logout),
  },

  companies: {
    getInfo: endpoint<void, CompanyInfoResponse | null>(
      "companies",
      "getInfo",
      companiesService.getInfo,
    ),

    create: endpoint<CreateCompanyPayload, CompanyInfoResponse>(
      "companies",
      "create",
      companiesService.create,
    ),

    getProfile: endpoint<void, ProfileResponse>(
      "companies",
      "getProfile",
      companiesService.getProfile,
    ),

    updateProfile: endpoint<UpdateProfilePayload, ProfileResponse>(
      "companies",
      "updateProfile",
      companiesService.updateProfile,
    ),
  },

  bookings: {
    list: endpoint<BookingListFilter | void, PaginatedResponse<Freight.IBooking>>(
      "bookings",
      "list",
      bookingsService.list,
    ),

    get: endpoint<{ id: string }, Freight.IBooking>(
      "bookings",
      "get",
      ({ id }) => bookingsService.get(id),
    ),

    create: endpoint<CreateBookingPayload, Freight.IBooking>(
      "bookings",
      "create",
      bookingsService.create,
    ),

    update: endpoint<
      { id: string; dto: Partial<CreateBookingPayload> },
      { booking: Freight.IBooking; warnings: string[] }
    >("bookings", "update", ({ id, dto }) => bookingsService.update(id, dto)),

    referenceData: endpoint<void, Freight.BookingReferenceData>(
      "bookings",
      "referenceData",
      bookingsService.getReferenceData,
    ),

    remove: endpoint<{ id: string }, void>("bookings", "remove", ({ id }) =>
      bookingsService.remove(id),
    ),

    cancel: endpoint<{ id: string; reason: string }, Freight.IBooking>(
      "bookings",
      "cancel",
      ({ id, reason }) => bookingsService.cancel(id, reason),
    ),

    generatePrice: endpoint<{ id: string }, GeneratePriceResponse>(
      "bookings",
      "generatePrice",
      ({ id }) => bookingsService.generatePrice(id),
    ),

    submit: endpoint<{ id: string }, Freight.IBooking>(
      "bookings",
      "submit",
      ({ id }) => bookingsService.submit(id),
    ),

    uploadDocuments: endpoint<
      { id: string; files: Record<string, File | File[] | null> },
      Freight.IBooking
    >("bookings", "uploadDocuments", ({ id, files }) =>
      bookingsService.uploadDocuments(id, files),
    ),

    pay: endpoint<{ id: string }, { redirectUrl: string }>(
      "bookings",
      "pay",
      ({ id }) => bookingsService.pay(id),
    ),

    checkPayment: endpoint<{ orderId: string }, { status: string }>(
      "bookings",
      "checkPayment",
      ({ orderId }) => bookingsService.checkPayment(orderId),
    ),
  },

  consignments: {
    list: endpoint<void, PaginatedResponse<Freight.IConsignment>>(
      "consignments",
      "list",
      consignmentsService.list,
    ),

    get: endpoint<{ id: string }, Freight.IConsignment>(
      "consignments",
      "get",
      ({ id }) => consignmentsService.get(id),
    ),
  },

  tracking: {
    forConsignment: endpoint<
      { consignmentId: string },
      Freight.ITrackingEvent[]
    >("tracking", "forConsignment", ({ consignmentId }) =>
      trackingService.forConsignment(consignmentId),
    ),
  },

  fileUploadSettings: {
    list: endpoint<void, FileUploadSetting[]>(
      "file-upload-settings",
      "list",
      fileUploadSettingsService.list,
    ),

    getById: endpoint<{ id: string }, FileUploadSetting>(
      "file-upload-settings",
      "getById",
      ({ id }) => fileUploadSettingsService.getById(id),
    ),

    getByCode: endpoint<{ code: string }, FileUploadSetting>(
      "file-upload-settings",
      "getByCode",
      ({ code }) => fileUploadSettingsService.getByCode(code),
    ),

    getByEntity: endpoint<{ entity: string }, FileUploadSetting[]>(
      "file-upload-settings",
      "getByEntity",
      ({ entity }) => fileUploadSettingsService.getByEntity(entity),
    ),

    create: endpoint<CreateFileUploadSettingDto, FileUploadSetting>(
      "file-upload-settings",
      "create",
      (payload) => fileUploadSettingsService.create(payload),
    ),

    update: endpoint<
      { id: string; dto: UpdateFileUploadSettingDto },
      FileUploadSetting
    >("file-upload-settings", "update", ({ id, dto }) =>
      fileUploadSettingsService.update(id, dto),
    ),

    remove: endpoint<{ id: string }, void>(
      "file-upload-settings",
      "remove",
      ({ id }) => fileUploadSettingsService.remove(id),
    ),

    replaceFields: endpoint<
      { id: string; fields: CreateFileUploadFieldDto[] },
      FileUploadField[]
    >("file-upload-settings", "replaceFields", ({ id, fields }) =>
      fileUploadSettingsService.replaceFields(id, fields),
    ),

    addField: endpoint<
      { settingId: string; dto: CreateFileUploadFieldDto },
      FileUploadField
    >("file-upload-settings", "addField", ({ settingId, dto }) =>
      fileUploadSettingsService.addField(settingId, dto),
    ),

    updateField: endpoint<
      { fieldId: string; dto: UpdateFileUploadFieldDto },
      FileUploadField
    >("file-upload-settings", "updateField", ({ fieldId, dto }) =>
      fileUploadSettingsService.updateField(fieldId, dto),
    ),

    removeField: endpoint<{ fieldId: string }, void>(
      "file-upload-settings",
      "removeField",
      ({ fieldId }) => fileUploadSettingsService.removeField(fieldId),
    ),
  },

  dropdownSettings: {
    list: endpoint<void, DropdownSetting[]>(
      "dropdown-settings",
      "list",
      dropdownSettingsService.list,
    ),

    getById: endpoint<{ id: string }, DropdownSetting>(
      "dropdown-settings",
      "getById",
      ({ id }) => dropdownSettingsService.getById(id),
    ),

    getByCode: endpoint<{ code: string }, DropdownSetting>(
      "dropdown-settings",
      "getByCode",
      ({ code }) => dropdownSettingsService.getByCode(code),
    ),

    create: endpoint<CreateDropdownSettingDto, DropdownSetting>(
      "dropdown-settings",
      "create",
      (payload) => dropdownSettingsService.create(payload),
    ),

    update: endpoint<
      { id: string; dto: UpdateDropdownSettingDto },
      DropdownSetting
    >("dropdown-settings", "update", ({ id, dto }) =>
      dropdownSettingsService.update(id, dto),
    ),

    remove: endpoint<{ id: string }, void>(
      "dropdown-settings",
      "remove",
      ({ id }) => dropdownSettingsService.remove(id),
    ),
    replaceOptions: endpoint<
      { id: string; options: CreateDropdownOptionDto[] },
      DropdownOption[]
    >("dropdown-settings", "replaceOptions", ({ id, options }) =>
      dropdownSettingsService.replaceOptions(id, options),
    ),

    addOption: endpoint<
      { id: string; dto: CreateDropdownOptionDto },
      DropdownOption
    >("dropdown-settings", "addOption", ({ id, dto }) =>
      dropdownSettingsService.addOption(id, dto),
    ),

    updateOption: endpoint<
      { optionId: string; dto: UpdateDropdownOptionDto },
      DropdownOption
    >("dropdown-settings", "updateOption", ({ optionId, dto }) =>
      dropdownSettingsService.updateOption(optionId, dto),
    ),

    removeOption: endpoint<{ optionId: string }, void>(
      "dropdown-settings",
      "removeOption",
      ({ optionId }) => dropdownSettingsService.removeOption(optionId),
    ),
  },
};
