/* eslint-disable @typescript-eslint/member-ordering, */
import {
  inject,
  Injectable,
  signal
} from '@angular/core';
import {
  Message,
  User,
  Room,
  Reaction,
  BanEntry
} from '../../shared-kernel';
import type { ChatAttachmentMeta } from '../../shared-kernel';
import { PlatformService } from '../../core/platform';
import { BrowserDatabaseService } from './browser-database.service';
import { ElectronDatabaseService } from './electron-database.service';

/**
 * Facade database service that transparently delegates to the correct
 * storage backend based on the runtime platform.
 *
 * - Electron -> SQLite via {@link ElectronDatabaseService} (IPC to main process).
 * - Browser -> IndexedDB via {@link BrowserDatabaseService}.
 *
 * All consumers inject `DatabaseService`; the underlying storage engine
 * is selected automatically.
 */
@Injectable({ providedIn: 'root' })
export class DatabaseService {
  private readonly platform = inject(PlatformService);
  private readonly browserDb = inject(BrowserDatabaseService);
  private readonly electronDb = inject(ElectronDatabaseService);

  /** Reactive flag: `true` once {@link initialize} has completed. */
  isReady = signal(false);

  /** The active storage backend for the current platform. */
  private get backend() {
    return this.platform.isBrowser ? this.browserDb : this.electronDb;
  }

  /** Initialise the platform-specific database. */
  async initialize(): Promise<void> {
    await this.backend.initialize();
    this.isReady.set(true);
  }

  /** Persist a single chat message. */
  saveMessage(message: Message) { return this.backend.saveMessage(message); }

  /** Retrieve the latest messages for a room or channel with optional pagination.
   *
   * When `beforeTimestamp` is provided, only messages strictly older than that
   * timestamp are returned. This is how scroll-up history loading paginates
   * backwards through the DB without holding the whole history in memory.
   */
  getMessages(
    roomId: string,
    limit = 100,
    offset = 0,
    channelId?: string,
    beforeTimestamp?: number
  ) { return this.backend.getMessages(roomId, limit, offset, channelId, beforeTimestamp); }

  /** Retrieve messages newer than a given timestamp for a room. */
  getMessagesSince(roomId: string, sinceTimestamp: number) { return this.backend.getMessagesSince(roomId, sinceTimestamp); }

  /** Permanently delete a message by ID. */
  deleteMessage(messageId: string) { return this.backend.deleteMessage(messageId); }

  /** Apply partial updates to an existing message. */
  updateMessage(messageId: string, updates: Partial<Message>) { return this.backend.updateMessage(messageId, updates); }

  /** Retrieve a single message by ID. */
  getMessageById(messageId: string) { return this.backend.getMessageById(messageId); }

  /** Remove every message belonging to a room. */
  clearRoomMessages(roomId: string) { return this.backend.clearRoomMessages(roomId); }

  /** Persist a reaction. */
  saveReaction(reaction: Reaction) { return this.backend.saveReaction(reaction); }

  /** Remove a specific reaction (user + emoji + message). */
  removeReaction(messageId: string, userId: string, emoji: string) { return this.backend.removeReaction(messageId, userId, emoji); }

  /** Return all reactions for a given message. */
  getReactionsForMessage(messageId: string) { return this.backend.getReactionsForMessage(messageId); }

  /** Persist a user record. */
  saveUser(user: User) { return this.backend.saveUser(user); }

  /** Retrieve a user by ID. */
  getUser(userId: string) { return this.backend.getUser(userId); }

  /** Retrieve the current (logged-in) user. */
  getCurrentUser() { return this.backend.getCurrentUser(); }

  /** Retrieve the persisted current user ID without loading the full user. */
  getCurrentUserId() { return this.backend.getCurrentUserId(); }

  /** Store the current user ID. */
  setCurrentUserId(userId: string) { return this.backend.setCurrentUserId(userId); }

  /** Retrieve users in a room. */
  getUsersByRoom(roomId: string) { return this.backend.getUsersByRoom(roomId); }

  /** Apply partial updates to an existing user. */
  updateUser(userId: string, updates: Partial<User>) { return this.backend.updateUser(userId, updates); }

  /** Persist a room record. */
  saveRoom(room: Room) { return this.backend.saveRoom(room); }

  /** Retrieve a room by ID. */
  getRoom(roomId: string) { return this.backend.getRoom(roomId); }

  /** Return every persisted room. */
  getAllRooms() { return this.backend.getAllRooms(); }

  /** Delete a room and its associated messages. */
  deleteRoom(roomId: string) { return this.backend.deleteRoom(roomId); }

  /** Apply partial updates to an existing room. */
  updateRoom(roomId: string, updates: Partial<Room>) { return this.backend.updateRoom(roomId, updates); }

  /** Persist a ban entry. */
  saveBan(ban: BanEntry) { return this.backend.saveBan(ban); }

  /** Remove a ban by oderId. */
  removeBan(oderId: string) { return this.backend.removeBan(oderId); }

  /** Return active bans for a room. */
  getBansForRoom(roomId: string) { return this.backend.getBansForRoom(roomId); }

  /** Check whether a user is currently banned from a room. */
  isUserBanned(userId: string, roomId: string) { return this.backend.isUserBanned(userId, roomId); }

  /** Persist attachment metadata. */
  saveAttachment(attachment: ChatAttachmentMeta) { return this.backend.saveAttachment(attachment); }

  /** Return all attachment records for a message. */
  getAttachmentsForMessage(messageId: string) { return this.backend.getAttachmentsForMessage(messageId); }

  /** Return every persisted attachment record. */
  getAllAttachments() { return this.backend.getAllAttachments(); }

  /** Delete all attachment records for a message. */
  deleteAttachmentsForMessage(messageId: string) { return this.backend.deleteAttachmentsForMessage(messageId); }

  /** Wipe all persisted data. */
  clearAllData() { return this.backend.clearAllData(); }
}
