// deno-lint-ignore-file
import { describe, it, stub, assertSpyCalls, assertSpyCallArgs } from '#test';
import { Query } from './query.ts';
import type * as m from './models/mod.ts';
import type { AddToCartPopupParams, AddToCartPopupBody } from './models/add-to-cart-popup.ts';
import type { AutocompleteParams, AutocompleteBody } from './models/autocomplete.ts';
import type { NavigationTreeParams } from './models/navigation-tree.ts';
import type { SearchPageParams, SearchPageBody } from './models/search-page.ts';


let fetchSpy: ReturnType<typeof createSpy>;
let response: Promise<Response>;
const createSpy = () => stub(globalThis, 'fetch', () => response);

const suite = describe({
  name: 'query',
  beforeEach() {
    fetchSpy = createSpy();
    response = Promise.resolve(new Response('{}', { status: 200 }));
  },
  afterEach() {
    fetchSpy.restore();
  }
});
const addToCartPopupSuite = describe(suite, 'addToCartPopup()');
const autocompleteSuite = describe(suite, 'autocomplete()');
const navigationTreeSuite = describe(suite, 'navigationTree()');
const searchPageSuite = describe(suite, 'searchPage()');
const productPageSuite = describe(suite, 'productPage()');
const cartPageSuite = describe(suite, 'cartPage()');
const landingPageSuite = describe(suite, 'landingPage()');
const sponsoredPageSuite = describe(suite, 'sponsoredPage()');
const contentInformationSuite = describe(suite, 'contentInformation()');
const contentSearchPageSuite = describe(suite, 'contentSearchPage()');

// TODO(csv): Use a single method for checking `ProductFilter` type and values?
it.ignore('should allow all valid productFilter values for page bodies', () => {});

it(addToCartPopupSuite, 'should pass on correct endpoint, params and body parameters to Request', async () => {
  const query = new Query({
    clusterUrl: 'http://localhost:13',
    market: 'fr',
    locale: 'fr-FR',
    touchpoint: 'mobile',
    session: () => ({ customerKey: 'c13', sessionKey: 's13' })
  });
  const params = Object.freeze<AddToCartPopupParams>({ variantKey: 'some_special_key' });
  const body = Object.freeze<AddToCartPopupBody>([{
    id: '1313',
    algorithm: 'ADD_TO_CART_RECS'
  }]);

  await query.addToCartPopup(params, body as AddToCartPopupBody);

  const expectedUrl = new URL('http://localhost:13/api/storefront/v3/queries/add-to-cart-popup?market=fr&customerKey=c13&sessionKey=s13&locale=fr-FR&touchpoint=mobile&variantKey=some_special_key');
  const expectedBody = '{"recommendationLists":[{"id":"1313","algorithm":"ADD_TO_CART_RECS"}]}';
  assertSpyCalls(fetchSpy, 1);
  assertSpyCallArgs(fetchSpy, 0, [
    expectedUrl,
    { method: 'POST', body: expectedBody, headers: { 'Content-Type': 'text/plain' } }
  ]);
});

it(addToCartPopupSuite, 'should allow all API parameters and body options (kitchen sink)', async () => {
  const query = new Query({
    clusterUrl: 'http://localhost:13',
    market: 'fr',
    locale: 'fr-FR',
    touchpoint: 'mobile',
    session: () => ({ customerKey: 'c13', sessionKey: 's13' })
  });
  const result = await query.addToCartPopup({
    variantKey: 'very_special_key',
    cart: ['cart-one'],
    channels: 'ONLINE|STORE',
    notify: true,
    presentCustom: ['something', 'anything'],
    presentPrices: ['low', 'high'],
    priceId: 'highPrice',
    stores: 'store-one|store-two',
    templateId: 'tpl-2',
    viewId: 'preview',
  }, [{
    id: '1313',
    algorithm: 'ADD_TO_CART_RECS',
    label: 'Do you have everything you need?',
    limit: 9,
    params: {
      cart: ['cart-one'],
      productKey: 'pk1234'
    },
    productRules: 'rule incl newness 10d ',
    showMoreLink: '/add-to-cart-popup',
    visualization: 'GRID'
  }]
  );

  result satisfies m.RecommendationListPage;
  result.recommendationLists satisfies m.RecommendationList[];
});

