/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

const { PlacesQuery } = ChromeUtils.importESModule(
  "resource://gre/modules/PlacesQuery.sys.mjs"
);

const HISTORY_FILE_PATH = "Library/Safari/History.db";
const HISTORY_STRANGE_ENTRIES_FILE_PATH =
  "Library/Safari/HistoryStrangeEntries.db";

// By default, our migrators will cut off migrating any history older than
// 180 days. In order to make sure this test continues to run correctly
// in the future, we copy the reference database to History.db, and then
// use Sqlite.sys.mjs to connect to it and manually update all of the visit
// times to be "now", so that they all fall within the 180 day window. The
// Nov 10th date below is right around when the reference database visit
// entries were created.
//
// This update occurs in `updateVisitTimes`.
const MS_SINCE_SNAPSHOT_TIME =
  new Date() - new Date("Nov 10, 2022 00:00:00 UTC");

async function setupHistoryFile() {
  removeHistoryFile();
  let file = do_get_file(HISTORY_STRANGE_ENTRIES_FILE_PATH);
  file.copyTo(file.parent, "History.db");
  await updateVisitTimes();
}

function removeHistoryFile() {
  let file = do_get_file(HISTORY_FILE_PATH, true);
  try {
    file.remove(false);
  } catch (ex) {
    // It is ok if this doesn't exist.
    if (ex.result != Cr.NS_ERROR_FILE_NOT_FOUND) {
      throw ex;
    }
  }
}

add_setup(async function setup() {
  registerFakePath("ULibDir", do_get_file("Library/"));
  await setupHistoryFile();
  registerCleanupFunction(async () => {
    await PlacesUtils.history.clear();
    removeHistoryFile();
  });
});

async function updateVisitTimes() {
  let cocoaSnapshotDelta = MS_SINCE_SNAPSHOT_TIME / 1000;
  let historyFile = do_get_file(HISTORY_FILE_PATH);
  let dbConn = await Sqlite.openConnection({ path: historyFile.path });

  await dbConn.execute(
    "UPDATE history_visits SET visit_time = visit_time + :cocoaSnapshotDelta;",
    {
      cocoaSnapshotDelta,
    }
  );

  await dbConn.close();
}

/**
 * Tests that we can import successfully from Safari when Safari's history
 * database contains malformed URLs.
 */
add_task(async function testHistoryImportStrangeEntries() {
  await PlacesUtils.history.clear();

  let placesQuery = new PlacesQuery();
  let emptyHistory = await placesQuery.getHistory({ daysOld: Infinity });
  Assert.equal(emptyHistory.size, 0, "Empty history should indeed be empty.");

  const EXPECTED_MIGRATED_SITES = 10;
  const EXPECTED_MIGRATED_VISTS = 23;

  let historyFile = do_get_file(HISTORY_FILE_PATH);
  let dbConn = await Sqlite.openConnection({ path: historyFile.path });
  let [rowCountResult] = await dbConn.execute(
    "SELECT COUNT(*) FROM history_visits"
  );
  Assert.greater(
    rowCountResult.getResultByName("COUNT(*)"),
    EXPECTED_MIGRATED_VISTS,
    "There are more total rows than valid rows"
  );
  await dbConn.close();

  let migrator = await MigrationUtils.getMigrator("safari");
  await promiseMigration(migrator, MigrationUtils.resourceTypes.HISTORY);
  let migratedHistory = await placesQuery.getHistory({
    daysOld: Infinity,
    sortBy: "site",
  });
  let siteCount = migratedHistory.size;
  let visitCount = 0;
  for (let [, visits] of migratedHistory) {
    visitCount += visits.length;
  }
  Assert.equal(
    siteCount,
    EXPECTED_MIGRATED_SITES,
    "Should have migrated all valid history sites"
  );
  Assert.equal(
    visitCount,
    EXPECTED_MIGRATED_VISTS,
    "Should have migrated all valid history visits"
  );

  placesQuery.close();
});
