/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Tests MDN quick suggest results.

"use strict";

const REMOTE_SETTINGS_DATA = [
  {
    type: "mdn-suggestions",
    attachment: [
      {
        url: "https://example.com/array-filter",
        title: "Array.prototype.filter()",
        description:
          "The filter() method creates a shallow copy of a portion of a given array, filtered down to just the elements from the given array that pass the test implemented by the provided function.",
        keywords: ["array filter", "fil", "filte", "filter"],
        score: 0.24,
      },
      {
        url: "https://example.com/input",
        title: "<input>: The Input (Form Input) element",
        description:
          "The <input> HTML element is used to create interactive controls for web-based forms in order to accept data from the user; a wide variety of types of input data and control widgets are available, depending on the device and user agent. The <input> element is one of the most powerful and complex in all of HTML due to the sheer number of combinations of input types and attributes.",
        keywords: ["input"],
        score: 0.24,
      },
      {
        url: "https://example.com/grid",
        title: "CSS Grid Layout",
        description:
          "CSS Grid Layout excels at dividing a page into major regions or defining the relationship in terms of size, position, and layer, between parts of a control built from HTML primitives.",
        keywords: ["grid"],
        score: 0.24,
      },
    ],
  },
];

add_setup(async function init() {
  // Disable search suggestions so we don't hit the network.
  Services.prefs.setBoolPref("browser.search.suggest.enabled", false);

  await QuickSuggestTestUtils.ensureQuickSuggestInit({
    remoteSettingsRecords: REMOTE_SETTINGS_DATA,
    prefs: [
      ["suggest.quicksuggest.all", true],
      ["suggest.quicksuggest.sponsored", false],
    ],
  });
});

add_task(async function basic() {
  for (const suggestion of REMOTE_SETTINGS_DATA[0].attachment) {
    const fullKeyword = suggestion.keywords[0];
    const firstWord = fullKeyword.split(" ")[0];
    for (let i = 1; i < fullKeyword.length; i++) {
      const keyword = fullKeyword.substring(0, i);
      const shouldMatch = i >= firstWord.length;
      const matches = shouldMatch
        ? [QuickSuggestTestUtils.mdnResult(suggestion)]
        : [];
      await check_results({
        context: createContext(keyword, {
          providers: [UrlbarProviderQuickSuggest.name],
          isPrivate: false,
        }),
        matches,
      });
    }

    await check_results({
      context: createContext(fullKeyword + " ", {
        providers: [UrlbarProviderQuickSuggest.name],
        isPrivate: false,
      }),
      matches: !fullKeyword.includes(" ")
        ? [QuickSuggestTestUtils.mdnResult(suggestion)]
        : [],
    });
  }
});

// Check wheather the MDN suggestions will be hidden by the pref.
add_task(async function disableByLocalPref() {
  const suggestion = REMOTE_SETTINGS_DATA[0].attachment[0];
  const keyword = suggestion.keywords[0];

  const prefs = [
    "suggest.mdn",
    "mdn.featureGate",
    "quicksuggest.enabled",
    "suggest.quicksuggest.all",
  ];

  for (const pref of prefs) {
    // First make sure the suggestion is added.
    await check_results({
      context: createContext(keyword, {
        providers: [UrlbarProviderQuickSuggest.name],
        isPrivate: false,
      }),
      matches: [QuickSuggestTestUtils.mdnResult(suggestion)],
    });

    // Now disable them.
    UrlbarPrefs.set(pref, false);
    await check_results({
      context: createContext(keyword, {
        providers: [UrlbarProviderQuickSuggest.name],
        isPrivate: false,
      }),
      matches: [],
    });

    // Revert.
    UrlbarPrefs.set(pref, true);
    await QuickSuggestTestUtils.forceSync();
  }
});

// Check wheather the MDN suggestions will be shown by the setup of Nimbus
// variable.
add_task(async function nimbus() {
  const defaultPrefs = Services.prefs.getDefaultBranch("browser.urlbar.");

  const suggestion = REMOTE_SETTINGS_DATA[0].attachment[0];
  const keyword = suggestion.keywords[0];

  // Disable the fature gate.
  defaultPrefs.setBoolPref("mdn.featureGate", false);
  await check_results({
    context: createContext(keyword, {
      providers: [UrlbarProviderQuickSuggest.name],
      isPrivate: false,
    }),
    matches: [],
  });

  // Enable by Nimbus.
  const cleanUpNimbusEnable = await UrlbarTestUtils.initNimbusFeature(
    { mdnFeatureGate: true },
    "urlbar",
    "config"
  );
  await QuickSuggestTestUtils.forceSync();
  await check_results({
    context: createContext(keyword, {
      providers: [UrlbarProviderQuickSuggest.name],
      isPrivate: false,
    }),
    matches: [QuickSuggestTestUtils.mdnResult(suggestion)],
  });
  await cleanUpNimbusEnable();

  // Enable locally.
  defaultPrefs.setBoolPref("mdn.featureGate", true);
  await QuickSuggestTestUtils.forceSync();

  // Disable by Nimbus.
  const cleanUpNimbusDisable = await UrlbarTestUtils.initNimbusFeature(
    { mdnFeatureGate: false },
    "urlbar",
    "config"
  );
  await check_results({
    context: createContext(keyword, {
      providers: [UrlbarProviderQuickSuggest.name],
      isPrivate: false,
    }),
    matches: [],
  });
  await cleanUpNimbusDisable();

  // Revert.
  defaultPrefs.setBoolPref("mdn.featureGate", true);
  await QuickSuggestTestUtils.forceSync();
});

