import {
  GetOrderAddressPath,
  GetOrderAddressResponse,
  GetOrderBuyerInfoPath,
  GetOrderBuyerInfoResponse,
  GetOrderItemsResponse,
  GetOrderItemsBuyerInfoPath,
  GetOrderItemsBuyerInfoQuery,
  GetOrderItemsBuyerInfoResponse,
  GetOrderItemsPath,
  GetOrderItemsQuery,
  GetOrderPath,
  GetOrderResponse,
  GetOrdersQuery,
  GetOrdersResponse
} from "./operations/orders";

import {
  CancelFeedPath,
  CancelFeedResponse,
  CreateFeedBody,
  CreateFeedDocumentBody,
  CreateFeedDocumentResponse,
  CreateFeedResponse,
  GetFeedDocumentPath,
  GetFeedDocumentResponse,
  GetFeedPath,
  GetFeedResponse,
  GetFeedsQuery,
  GetFeedsResponse
} from "./operations/feeds";
import { Config, DownloadDocument, DownloadOptions, Scope } from "./baseTypes";
import {
  ConfirmPreorderPath,
  ConfirmPreorderQuery,
  ConfirmPreorderResponse,
  ConfirmTransportPath,
  ConfirmTransportResponse,
  CreateInboundShipmentPath,
  CreateInboundShipmentBody,
  CreateInboundShipmentResponse,
  CreateInboundShipmentPlanBody,
  CreateInboundShipmentPlanResponse,
  EstimateTransportPath,
  EstimateTransportResponse,
  GetBillOfLadingPath,
  GetBillOfLadingResponse,
  GetLabelsPath,
  GetLabelsQuery,
  GetLabelsResponse,
  GetPreorderInfoPath,
  GetPreorderInfoQuery,
  GetPreorderInfoResponse,
  GetPrepInstructionsQuery,
  GetPrepInstructionsResponse,
  GetShipmentsQuery,
  GetShipmentsResponse,
  GetShipmentItemsByShipmentIdPath,
  GetShipmentItemsByShipmentIdQuery,
  GetShipmentItemsByShipmentIdResponse,
  GetShipmentItemsQuery,
  GetShipmentItemsResponse,
  GetTransportDetailsPath,
  GetTransportDetailsResponse,
  PutTransportDetailsBody,
  PutTransportDetailsPath,
  PutTransportDetailsResponse,
  UpdateInboundShipmentBody,
  UpdateInboundShipmentPath,
  UpdateInboundShipmentResponse,
  VoidTransportPath,
  VoidTransportResponse
} from "./operations/fulfillmentInbound";
import {
  CreateReportBody,
  CreateReportResponse,
  GetReportDocumentPath,
  GetReportDocumentResponse,
  GetReportPath,
  GetReportResponse,
  ReportDocument
} from "./operations/reports";
import {
  GetCatalogItemPath,
  GetCatalogItemQuery,
  GetCatalogItemResponse,
  ListCatalogCategoriesQuery,
  ListCatalogCategoriesResponse
} from "./operations/catalogItems";
import {
  GetInventorySummariesQuery,
  GetInventorySummariesResponse
} from "./operations/fbaInventory";
import {
  GetItemEligibilityPreviewQuery,
  GetItemEligibilityPreviewResponse
} from "./operations/fbaInboundEligibility";
import {
  ListFinancialEventGroupsByGroupIdPath,
  ListFinancialEventGroupsByGroupIdQuery,
  ListFinancialEventGroupsByGroupIdResponse,
  ListFinancialEventGroupsQuery,
  ListFinancialEventGroupsResponse,
  ListFinancialEventsByOrderIdPath,
  ListFinancialEventsByOrderIdQuery,
  ListFinancialEventsByOrderIdResponse,
  ListFinancialEventsQuery,
  ListFinancialEventsResponse
} from "./operations/finances";
import {
  CreateRestrictedDataTokenBody,
  CreateRestrictedDataTokenResponse
} from "./operations/tokens";
import { IReqOptions } from "./IReqOptions";

