import { ImportedTrackingEvent } from '../models';
import type { Request } from 'express';
import {
  RegisterRequest,
  CreateLabelRequest,
  VoidLabelsRequest,
  CreateManifestRequest,
  GetManifestRequest,
  SchedulePickupRequest,
  CancelPickupRequest,
  GetRatesRequest,
  TrackingRequest,
  CancelNotificationRequest,
  CreateNotificationRequest,
  ValidateInboundDataRequest,
  NormalizeTrackingDataRequest,
  GetRelayPointsRequest,
  GetServicePointsRequest,
  GetServicePointRequest,
  ImportTrackingEventsRequest,
  UpdateSettingsRequest,
} from '../requests';

import {
  RegisterResponse,
  CreateLabelResponse,
  VoidLabelsResponse,
  CreateManifestResponse,
  SchedulePickupResponse,
  CancelPickupResponse,
  GetRatesResponse,
  TrackingResponse,
  CancelNotificationResponse,
  CreateNotificationResponse,
  ValidateInboundDataResponse,
  NormalizeTrackingDataResponse,
  GetRelayPointsResponse,
  GetServicePointsResponse,
  GetServicePointResponse,
  UpdateSettingsResponse,
} from '../responses';

import { CarrierAppMetadata } from './metadata/carrier-app-metadata';

import { RequestResponseInfo, Handler } from '@shipengine/connect-runtime';

/**
 * @description This defines a connect carrier app
 */
export interface CarrierAppDefinition {
  Metadata: CarrierAppMetadata;
  /**
   * @description This method is used to register an account
   * @param request The information needed to register or initialize a connection with the shipping provider
   */
  Register?: (request: RegisterRequest) => RegisterResponse | Promise<RegisterResponse>;
  /**
   * @description This method is used to create a label
   * @param request Data needed by the provider to create a label
   */
  CreateLabel?: (request: CreateLabelRequest) => CreateLabelResponse | Promise<CreateLabelResponse>;
  /**
   * @description This method is used to void multiple labels
   * @param request Data needed by the provider to void multiple labels
   */
  VoidLabels?: (request: VoidLabelsRequest) => VoidLabelsResponse | Promise<VoidLabelsResponse>;
  /**
   * @description This method is used to create a manifest with a carrier
   * @param request Data needed by the provider to create a manifest
   */
  CreateManifest?: (
    request: CreateManifestRequest,
  ) => CreateManifestResponse | Promise<CreateManifestResponse>;
  /**
   * @description This method is used to retrieve a manifest with a carrier
   * @param request Data needed by the provider to retrieve a previousely created manifest
   */
  GetManifest?: (
    request: GetManifestRequest,
  ) => CreateManifestResponse | Promise<CreateManifestResponse>;
  /**
   * @description This endpoint is used to schedule an adhoc pickup with the shipping provider
   * @param request Data needed by the provider to schedule adhoc pickups
   */
  SchedulePickup?: (
    request: SchedulePickupRequest,
  ) => SchedulePickupResponse | Promise<SchedulePickupResponse>;
  /**
   * @description This endpoint is used to cancel a previously scheduled pickup
   * @param request Data needed by the provider to cancel a pickup
   */
  CancelPickup?: (
    request: CancelPickupRequest,
  ) => CancelPickupResponse | Promise<CancelPickupResponse>;
  /**
   * @description This endpoint is used to get rates for a particular shipment
   * @param request Data needed by the provider to get a rate estimate
   */
  GetRates?: (request: GetRatesRequest) => GetRatesResponse | Promise<GetRatesResponse>;
  /**
   * @description This endpoint is used to get tracking information about a shipment
   * @param request Data needed by the provider to track a shipment
   */
  Track?: (request: TrackingRequest) => TrackingResponse | Promise<TrackingResponse>;
  /**
   * @description This endpoint is used to submit notification of the creation of a shipment
   * @param request Data needed by the provider to inform them of a shipment
   */
  CreateNotification?: (
    request: CreateNotificationRequest,
  ) => CreateNotificationResponse | Promise<CreateNotificationResponse>;
  /**
   * @description This endpoint is used to submit cancellation of a shipment notification
   * @param request Data needed by the provider to inform them of the cancellation
   */
  CancelNotification?: (
    request: CancelNotificationRequest,
  ) => CancelNotificationResponse | Promise<CancelNotificationResponse>;
  /**
   * @description This endpoint is used to validate inbound data and determine the type of data included in the inbound message
   * @param request Data received from the provider via an inbound method, such as a webhook
   */
  ValidateInboundData?: (
    request: ValidateInboundDataRequest,
  ) => ValidateInboundDataResponse | Promise<ValidateInboundDataResponse>;
  /**
   * @description This endpoint is used to normalize inbound tracking data and determine the type of data
   * @param request Tracking data received from the provider via an inbound method, such as a webhook
   */
  NormalizeTrackingData?: (
    request: NormalizeTrackingDataRequest,
  ) => NormalizeTrackingDataResponse | Promise<NormalizeTrackingDataResponse>;
  /**
   * @description This endpoint is used to get all relay points for carrier
   * @param request Data needed by the provider about the relay points to be returned
   */
  GetRelayPoints?: (
    request: GetRelayPointsRequest,
  ) => GetRelayPointsResponse | Promise<GetRelayPointsResponse>;
  /**
   * @description This endpoint is used to get carrier service points
   * @param request Data needed by the provider about the service points to be returned
   */
  GetServicePoints?: (
    request: GetServicePointsRequest,
  ) => GetServicePointsResponse | Promise<GetServicePointsResponse>;
  /**
   * @description This endpoint is used to get a carrier service point by id
   * @param request Data needed by the provider about the service point to be returned
   */
  GetServicePoint?: (
    request: GetServicePointRequest,
  ) => GetServicePointResponse | Promise<GetServicePointResponse>;
  /**
   * @description This endpoint is used to import tracking events for a connection by id
   * @param request Data needed by the provider to import tracking events
   */
  ImportTrackingEvents?: (
    request: ImportTrackingEventsRequest,
  ) => AsyncGenerator<ImportedTrackingEvent>;

  ScheduledFunction?: (request: Record<string, any>) => Promise<{}[] | null> | {}[] | null;

  /** @description A method that gets additional context to log from the request when logging */
  getAdditionalContext?: (req: Request) => Record<string, string>;
  /** @description A method that redacts external HTTP requests and responses to prevent logging sensitive information */
  redactExternalRequest?: (
    req: RequestResponseInfo,
  ) => Promise<RequestResponseInfo> | RequestResponseInfo;
  /** @description A method that gets additional information to return with the diagnostic version route */
  getAdditionalVersionInfo?: () => Promise<Record<string, string>> | Record<string, string>;
  /**
   * @description This endpoint is used to update carrier settings
   * @param request Data needed by the provider to update carrier settings
   */
  UpdateSettings?: (
    request: UpdateSettingsRequest,
  ) => UpdateSettingsResponse | Promise<UpdateSettingsResponse>;
  /**
   * @description A collection of additional routes that can be used to extend the functionality of the app.
   * Extension methods are not automatically called by the ShipEngine platform, and require working with Auctane developers to implement.
   * The request and response shapes of each method will be defined by Auctane, but will not be documented as part of Connect unless
   * they are made public and the functionality is taken out of extensions and into a named method.
   */
  Extensions?: Record<string, Handler>;
}
