import { Injectable, inject } from '@angular/core';
import { Store } from '@ngrx/store';
import { getUserScopedStorageKey } from '../../../../core/storage/current-user-storage';
import { ElectronBridgeService } from '../../../../core/platform/electron/electron-bridge.service';
import { selectCurrentRoomId } from '../../../../store/rooms/rooms.selectors';

const STORAGE_PREFIX_PLUGIN_LOCAL = 'metoyou_plugin_local';
const STORAGE_PREFIX_PLUGIN_SERVER_LOCAL = 'metoyou_plugin_server_local';

type PluginDataScope = 'local' | 'server';

@Injectable({ providedIn: 'root' })
export class PluginStorageService {
  private readonly electronBridge = inject(ElectronBridgeService);
  private readonly store = inject(Store);
  private readonly currentRoomId = this.store.selectSignal(selectCurrentRoomId);

  getLocal(pluginId: string, key: string): unknown {
    return this.read(`${STORAGE_PREFIX_PLUGIN_LOCAL}:${pluginId}:${key}`);
  }

  removeLocal(pluginId: string, key: string): void {
    localStorage.removeItem(getUserScopedStorageKey(`${STORAGE_PREFIX_PLUGIN_LOCAL}:${pluginId}:${key}`));
    void this.deleteFromClientDatabase(pluginId, 'local', key);
  }

  setLocal(pluginId: string, key: string, value: unknown): void {
    this.write(`${STORAGE_PREFIX_PLUGIN_LOCAL}:${pluginId}:${key}`, value);
    void this.writeToClientDatabase(pluginId, 'local', key, value);
  }

  async readClientData(pluginId: string, key: string): Promise<unknown> {
    return await this.readScopedData(pluginId, 'local', key);
  }

  async removeClientData(pluginId: string, key: string): Promise<void> {
    localStorage.removeItem(getUserScopedStorageKey(`${STORAGE_PREFIX_PLUGIN_LOCAL}:${pluginId}:${key}`));
    await this.deleteFromClientDatabase(pluginId, 'local', key);
  }

  async writeClientData(pluginId: string, key: string, value: unknown): Promise<void> {
    this.write(`${STORAGE_PREFIX_PLUGIN_LOCAL}:${pluginId}:${key}`, value);
    await this.writeToClientDatabase(pluginId, 'local', key, value);
  }

  async readServerData(pluginId: string, key: string): Promise<unknown> {
    return await this.readScopedData(pluginId, 'server', key, this.requireRoomId());
  }

  async removeServerData(pluginId: string, key: string): Promise<void> {
    localStorage.removeItem(getUserScopedStorageKey(this.serverLocalKey(pluginId, key)));
    await this.deleteFromClientDatabase(pluginId, 'server', key, this.requireRoomId());
  }

  async writeServerData(pluginId: string, key: string, value: unknown): Promise<void> {
    this.write(this.serverLocalKey(pluginId, key), value);
    await this.writeToClientDatabase(pluginId, 'server', key, value, this.requireRoomId());
  }

  private async readScopedData(pluginId: string, scope: PluginDataScope, key: string, serverId?: string): Promise<unknown> {
    const api = this.electronBridge.getApi();

    if (api) {
      return await api.query({
        type: 'get-plugin-data',
        payload: {
          key,
          pluginId,
          scope,
          serverId
        }
      });
    }

    return this.read(scope === 'server'
      ? this.serverLocalKey(pluginId, key)
      : `${STORAGE_PREFIX_PLUGIN_LOCAL}:${pluginId}:${key}`);
  }

  private async writeToClientDatabase(pluginId: string, scope: PluginDataScope, key: string, value: unknown, serverId?: string): Promise<void> {
    const api = this.electronBridge.getApi();

    if (!api) {
      return;
    }

    await api.command({
      type: 'save-plugin-data',
      payload: {
        key,
        pluginId,
        scope,
        serverId,
        value
      }
    });
  }

  private async deleteFromClientDatabase(pluginId: string, scope: PluginDataScope, key: string, serverId?: string): Promise<void> {
    const api = this.electronBridge.getApi();

    if (!api) {
      return;
    }

    await api.command({
      type: 'delete-plugin-data',
      payload: {
        key,
        pluginId,
        scope,
        serverId
      }
    });
  }

  private serverLocalKey(pluginId: string, key: string): string {
    const roomId = this.requireRoomId();

    return `${STORAGE_PREFIX_PLUGIN_SERVER_LOCAL}:${roomId}:${pluginId}:${key}`;
  }

  private requireRoomId(): string {
    const roomId = this.currentRoomId();

    if (!roomId) {
      throw new Error('No active server for plugin server data');
    }

    return roomId;
  }

  private read(key: string): unknown {
    const raw = localStorage.getItem(getUserScopedStorageKey(key));

    if (!raw) {
      return null;
    }

    try {
      return JSON.parse(raw) as unknown;
    } catch {
      return null;
    }
  }

  private write(key: string, value: unknown): void {
    localStorage.setItem(getUserScopedStorageKey(key), JSON.stringify(value));
  }
}