import { ReportDocumentType } from "./download";
import {
  GetItemOffersPath,
  GetItemOffersQuery,
  GetItemOffersResponse
} from "./operations/productPricing";
import { GetMarketplaceParticipationsResponse } from "./operations/sellers";
import { 
  SearchProductTypesQuery, 
  SearchProductTypesResponse, 
  SearchDefinitionsProductTypesQuery, 
  SearchDefinitionsProductTypesResponse 
} from "./operations/productTypeDefinitions";

declare module "amazon-sp-api" {
  export class SellingPartner {
    constructor(config: Config);

    refreshAccessToken(scope?: Scope): Promise<void>;

    exchange(auth_code: string): Promise<any>;

    get access_token(): string;

    callAPI<TOperation extends Operation>(
      req_params: ReqParams<TOperation>
    ): Promise<ObjectType<TOperation>>;

    download<T extends ReportDocumentType>(
      details: DownloadDocument,
      options?: DownloadOptions
    ): T;

    upload<T>(
      details: {
        url: string;
      },
      feed: {
        content?: string;
        file?: string;
        contentType?: string;
      }
    ): T;

    downloadReport<T extends ReportDocumentType>(body: {
      body: CreateReportBody;
      version?: string;
      interval?: number;
      cancel_after?: number;
      download?: DownloadOptions;
    }): T;
  }

  type Operation =
    | "getCatalogItem"
    | "listCatalogCategories"
    | "getItemEligibilityPreview"
    | "getInventorySummaries"
    | "getFeeds"
    | "createFeed"
    | "getFeed"
    | "cancelFeed"
    | "createFeedDocument"
    | "getFeedDocument"
    | "listFinancialEventGroups"
    | "listFinancialEventsByGroupId"
    | "listFinancialEventsByOrderId"
    | "listFinancialEvents"
    | "updateInboundShipment"
    | "createInboundShipment"
    | "getPreorderInfo"
    | "confirmPreorder"
    | "getPrepInstructions"
    | "getReport"
    | "getReportDocument"
    | "getOrders"
    | "getOrder"
    | "getOrderBuyerInfo"
    | "getOrderAddress"
    | "getOrderItems"
    | "getOrderItemsBuyerInfo"
    | "getTransportDetails"
    | "putTransportDetails"
    | "voidTransport"
    | "estimateTransport"
    | "confirmTransport"
    | "createRestrictedDataToken"
    | "getLabels"
    | "getBillOfLading"
    | "getShipments"
    | "getShipmentItemsByShipmentId"
    | "getShipmentItems"
    | "getItemOffers"
    | "productPricing.getItemOffers"
    | "getMarketplaceParticipations"
    | "searchProductTypes"
    | "searchDefinitionsProductTypes"
    | string;