it(autocompleteSuite, 'should pass on correct endpoint, params, and body parameters to Request', async() => {
  const query = new Query({
    clusterUrl: 'http://localhost:10',
    market: 'se',
    locale: 'sv-SE',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c10', sessionKey: 's10' })
  });
  const params = Object.freeze<AutocompleteParams>({
    q: 'foo',
    notify: false,
    viewId: 'production',
    priceId: 'default',
    channels: 'ONLINE',
    stores: 'lund',
    presentCustom: ['material']
  });
  const body = Object.freeze<AutocompleteBody>({
    contentLists: [{
      id: '1',
    }],
    productFilter: { size: ['XL'] }
  });

  await query.autocomplete(params, body);

  const expectedUrl = new URL('http://localhost:10/api/storefront/v3/queries/autocomplete?market=se&customerKey=c10&sessionKey=s10&locale=sv-SE&touchpoint=desktop&q=foo&notify=false&viewId=production&priceId=default&channels=ONLINE&stores=lund&presentCustom=material');
  const expectedBody = '{"contentLists":[{"id":"1"}],"productFilter":{"size":["XL"]}}';
  assertSpyCalls(fetchSpy, 1);
  assertSpyCallArgs(fetchSpy, 0, [
    expectedUrl,
    { method: 'POST', body: expectedBody, headers: { 'Content-Type': 'text/plain' } }
  ]);
});

it(autocompleteSuite, 'should allow all API parameters and body options (kitchen sink)', async() => {
  const query = new Query({
    clusterUrl: 'http://localhost:11',
    market: 'se2',
    locale: 'sv-SE2',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c11', sessionKey: 's11' })
  });
  const result = await query.autocomplete({
    q: 'robe',
    notify: false,
    viewId: 'production',
    priceId: 'default',
    channels: 'ONLINE',
    stores: 'storeA|storeB',
    templateId: 'my-data-template',
    presentCustom: ['foo', 'bar'],
    presentPrices: ['discount']
  }, {
    contentLists: [{ id: 'asd', algorithm: 'NEWEST_CONTENT', limit: 2, contentFilter: { type: 'article' } }],
    productFilter: {
      brand: 'Nike',
      color: ['RED', 'GREEN'],
      price: { min: 10, max: 100 }
    },
    productRules: 'rule incl newness 10d '
  });

  result satisfies m.Autocomplete;
  result.contentSuggestions satisfies m.ContentSuggestion[];
  result.phraseSuggestions satisfies m.PhraseSuggestion[];
  result.productSuggestions satisfies m.ProductGroup[];
  result.contentLists satisfies m.ContentList[];
  result.totalHits satisfies number;
  result.redirectLink satisfies string | undefined;
});

it(navigationTreeSuite, 'should pass on correct endpoint, and params, parameters to Request', async() => {
  const query = new Query({
    clusterUrl: 'http://localhost:20',
    market: 'en',
    locale: 'en-US',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c20', sessionKey: 's20' })
  });
  const params = Object.freeze<NavigationTreeParams>({
    priceId: 'SEK',
    notify: true
  });
  await query.navigationTree(params);

  const expectedUrl = new URL('http://localhost:20/api/storefront/v3/queries/navigation-tree?market=en&customerKey=c20&sessionKey=s20&locale=en-US&touchpoint=desktop&priceId=SEK&notify=true');
  assertSpyCalls(fetchSpy, 1);
  assertSpyCallArgs(fetchSpy, 0, [expectedUrl, { method: 'GET' }]);
});

it(navigationTreeSuite, 'should allow all API parameters and body options (kitchen sink)', async () => {
  const query = new Query({
    clusterUrl: 'http://localhost:21',
    market: 'en2',
    locale: 'en-US2',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c21', sessionKey: 's21' })
  });
  const result = await query.navigationTree({
    notify: false,
    viewId: 'production',
    priceId: 'default',
    channels: 'STORE',
    stores: 'storeZ|storeD'
  });

  result satisfies m.NavigationTree;
  result.tree satisfies m.NavigationNode;
});