add_task(async function mixedCaseQuery() {
  const suggestion = REMOTE_SETTINGS_DATA[0].attachment[1];
  const keyword = "InPuT";

  await check_results({
    context: createContext(keyword, {
      providers: [UrlbarProviderQuickSuggest.name],
      isPrivate: false,
    }),
    matches: [QuickSuggestTestUtils.mdnResult(suggestion)],
  });
});

// Tests the "Dismiss" command: a dismissed suggestion shouldn't be added.
add_task(async function dismiss() {
  await doDismissOneTest({
    result: QuickSuggestTestUtils.mdnResult(
      REMOTE_SETTINGS_DATA[0].attachment[0]
    ),
    command: "dismiss",
    feature: QuickSuggest.getFeature("MDNSuggestions"),
    queriesForDismissals: [
      {
        query: REMOTE_SETTINGS_DATA[0].attachment[0].keywords[0],
      },
    ],
    queriesForOthers: [
      {
        query: REMOTE_SETTINGS_DATA[0].attachment[1].keywords[0],
        expectedResults: [
          QuickSuggestTestUtils.mdnResult(
            REMOTE_SETTINGS_DATA[0].attachment[1]
          ),
        ],
      },
    ],
  });
});

// Tests the "Not interested" command: all MDN suggestions should be disabled
// and not added anymore.
add_task(async function notInterested() {
  await doDismissAllTest({
    result: QuickSuggestTestUtils.mdnResult(
      REMOTE_SETTINGS_DATA[0].attachment[0]
    ),
    command: "not_interested",
    feature: QuickSuggest.getFeature("MDNSuggestions"),
    pref: "suggest.mdn",
    queries: [
      {
        query: REMOTE_SETTINGS_DATA[0].attachment[0].keywords[0],
      },
      {
        query: REMOTE_SETTINGS_DATA[0].attachment[1].keywords[0],
        expectedResults: [
          QuickSuggestTestUtils.mdnResult(
            REMOTE_SETTINGS_DATA[0].attachment[1]
          ),
        ],
      },
    ],
  });
});

add_task(async function show_less_frequently() {
  UrlbarPrefs.set("mdn.showLessFrequentlyCount", 0);
  UrlbarPrefs.set("mdn.minKeywordLength", 0);
  UrlbarPrefs.set("mdn.showLessFrequentlyCap", 3);

  let result = QuickSuggestTestUtils.mdnResult(
    REMOTE_SETTINGS_DATA[0].attachment[0]
  );
  const testData = [
    {
      input: "fil",
      before: {
        canShowLessFrequently: true,
        showLessFrequentlyCount: 0,
        minKeywordLength: 0,
      },
      after: {
        canShowLessFrequently: true,
        showLessFrequentlyCount: 1,
        minKeywordLength: 4,
      },
    },
    {
      input: "filte",
      before: {
        canShowLessFrequently: true,
        showLessFrequentlyCount: 1,
        minKeywordLength: 4,
      },
      after: {
        canShowLessFrequently: true,
        showLessFrequentlyCount: 2,
        minKeywordLength: 6,
      },
    },
    {
      input: "filter",
      before: {
        canShowLessFrequently: true,
        showLessFrequentlyCount: 2,
        minKeywordLength: 6,
      },
      after: {
        canShowLessFrequently: false,
        showLessFrequentlyCount: 3,
        minKeywordLength: 7,
      },
    },
  ];

  for (let { input, before, after } of testData) {
    let feature = QuickSuggest.getFeature("MDNSuggestions");

    await check_results({
      context: createContext(input, {
        providers: [UrlbarProviderQuickSuggest.name],
        isPrivate: false,
      }),
      matches: [result],
    });

    Assert.equal(
      UrlbarPrefs.get("mdn.minKeywordLength"),
      before.minKeywordLength
    );
    Assert.equal(feature.canShowLessFrequently, before.canShowLessFrequently);
    Assert.equal(
      feature.showLessFrequentlyCount,
      before.showLessFrequentlyCount
    );

    triggerCommand({
      result,
      feature,
      command: "show_less_frequently",
      searchString: input,
    });

    Assert.equal(
      UrlbarPrefs.get("mdn.minKeywordLength"),
      after.minKeywordLength
    );
    Assert.equal(feature.canShowLessFrequently, after.canShowLessFrequently);
    Assert.equal(
      feature.showLessFrequentlyCount,
      after.showLessFrequentlyCount
    );

    await check_results({
      context: createContext(input, {
        providers: [UrlbarProviderQuickSuggest.name],
        isPrivate: false,
      }),
      matches: [],
    });
  }

  UrlbarPrefs.clear("mdn.showLessFrequentlyCount");
  UrlbarPrefs.clear("mdn.minKeywordLength");
  UrlbarPrefs.clear("mdn.showLessFrequentlyCap");
});