  type ObjectType<TOperation> = TOperation extends "getCatalogItem"
    ? GetCatalogItemResponse
    : TOperation extends "listCatalogCategories"
    ? ListCatalogCategoriesResponse
    : TOperation extends "getItemEligibilityPreview"
    ? GetItemEligibilityPreviewResponse
    : TOperation extends "getInventorySummaries"
    ? GetInventorySummariesResponse
    : TOperation extends "getFeeds"
    ? GetFeedsResponse
    : TOperation extends "createFeed"
    ? CreateFeedResponse
    : TOperation extends "getFeed"
    ? GetFeedResponse
    : TOperation extends "cancelFeed"
    ? CancelFeedResponse
    : TOperation extends "createFeedDocument"
    ? CreateFeedDocumentResponse
    : TOperation extends "getFeedDocument"
    ? GetFeedDocumentResponse
    : TOperation extends "listFinancialEventGroups"
    ? ListFinancialEventGroupsResponse
    : TOperation extends "listFinancialEventsByGroupId"
    ? ListFinancialEventGroupsByGroupIdResponse
    : TOperation extends "listFinancialEventsByOrderId"
    ? ListFinancialEventsByOrderIdResponse
    : TOperation extends "listFinancialEvents"
    ? ListFinancialEventsResponse
    : TOperation extends "updateInboundShipment"
    ? UpdateInboundShipmentResponse
    : TOperation extends "createInboundShipment"
    ? CreateInboundShipmentResponse
    : TOperation extends "getPreorderInfo"
    ? GetPreorderInfoResponse
    : TOperation extends "confirmPreorder"
    ? ConfirmPreorderResponse
    : TOperation extends "getPrepInstructions"
    ? GetPrepInstructionsResponse
    : TOperation extends "getReport"
    ? GetReportResponse
    : TOperation extends "getReportDocument"
    ? GetReportDocumentResponse
    : TOperation extends "getOrders"
    ? GetOrdersResponse
    : TOperation extends "getOrder"
    ? GetOrderResponse
    : TOperation extends "getOrderBuyerInfo"
    ? GetOrderBuyerInfoResponse
    : TOperation extends "getOrderAddress"
    ? GetOrderAddressResponse
    : TOperation extends "getOrderItem"
    ? GetOrderItemsResponse
    : TOperation extends "getOrderItemsBuyerInfo"
    ? GetOrderItemsBuyerInfoResponse
    : TOperation extends "createInboundShipmentPlan"
    ? CreateInboundShipmentPlanResponse
    : TOperation extends "putTransportDetails"
    ? PutTransportDetailsResponse
    : TOperation extends "getTransportDetails"
    ? GetTransportDetailsResponse
    : TOperation extends "voidTransport"
    ? VoidTransportResponse
    : TOperation extends "estimateTransport"
    ? EstimateTransportResponse
    : TOperation extends "confirmTransport"
    ? ConfirmTransportResponse
    : TOperation extends "createRestrictedDataToken"
    ? CreateRestrictedDataTokenResponse
    : TOperation extends "getLabels"
    ? GetLabelsResponse
    : TOperation extends "getBillOfLading"
    ? GetBillOfLadingResponse
    : TOperation extends "getShipments"
    ? GetShipmentsResponse
    : TOperation extends "getShipmentItemsByShipmentId"
    ? GetShipmentItemsByShipmentIdResponse
    : TOperation extends "getShipmentItems"
    ? GetShipmentItemsResponse
    : // ProductPricing
    TOperation extends "getItemOffers"
    ? GetItemOffersResponse
    : TOperation extends "productPricing.getItemOffers"
    ? GetItemOffersResponse
    : TOperation extends "createReport"
    ? CreateReportResponse
    : TOperation extends "getMarketplaceParticipations"
    ? GetMarketplaceParticipationsResponse
    : TOperation extends "searchProductTypes"
    ? SearchProductTypesResponse
    : TOperation extends "searchDefinitionsProductTypes"
    ? SearchDefinitionsProductTypesResponse
    : any;

  type QueryType<TOperation extends Operation> =
    TOperation extends "getCatalogItem"
    ? GetCatalogItemQuery
    : TOperation extends "listCatalogCategories"
    ? ListCatalogCategoriesQuery
    : TOperation extends "getItemEligibilityPreview"
    ? GetItemEligibilityPreviewQuery
    : TOperation extends "getInventorySummaries"
    ? GetInventorySummariesQuery
    : TOperation extends "getFeeds"
    ? GetFeedsQuery
    : TOperation extends "listFinancialEventGroups"
    ? ListFinancialEventGroupsQuery
    : TOperation extends "listFinancialEventsByGroupId"
    ? ListFinancialEventGroupsByGroupIdQuery
    : TOperation extends "listFinancialEventsByOrderId"
    ? ListFinancialEventsByOrderIdQuery
    : TOperation extends "listFinancialEvents"
    ? ListFinancialEventsQuery
    : TOperation extends "getPreorderInfo"
    ? GetPreorderInfoQuery
    : TOperation extends "confirmPreorder"
    ? ConfirmPreorderQuery
    : TOperation extends "getPrepInstructions"
    ? GetPrepInstructionsQuery
    : TOperation extends "createReport"
    ? CreateReportResponse
    : TOperation extends "getOrders"
    ? GetOrdersQuery
    : TOperation extends "getOrderItems"
    ? GetOrderItemsQuery
    : TOperation extends "getOrderItemsBuyerInfo"
    ? GetOrderItemsBuyerInfoQuery
    : TOperation extends "getLabels"
    ? GetLabelsQuery
    : TOperation extends "getShipments"
    ? GetShipmentsQuery
    : TOperation extends "getShipmentItemsByShipmentId"
    ? GetShipmentItemsByShipmentIdQuery
    : TOperation extends "getShipmentItems"
    ? GetShipmentItemsQuery
    : // ProductPricing
    TOperation extends "getItemOffers"
    ? GetItemOffersQuery
    : TOperation extends "productPricing.getItemOffers"
    ? GetItemOffersQuery
    : TOperation extends "searchProductTypes"
    ? SearchProductTypesQuery
    : TOperation extends "searchDefinitionsProductTypes"
    ? SearchDefinitionsProductTypesQuery
    : any;