it(searchPageSuite, 'should pass on correct endpoint, facets, params, and body parameters to Request', async() => {
  const query = new Query({
    clusterUrl: 'http://localhost:30',
    market: 'dk',
    locale: 'da-DK',
    touchpoint: 'mobile',
    session: () => ({ customerKey: 'c30', sessionKey: 's30' })
  });
  const params = Object.freeze<SearchPageParams>({
    q: 'shirt',
    limit: 11,
    facets: {
      color: ['steelblue']
    }
  });
  const body = Object.freeze<SearchPageBody>({ primaryList: { include: true } });
  await query.searchPage(params, body);

  const expectedUrl = new URL('http://localhost:30/api/storefront/v3/queries/search-page?market=dk&customerKey=c30&sessionKey=s30&locale=da-DK&touchpoint=mobile&q=shirt&limit=11&f.color=steelblue');
  const expectedBody = '{"primaryList":{"include":true}}';
  assertSpyCalls(fetchSpy, 1);
  assertSpyCallArgs(fetchSpy, 0, [
    expectedUrl,
    { method: 'POST', body: expectedBody, headers: { 'Content-Type': 'text/plain' } }
  ]);
});

it(searchPageSuite, 'should allow all API parameters and body options (kitchen sink)', async() => {
  const sort: 'RELEVANCE' | 'NEWEST_FIRST' | 'PRICE_ASCENDING' | 'PRICE_DESCENDING' | 'DISCOUNT' | 'RATING' = 'RELEVANCE';
  const origin: 'ORGANIC' | 'PHRASE_SUGGEST' | 'DID_YOU_MEAN' | 'UNDO_AUTO_CORRECT' | 'RELATED_SEARCHES'
    = 'ORGANIC';
  const query = new Query({
    clusterUrl: 'http://localhost:31',
    market: 'dk2',
    locale: 'da-DK2',
    touchpoint: 'mobile',
    session: () => ({ customerKey: 'c31', sessionKey: 's31' })
  });
  const result = await query.searchPage({
    q: 'robe',
    sort,
    origin,
    limit: 20,
    skip: 10,
    notify: false,
    viewId: 'production',
    priceId: 'default',
    channels: 'ONLINE|STORE',
    stores: 'storeF',
    selectedCategory: 'women',
    templateId: 'list-template',
    viewAllSecondary: true,
    presentCustom: ['lorem', 'ipsum'],
    presentPrices: ['VIP'],
    facets: {
      color: ['firebrick'],
      brand: ['nike', 'adidas'],
      price: { min: 10, max: 500 },
      coolFactor: { min: 9001 },
      length: { max: 180 }
    }
  }, {
    navigation: { include: true },
    primaryList: {
      include: true,
      productFilter: {
        brand: 'Nike',
        color: ['RED', 'GREEN'],
        price: { min: 10, max: 100 }
      },
      productRules: 'rule incl newness 10d '
    },
    contentLists: [
      { id: 'jgf', limit: 11, algorithm: 'TOP_CONTENT', contentFilter: { content_key: 'ck12345' } }
    ]
  });

  result satisfies m.SearchPage;
  result.q satisfies string;
  result.primaryList satisfies m.PrimaryList;
  result.didYouMean satisfies m.DidYouMean[];
  result.autoCorrect satisfies m.AutoCorrect | undefined;
  result.navigation satisfies m.Navigation | undefined;
  result.contentLists satisfies m.ContentList[];
  result.secondaryList satisfies m.SecondaryList | undefined;
  result.relatedSearches satisfies m.RelatedSearch[] | undefined;
});

it(productPageSuite, 'should pass on correct endpoint, facets, params, and body parameters to Request', async () => {
  const query = new Query({
    clusterUrl: 'http://localhost:40',
    market: 'no',
    locale: 'no-NO',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c40', sessionKey: 's40' })
  });
  const params = Object.freeze({
    productKey: 'p123456',
    viewId: 'production' as const
  });
  const body = Object.freeze({ productGroup: { include: true } });
  await query.productPage(params, body);

  const expectedUrl = new URL('http://localhost:40/api/storefront/v3/queries/product-page?market=no&customerKey=c40&sessionKey=s40&locale=no-NO&touchpoint=desktop&productKey=p123456&viewId=production');
  const expectedBody = '{"productGroup":{"include":true}}';
  assertSpyCalls(fetchSpy, 1);
  assertSpyCallArgs(fetchSpy, 0, [
    expectedUrl,
    { method: 'POST', body: expectedBody, headers: { 'Content-Type': 'text/plain' } }
  ]);
});

