'use strict';

const { Registry } = require('../plugins/registry-base');
const { SourceAdapterBase } = require('./base');
const { assertAdapterSchema } = require('./record-types');

const _registry = new Registry('source-adapter');

function register(entry, opts = {}) {
  const normalized = normalizeEntry(entry);
  return _registry.register(normalized, opts);
}

function normalizeEntry(entry) {
  if (typeof entry === 'function') {
    const instance = new entry();
    return {
      id: instance.schema.adapterId,
      adapterClass: entry,
      schema: instance.schema,
      source: 'class',
    };
  }
  if (entry instanceof SourceAdapterBase) {
    return {
      id: entry.schema.adapterId,
      adapter: entry,
      schema: entry.schema,
      source: 'instance',
    };
  }
  if (entry && typeof entry === 'object') {
    const schema = assertAdapterSchema(entry.schema || entry.manifest || entry);
    return {
      ...entry,
      id: entry.id || schema.adapterId,
      schema,
    };
  }
  throw new Error('source adapter registry entry must be a class, instance, or object');
}

function instantiate(id, opts = {}) {
  const entry = _registry.get(id);
  if (!entry) return null;
  if (entry.adapter) return entry.adapter;
  if (entry.adapterClass) return new entry.adapterClass(opts);
  if (typeof entry.factory === 'function') return entry.factory(opts);
  return null;
}

function get(id) {
  return _registry.get(id) || null;
}

function has(id) {
  return _registry.has(id);
}

function list(filter = {}) {
  let entries = _registry.list();
  if (filter.privacyClass) {
    entries = entries.filter((entry) => entry.schema.defaultPrivacyClass === filter.privacyClass);
  }
  if (filter.incremental != null) {
    entries = entries.filter((entry) => Boolean(entry.schema.supportsIncremental) === Boolean(filter.incremental));
  }
  return entries;
}

function ids(filter = {}) {
  return list(filter).map((entry) => entry.id);
}

function size() {
  return _registry.size();
}

function clear() {
  _registry.clear();
}

module.exports = {
  clear,
  get,
  has,
  ids,
  instantiate,
  list,
  register,
  size,
};