  type PathType<TOperation extends Operation> =
    TOperation extends "getCatalogItem"
    ? GetCatalogItemPath
    : TOperation extends "getFeed"
    ? GetFeedPath
    : TOperation extends "cancelFeed"
    ? CancelFeedPath
    : TOperation extends "getFeedDocument"
    ? GetFeedDocumentPath
    : TOperation extends "listFinancialEventsByGroupId"
    ? ListFinancialEventGroupsByGroupIdPath
    : TOperation extends "listFinancialEventsByOrderId"
    ? ListFinancialEventsByOrderIdPath
    : TOperation extends "updateInboundShipment"
    ? UpdateInboundShipmentPath
    : TOperation extends "createInboundShipment"
    ? CreateInboundShipmentPath
    : TOperation extends "getPreorderInfo"
    ? GetPreorderInfoPath
    : TOperation extends "confirmPreorder"
    ? ConfirmPreorderPath
    : TOperation extends "getReport"
    ? GetReportPath
    : TOperation extends "getReportDocument"
    ? GetReportDocumentPath
    : TOperation extends "getOrder"
    ? GetOrderPath
    : TOperation extends "getOrderAddress"
    ? GetOrderAddressPath
    : TOperation extends "getOrderItems"
    ? GetOrderItemsPath
    : TOperation extends "getOrderItemsBuyerInfo"
    ? GetOrderItemsBuyerInfoPath
    : TOperation extends "getOrderBuyerInfo"
    ? GetOrderBuyerInfoPath
    : TOperation extends "putTransportDetails"
    ? PutTransportDetailsPath
    : TOperation extends "getTransportDetails"
    ? GetTransportDetailsPath
    : TOperation extends "voidTransport"
    ? VoidTransportPath
    : TOperation extends "estimateTransport"
    ? EstimateTransportPath
    : TOperation extends "confirmTransport"
    ? ConfirmTransportPath
    : TOperation extends "getLabels"
    ? GetLabelsPath
    : TOperation extends "getBillOfLading"
    ? GetBillOfLadingPath
    : TOperation extends "getShipmentItemsByShipmentId"
    ? GetShipmentItemsByShipmentIdPath
    : // ProductPricing
    TOperation extends "getItemOffers"
    ? GetItemOffersPath
    : TOperation extends "productPricing.getItemOffers"
    ? GetItemOffersPath
    : any;

  type BodyType<TOperation extends Operation> = TOperation extends "createFeed"
    ? CreateFeedBody
    : TOperation extends "createFeedDocument"
    ? CreateFeedDocumentBody
    : TOperation extends "createInboundShipmentPlan"
    ? CreateInboundShipmentPlanBody
    : TOperation extends "updateInboundShipment"
    ? UpdateInboundShipmentBody
    : TOperation extends "createInboundShipment"
    ? CreateInboundShipmentBody
    : TOperation extends "createReport"
    ? CreateReportBody
    : TOperation extends "putTransportDetails"
    ? PutTransportDetailsBody
    : TOperation extends "createRestrictedDataToken"
    ? CreateRestrictedDataTokenBody
    : any;

  type ReqOptions = IReqOptions;

  export interface ReqParams<TOperation extends Operation> {
    operation: TOperation;
    endpoint?: string;
    restricted_data_token?: string;
    path?: PathType<TOperation>;
    query?: QueryType<TOperation>;
    body?: BodyType<TOperation>;
    options?: ReqOptions;
    scope?: Scope;
    api_path?: string;
    method?: HttpMethod;
  }

  type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
}