it(productPageSuite, 'should allow all API parameters and body options (kitchen sink)', async() => {
  const query = new Query({
    clusterUrl: 'http://localhost:41',
    market: 'no2',
    locale: 'no-NO2',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c41', sessionKey: 's41' })
  });
  const result = await query.productPage({
    productKey: 'pk1234567',
    notify: false,
    viewId: 'production',
    priceId: 'default',
    channels: 'STORE|ONLINE',
    stores: '123|abc|xyz',
    templateId: 'rec-list-template',
    presentCustom: ['season', 'age'],
    presentPrices: ['member']
  }, {
    productGroup: {
      include: true
    },
    recommendationLists: [
      { id: 'top', label: 'Top sellers', limit: 8, algorithm: 'TOP_PRODUCTS', visualization: 'GRID', showMoreLink: '/top', params: { productKey: 'pk1234' } }
    ]
  });

  result satisfies m.ProductPage;
  result.productGroup satisfies m.ProductGroup | undefined;
  result.recommendationLists satisfies m.RecommendationList[];
});

it(cartPageSuite, 'should pass on correct endpoint, facets, params, and body parameters to Request', async () => {
  const query = new Query({
    clusterUrl: 'http://localhost:50',
    market: 'fi',
    locale: 'fi-FI',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c50', sessionKey: 's50' })
  });
  const params = Object.freeze({
    cart: ['p123456', 'p234567'],
    viewId: 'production' as const
  });
  const body = Object.freeze({ cart: { include: true } });
  await query.cartPage(params, body);

  const expectedUrl = new URL('http://localhost:50/api/storefront/v3/queries/cart-page?market=fi&customerKey=c50&sessionKey=s50&locale=fi-FI&touchpoint=desktop&cart=p123456%7Cp234567&viewId=production');
  const expectedBody = '{"cart":{"include":true}}';
  assertSpyCalls(fetchSpy, 1);
  assertSpyCallArgs(fetchSpy, 0, [
    expectedUrl,
    { method: 'POST', body: expectedBody, headers: { 'Content-Type': 'text/plain' } }
  ]);
});

it(cartPageSuite, 'should allow all API parameters and body options (kitchen sink)', async() => {
  const query = new Query({
    clusterUrl: 'http://localhost:51',
    market: 'fi2',
    locale: 'fi-FI2',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c51', sessionKey: 's51' })
  });
  const result = await query.cartPage({
    cart: ['pk1234567', 'pk2345678'],
    notify: true,
    viewId: 'preview',
    priceId: 'default',
    channels: 'ONLINE',
    stores: 'storeA|storeB',
    templateId: 'rec-list-template',
    presentCustom: ['red', 'blue'],
    presentPrices: ['SEK', 'EURO']
  }, {
    cart: {
      include: true
    },
    recommendationLists: [
      { id: 'cart', label: 'Cart recs', limit: 8, algorithm: 'CART', visualization: 'GRID', showMoreLink: '/top', params: { cart: ['pk1234'] } }
    ]
  });

  result satisfies m.CartPage;
  result.cart satisfies m.ProductGroup[];
  result.recommendationLists satisfies m.RecommendationList[];
});

it(landingPageSuite, 'should allow being called without parameters', async () => {
  const query = new Query({
    clusterUrl: 'http://localhost:60',
    market: 'de',
    locale: 'de-DE',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c60', sessionKey: 's60' })
  });
  await query.landingPage();

  const expectedUrl = new URL('http://localhost:60/api/storefront/v3/queries/landing-page?market=de&customerKey=c60&sessionKey=s60&locale=de-DE&touchpoint=desktop');
  assertSpyCalls(fetchSpy, 1);
  assertSpyCallArgs(fetchSpy, 0, [expectedUrl, { method: 'GET' }]);
});

it(landingPageSuite, 'should pass on correct endpoint, facets, params, and body parameters to Request', async () => {
  const query = new Query({
    clusterUrl: 'http://localhost:61',
    market: 'de2',
    locale: 'de-DE2',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c61', sessionKey: 's61' })
  });
  const params = Object.freeze({
    sort: 'RELEVANCE' as const,
    limit: 11,
    facets: {
      color: ['steelblue'],
      size: ['XL']
    }
  });
  const body = Object.freeze({ primaryList: { include: true } });
  await query.landingPage(params, body);

  const expectedUrl = new URL('http://localhost:61/api/storefront/v3/queries/landing-page?market=de2&customerKey=c61&sessionKey=s61&locale=de-DE2&touchpoint=desktop&sort=RELEVANCE&limit=11&f.color=steelblue&f.size=XL');
  const expectedBody = '{"primaryList":{"include":true}}';
  assertSpyCalls(fetchSpy, 1);
  assertSpyCallArgs(fetchSpy, 0, [
    expectedUrl,
    { method: 'POST', body: expectedBody, headers: { 'Content-Type': 'text/plain' } }
  ]);
});

