"use strict";

let vendorGetDbPromise = null;

function openVendorGetDb() {
  if (vendorGetDbPromise) {
    return vendorGetDbPromise;
  }

  vendorGetDbPromise = new Promise((resolve, reject) => {
    const request = indexedDB.open(VENDORGET_DB_NAME, VENDORGET_DB_VERSION);

    request.onerror = () => reject(request.error);

    request.onupgradeneeded = (event) => {
      const db = event.target.result;

      if (!db.objectStoreNames.contains("consent_states")) {
        const consentStates = db.createObjectStore("consent_states", {
          keyPath: "stateFingerprint"
        });

        consentStates.createIndex("pageOrigin", "page.origin", { unique: false });
        consentStates.createIndex("firstSeenAt", "firstSeenAt", { unique: false });
        consentStates.createIndex("lastSeenAt", "lastSeenAt", { unique: false });
      }

      if (!db.objectStoreNames.contains("consent_events")) {
        const consentEvents = db.createObjectStore("consent_events", {
          keyPath: "id",
          autoIncrement: true
        });

        consentEvents.createIndex("stateFingerprint", "stateFingerprint", {
          unique: false
        });

        consentEvents.createIndex("eventType", "eventType", { unique: false });
        consentEvents.createIndex("capturedAt", "capturedAt", { unique: false });
        consentEvents.createIndex("pageOrigin", "page.origin", { unique: false });
      }

      if (!db.objectStoreNames.contains("observed_requests")) {
        const observedRequests = db.createObjectStore("observed_requests", {
          keyPath: "requestFingerprint"
        });

        observedRequests.createIndex("lastSeenAt", "lastSeenAt", {
          unique: false
        });

        observedRequests.createIndex("firstSeenAt", "firstSeenAt", {
          unique: false
        });

        observedRequests.createIndex("requestOrigin", "request.origin", {
          unique: false
        });

        observedRequests.createIndex("requestType", "request.type", {
          unique: false
        });

        observedRequests.createIndex("requestThirdParty", "request.thirdParty", {
          unique: false
        });

        observedRequests.createIndex(
          "correlationStateFingerprint",
          "correlation.stateFingerprint",
          { unique: false }
        );
      }

      ensureGvlStores(db);
    };

    request.onsuccess = () => resolve(request.result);
  });

  return vendorGetDbPromise;
}

async function closeVendorGetDb() {
  if (!vendorGetDbPromise) {
    return;
  }

  try {
    const db = await vendorGetDbPromise;
    db.close();
  } finally {
    vendorGetDbPromise = null;
  }
}

async function deleteVendorGetDatabase() {
  await closeVendorGetDb();

  return new Promise((resolve, reject) => {
    const request = indexedDB.deleteDatabase(VENDORGET_DB_NAME);

    request.onerror = () => reject(request.error);
    request.onblocked = () => reject(new Error("database_delete_blocked"));
    request.onsuccess = () => {
      resolve({
        success: true
      });
    };
  });
}

function ensureGvlStores(db) {
  if (!db.objectStoreNames.contains("gvl_snapshots")) {
    const gvlSnapshots = db.createObjectStore("gvl_snapshots", {
      keyPath: "sha256"
    });

    gvlSnapshots.createIndex("gvlRevision", "gvlRevision", { unique: false });
    gvlSnapshots.createIndex("vendorListVersion", "vendorListVersion", {
      unique: false
    });
    gvlSnapshots.createIndex("fetchedAt", "fetchedAt", { unique: false });
    gvlSnapshots.createIndex("sourceUrl", "sourceUrl", { unique: false });
  }

  if (!db.objectStoreNames.contains("gvl_snapshot_events")) {
    const gvlSnapshotEvents = db.createObjectStore("gvl_snapshot_events", {
      keyPath: "id",
      autoIncrement: true
    });

    gvlSnapshotEvents.createIndex("eventType", "eventType", { unique: false });
    gvlSnapshotEvents.createIndex("capturedAt", "capturedAt", { unique: false });
    gvlSnapshotEvents.createIndex("gvlRevision", "gvlRevision", {
      unique: false
    });
    gvlSnapshotEvents.createIndex("vendorListVersion", "vendorListVersion", {
      unique: false
    });
    gvlSnapshotEvents.createIndex("sha256", "sha256", { unique: false });
    gvlSnapshotEvents.createIndex("sourceUrl", "sourceUrl", { unique: false });
  }

  ensureGvlRelationshipStores(db);
}

function ensureGvlRelationshipStores(db) {
  const gvlRelationshipStoreDefinitions = [
    {
      name: "gvl_vendors",
      indexes: [
        "vendorListVersion",
        "vendorId",
        "name",
        "policyUrl",
        "deletedDate"
      ]
    },
    {
      name: "gvl_purposes",
      indexes: ["vendorListVersion", "purposeId", "name"]
    },
    {
      name: "gvl_special_purposes",
      indexes: ["vendorListVersion", "specialPurposeId", "name"]
    },
    {
      name: "gvl_features",
      indexes: ["vendorListVersion", "featureId", "name"]
    },
    {
      name: "gvl_special_features",
      indexes: ["vendorListVersion", "specialFeatureId", "name"]
    },
    {
      name: "gvl_data_categories",
      indexes: ["vendorListVersion", "dataCategoryId", "name"]
    },
    {
      name: "gvl_vendor_relationships",
      indexes: [
        "vendorListVersion",
        "vendorId",
        "relationshipType",
        "relatedId"
      ]
    }
  ];

  gvlRelationshipStoreDefinitions.forEach((storeDefinition) => {
    if (db.objectStoreNames.contains(storeDefinition.name)) {
      return;
    }

    const objectStore = db.createObjectStore(storeDefinition.name, {
      keyPath: "id"
    });

    storeDefinition.indexes.forEach((indexName) => {
      objectStore.createIndex(indexName, indexName, { unique: false });
    });
  });
}
