import { serialize, deserialize } from '../common/serializer';
import { useObjectFileSystem } from './objectfilesystem';
import { useTimeLabelStore } from './datastores/timelabelstore';
import { useResourceStore } from './datastores/resourcestore';
import { useResourceHourStore } from './datastores/resourcehourstore';
import { useEventStore } from './datastores/eventstore';
import { useDataImporterExporter } from './datastores/data-importer-exporter';
import { ApiError, UnexpectedApiError } from './apierror.js';


const objectFileSystem = useObjectFileSystem();

let scopeToStore = null;

async function ensureStoreInitialized() {
  if(!scopeToStore) {
    const timeLabelStore = await useTimeLabelStore(objectFileSystem);
    const resourceStore = await useResourceStore(objectFileSystem);
    const resourceHourStore = await useResourceHourStore(objectFileSystem, resourceStore);
    const eventStore = await useEventStore(
      objectFileSystem, timeLabelStore, resourceStore
    );
    scopeToStore = new Map([
      ['timeLabel', timeLabelStore],
      ['resource', resourceStore],
      ['resourceHour', resourceHourStore],
      ['event', eventStore],
      ['dataImporterExporter', useDataImporterExporter(
        timeLabelStore, resourceStore, resourceHourStore, eventStore
      )],
    ]);
  }
}

self.addEventListener('connect', e => {
  const port = e.ports[0];

  port.addEventListener('message', async e => {
    await ensureStoreInitialized();

    const message = deserialize(e.data);

    if(message.code === 'query') {
      const queryID = message.payload.queryID;
      const store = scopeToStore.get(message.payload.scope);

      let code, payload;
      if(!store) {
        code = 'scope_not_found', payload = message.payload.scope;
      } else {
        try {
          payload = await store.query(message.payload.param);
          code = 'success';
        } catch(e) {
          if(e instanceof ApiError) {
            code = e.code, payload = e.payload;
          } else {
            const err = new UnexpectedApiError(e);
            code = err.code, payload = err.payload;
          }
        }
      }

      port.postMessage({ code: 'query_result', payload: {
        queryID, code, payload: serialize(payload),
      }});
    } else if(message.code === 'mutate') {
      const mutationID = message.payload.mutationID;
      const store = scopeToStore.get(message.payload.scope);

      let code, payload;
      if(!store) {
        code = 'scope_not_found', payload = message.payload.scope;
      } else {
        try {
          payload = await store.mutate(message.payload.ops);
          code = 'success';
        } catch(e) {
          if(!(e instanceof ApiError)) {
            throw e;
          }
          code = e.code;
          payload = e.payload;
        }
      }

      port.postMessage({ code: 'mutate_result', payload: {
        mutationID, code, payload: serialize(payload),
      }});
    }
  });

  port.start();
});