it(landingPageSuite, 'should allow all API parameters and body options (kitchen sink)', async() => {
  const sort: 'RELEVANCE' | 'NEWEST_FIRST' | 'PRICE_ASCENDING' | 'PRICE_DESCENDING' | 'DISCOUNT' | 'RATING' = 'RELEVANCE';
  const query = new Query({
    clusterUrl: 'http://localhost:62',
    market: 'de3',
    locale: 'de-DE3',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c62', sessionKey: 's62' })
  });
  const result = await query.landingPage({
    sort,
    limit: 20,
    skip: 10,
    q: 'red dress',
    notify: false,
    pageReference: '/women/jackets',
    includeNavigation: true,
    viewId: 'production',
    priceId: 'default',
    channels: 'ONLINE',
    stores: 'se|de|no',
    templateId: 'list-template',
    presentCustom: ['cut'],
    presentPrices: ['foo', 'bar'],
    facets: {
      color: ['firebrick'],
      brand: ['nike', 'adidas'],
      price: { min: 10, max: 500 },
      coolFactor: { min: 9001 },
      length: { max: 180 }
    }
  }, {
    navigation: { include: true },
    primaryList: {
      include: true,
      productFilter: {
        brand: 'Nike',
        color: ['RED', 'GREEN'],
        price: { min: 10, max: 100 }
      },
      productRules: 'rule incl newness 10d '
    },
    recommendationLists: [
      { id: 'peronsal', label: 'For you', algorithm: 'PERSONAL', limit: 8, visualization: 'CAROUSEL' }
    ],
    contentLists: [
      { id: 'blogs', limit: 3, algorithm: 'NEWEST_CONTENT', contentFilter: { type: 'blog' } }
    ]
  });

  result satisfies m.LandingPage;
  result.primaryList satisfies m.PrimaryList | undefined;
  result.recommendationLists satisfies m.RecommendationList[];
  result.contentLists satisfies m.ContentList[];
  result.navigation satisfies m.Navigation | undefined;
  result.seo satisfies m.SearchEngineOptimization;
});

it(sponsoredPageSuite, 'should allow being called without parameters', async () => {
  const query = new Query({
    clusterUrl: 'http://localhost:82',
    market: 'fr',
    locale: 'fr-EN',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c82', sessionKey: 's82' })
  });
  await query.sponsoredPage({ pageReference: '/' });

  const expectedUrl = new URL('http://localhost:82/api/storefront/v3/queries/sponsored-page?market=fr&customerKey=c82&sessionKey=s82&locale=fr-EN&touchpoint=desktop&pageReference=%2F');
  assertSpyCalls(fetchSpy, 1);
  assertSpyCallArgs(fetchSpy, 0, [expectedUrl, { method: 'GET' }]);
});

// it(sponsoredPageSuite, 'should pass on correct endpoint, facets, params, and body parameters to Request', async () => {
//   const query = new Query({
//     clusterUrl: 'http://localhost:83',
//     market: 'fr2',
//     locale: 'fr-EN2',
//     touchpoint: 'desktop',
//     session: () => ({ customerKey: 'c83', sessionKey: 's83' })
//   });
//   const params = Object.freeze({
//     sort: 'RELEVANCE' as const,
//     limit: 11,
//     facets: {
//       color: ['steelblue'],
//       size: ['XL']
//     }
//   });
//   const body = Object.freeze({ primaryList: { include: true } });
//   await query.sponsoredPage(params, body);

//   const expectedUrl = new URL('http://localhost:61/api/storefront/v3/queries/landing-page?market=de2&customerKey=c61&sessionKey=s61&locale=de-DE2&touchpoint=desktop&sort=RELEVANCE&limit=11&f.color=steelblue&f.size=XL');
//   const expectedBody = '{"primaryList":{"include":true}}';
//   assertSpyCalls(fetchSpy, 1);
//   assertSpyCallArgs(fetchSpy, 0, [
//     expectedUrl,
//     { method: 'POST', body: expectedBody, headers: { 'Content-Type': 'text/plain' } }
//   ]);
// });

