import { ContextDeleteRecord, IRequestUiMeta, ContextChangeRecord, RequestUiMetaKind, IBulkOperationResult } from "@api-client/core/build/browser.js";
import { ProjectUiCreatedBroadcastEvent, ProjectUiDeletedBroadcastEvent } from "../../../events/BroadcastUiEvents.js";
import { StoreBroadcast } from "../StoreBroadcast.js";
import { ProjectUi } from "../stores/ProjectUi.js";
import { IStoredRequestUi } from "../types.js";
import { IdbStore } from "./IdbStore.js";

export class IdbProjectUi extends IdbStore implements ProjectUi {
  channel = new BroadcastChannel(StoreBroadcast.projectUi);

  async clear(key: string): Promise<ContextDeleteRecord> {
    const tx = this.db.transaction('ProjectUi', 'readwrite');
    const index = tx.store.index('project');
    const items = await index.getAll(key);
    await Promise.all(items.map(item => tx.store.delete([item.meta.project, item.meta.key])));
    items.forEach(item => {
      this.notifyDeleted(item.meta.project, item.meta.key);
    });
    return {
      key,
    }
  }

  async set(pid: string, key: string, meta: IRequestUiMeta): Promise<ContextChangeRecord<IRequestUiMeta>> {
    const value: IStoredRequestUi = {
      data: meta,
      meta: { project: pid, key, },
    };
    await this.db.put('ProjectUi', value);
    const event: ProjectUiCreatedBroadcastEvent = {
      type: 'event',
      operation: 'created',
      kind: RequestUiMetaKind,
      key,
      project: pid,
      data: meta,
      space: '',
      path: '/projects/ui',
    };
    this.channel.postMessage(event);
    return {
      key,
      parent: pid,
      item: meta,
      kind: RequestUiMetaKind,
    };
  }

  async get(pid: string, key: string): Promise<IRequestUiMeta | undefined> {
    const item = await this.db.get('ProjectUi', [pid, key]);
    if (item) {
      return item.data;
    }
    return undefined;
  }

  async getBulk(pid: string, keys: string[]): Promise<IBulkOperationResult<IRequestUiMeta>> {
    const { store } = this.db.transaction('ProjectUi', 'readonly');
    const items = await Promise.all(keys.map(key => store.get([pid, key])));
    const result: (IRequestUiMeta | undefined)[] = items.map((item) => {
      if (item) {
        return item.data;
      }
      return undefined;
    });
    return {
      items: result,
    };
  }

  async delete(pid: string, key: string): Promise<ContextDeleteRecord> {
    await this.db.delete('ProjectUi', [pid, key]);
    this.notifyDeleted(pid, key);
    return {
      key,
      kind: RequestUiMetaKind,
      parent: pid,
    }
  }

  protected notifyDeleted(projectId: string, requestId: string): void {
    const event: ProjectUiDeletedBroadcastEvent = {
      type: 'event',
      operation: 'deleted',
      kind: RequestUiMetaKind,
      key: requestId,
      project: projectId,
      space: '',
      path: '/projects/ui',
    };
    this.channel.postMessage(event);
  }
}
