import type { Freight, PaginatedResponse } from "@edr/types";
import { endpoint } from "@/utils/endpoint";
import type {
  CreateFileUploadFieldDto,
  FileUploadField,
  FileUploadSetting,
  UpdateFileUploadFieldDto,
} from "@/types/fileUploadSettings";
import {
  bookingsService,
  BookingListFilter,
  CreateBookingPayload,
  GeneratePriceResponse,
  SubmitBookingResponse,
} from "./bookings.service";
import {
  bookingOrdersService,
  CreateBookingOrderPayload,
} from "./booking-orders.service";
import type { BookingDocuments } from "@/pages/bookings/new-booking-form/schema";
import {
  paymentsService,
  InitiatePaymentPayload,
  InitiateResponse,
  IntentStatus,
} from "./payments.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,
  CompanyNationality,
  CompanyProfileResponse,
  CreateCompanyPayload,
  DashboardSummary,
  ProfileTypeValue,
} 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,
    ),

    getDashboard: endpoint<string | undefined, DashboardSummary>(
      "companies",
      "getDashboard",
      companiesService.getDashboard,
    ),

    addCompanyProfiles: endpoint<{ types: string[] }, CompanyProfileResponse[]>(
      "companies",
      "addCompanyProfiles",
      companiesService.addCompanyProfiles,
    ),

    createCompanyProfile: endpoint<
      { type: ProfileTypeValue; businessLicense?: string },
      CompanyProfileResponse
    >("companies", "createCompanyProfile", companiesService.createCompanyProfile),

    startOnboarding: endpoint<
      {
        companyType: string;
        roles: ProfileTypeValue[];
        nationality?: CompanyNationality;
      },
      CompanyInfoResponse
    >("companies", "startOnboarding", companiesService.startOnboarding),

    setActiveMode: endpoint<{ type: ProfileTypeValue }, CompanyInfoResponse>(
      "companies",
      "setActiveMode",
      companiesService.setActiveMode,
    ),

    setOnboardingStep: endpoint<{ step: string }, void>(
      "companies",
      "setOnboardingStep",
      companiesService.setOnboardingStep,
    ),

    completeOnboarding: endpoint<void, CompanyInfoResponse>(
      "companies",
      "completeOnboarding",
      companiesService.completeOnboarding,
    ),
  },

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

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

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

    create: endpoint<
      { payload: CreateBookingPayload; documents?: BookingDocuments },
      Freight.IBooking
    >("bookings", "create", ({ payload, documents }) =>
      bookingsService.create(payload, documents),
    ),

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

    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),
    ),

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

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

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

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

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

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

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

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

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

    getBookableSchedules: endpoint<
      { originYardId?: string; destinationYardId?: string },
      Freight.BookableScheduleItem[]
    >(
      "train-scheduling",
      "bookableSchedules",
      ({ originYardId, destinationYardId }) =>
        bookingsService.getBookableSchedules({
          originYardId,
          destinationYardId,
        }),
    ),

    getAvailableDays: endpoint<
      { originYardId?: string; destinationYardId?: string },
      string[]
    >(
      "train-scheduling",
      "availableDays",
      ({ originYardId, destinationYardId }) =>
        bookingsService.getAvailableDays({ originYardId, destinationYardId }),
    ),
  },

  bookingOrders: {
    listByContract: endpoint<
      { contractBookingId: string },
      Freight.IBookingOrder[]
    >("booking-orders", "listByContract", ({ contractBookingId }) =>
      bookingOrdersService.listByContract(contractBookingId),
    ),

    pool: endpoint<
      { contractBookingId: string },
      Freight.ContractQuantityLine[]
    >("booking-orders", "pool", ({ contractBookingId }) =>
      bookingOrdersService.pool(contractBookingId),
    ),

    routes: endpoint<
      { contractBookingId: string },
      Freight.ContractRouteLine[]
    >("booking-orders", "routes", ({ contractBookingId }) =>
      bookingOrdersService.routes(contractBookingId),
    ),

    create: endpoint<CreateBookingOrderPayload, Freight.IBookingOrder>(
      "booking-orders",
      "create",
      (payload) => bookingOrdersService.create(payload),
    ),
  },

  payments: {
    initiate: endpoint<InitiatePaymentPayload, InitiateResponse>(
      "payments",
      "initiate",
      paymentsService.initiate,
    ),

    getIntent: endpoint<{ bookingId: string }, IntentStatus>(
      "payments",
      "getIntent",
      ({ bookingId }) => paymentsService.getIntent(bookingId),
    ),
  },

  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),
    ),

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