it(sponsoredPageSuite, 'should allow all API parameters and body options (kitchen sink)', async () => {
  const query = new Query({
    clusterUrl: 'http://localhost:84',
    market: 'fr3',
    locale: 'fr-EN3',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c84', sessionKey: 's84' })
  });
  const result = await query.sponsoredPage({
    notify: false,
    pageReference: '/women/jackets/sponsored',
    viewId: 'production',
    templateId: 'sponsored-template'
  });

  result satisfies m.SponsoredPage;
  result.sponsoredLists satisfies m.SponsoredList[];
});

it(contentInformationSuite, 'should pass on correct endpoint, and params, parameters to Request', async () => {
  const query = new Query({
    clusterUrl: 'http://localhost:70',
    market: 'fr',
    locale: 'fr-FR',
    touchpoint: 'mobile',
    session: () => ({ customerKey: 'c70', sessionKey: 's70' })
  });
  const params = Object.freeze({ contentKeys: ['ck1234', 'ck9876'] });
  await query.contentInformation(params);

  const expectedUrl = new URL('http://localhost:70/api/storefront/v3/queries/content-information?market=fr&customerKey=c70&sessionKey=s70&locale=fr-FR&touchpoint=mobile&contentKeys=ck1234%7Cck9876');
  assertSpyCalls(fetchSpy, 1);
  assertSpyCallArgs(fetchSpy, 0, [
    expectedUrl,
    { method: 'GET' }
  ]);
});

it(contentInformationSuite, 'should allow all API parameters and body options (kitchen sink)', async () => {
  const query = new Query({
    clusterUrl: 'http://localhost:71',
    market: 'fr2',
    locale: 'fr-FR2',
    touchpoint: 'mobile',
    session: () => ({ customerKey: 'c71', sessionKey: 's71' })
  });
  const result = await query.contentInformation({
    contentKeys: ['ck123456', 'ck234567'],
    notify: false,
    viewId: 'production'
  });

  result satisfies m.ContentInformation;
  result.items satisfies m.ContentItem[];
});

it(contentSearchPageSuite, 'should pass on correct endpoint, facets, params, and body parameters to Request', async() => {
  const query = new Query({
    clusterUrl: 'http://localhost:80',
    market: 'es',
    locale: 'es-ES',
    touchpoint: 'desktop',
    session: () => ({ customerKey: 'c80', sessionKey: 's80' })
  });
  const params = Object.freeze({
    q: 'sizeguide',
    limit: 11
  });
  const body = Object.freeze({ primaryList: { contentFilter: { type: 'article' } } });
  await query.contentSearchPage(params, body);

  const expectedUrl = new URL('http://localhost:80/api/storefront/v3/queries/content-search-page?market=es&customerKey=c80&sessionKey=s80&locale=es-ES&touchpoint=desktop&q=sizeguide&limit=11');
  const expectedBody = '{"primaryList":{"contentFilter":{"type":"article"}}}';
  assertSpyCalls(fetchSpy, 1);
  assertSpyCallArgs(fetchSpy, 0, [
    expectedUrl,
    { method: 'POST', body: expectedBody, headers: { 'Content-Type': 'text/plain' } }
  ]);
});

it(contentSearchPageSuite, 'should allow all API parameters and body options (kitchen sink)', async() => {
  const query = new Query({
    clusterUrl: 'http://localhost:81',
    market: 'es2',
    locale: 'es-ES2',
    touchpoint: 'mobile',
    session: () => ({ customerKey: 'c81', sessionKey: 's81' })
  });
  const result = await query.contentSearchPage({
    q: 'faq',
    sort: 'RELEVANCE',
    origin: 'UNDO_AUTO_CORRECT',
    skip: 10,
    limit: 30,
    notify: false,
    viewId: 'preview'
  }, {
    primaryList: {
      contentFilter: {
        type: 'article',
        content_key: ['ck123', 'ck234', 'ck345'],
        'custom.foo': 'bar'
      }
    }
  });

  result satisfies m.ContentSearchPage;
  result.q satisfies string;
  result.primaryList satisfies m.PrimaryContentList;
  result.didYouMean satisfies m.DidYouMean[];
  result.autoCorrect satisfies m.AutoCorrect | undefined;
});
