import { Injectable, inject } from '@angular/core';
import {
  Message,
  User,
  Room,
  Reaction,
  BanEntry
} from '../../shared-kernel';
import type { ElectronApi } from '../../core/platform/electron/electron-api.models';
import { ElectronBridgeService } from '../../core/platform/electron/electron-bridge.service';

/**
 * Database service for the Electron (desktop) runtime.
 *
 * The SQLite database is managed by TypeORM in the Electron main process.
 * This service is a thin CQRS IPC client that dispatches structured
 * command/query objects through the unified preload channels.
 */
@Injectable({ providedIn: 'root' })
export class ElectronDatabaseService {
  private readonly electronBridge = inject(ElectronBridgeService);

  /** Shorthand accessor for the preload-exposed CQRS API. */
  private get api(): ElectronApi {
    return this.electronBridge.requireApi();
  }

  /**
   * No-op: the database is initialised in the main process before the
   * renderer window opens and requires no explicit bootstrap call here.
   */
  async initialize(): Promise<void> { /* no-op */ }

  /** Persist a single chat message. */
  saveMessage(message: Message): Promise<void> {
    return this.api.command({ type: 'save-message', payload: { message } });
  }

  /**
   * Retrieve messages for a room, sorted oldest-first.
   *
   * @param roomId - Target room.
   * @param limit  - Maximum number of messages to return.
   * @param offset - Number of messages to skip (for pagination).
   */
  getMessages(roomId: string, limit = 100, offset = 0): Promise<Message[]> {
    return this.api.query<Message[]>({ type: 'get-messages', payload: { roomId, limit, offset } });
  }

  getMessagesSince(roomId: string, sinceTimestamp: number): Promise<Message[]> {
    return this.api.query<Message[]>({ type: 'get-messages-since', payload: { roomId, sinceTimestamp } });
  }

  /** Permanently delete a message by ID. */
  deleteMessage(messageId: string): Promise<void> {
    return this.api.command({ type: 'delete-message', payload: { messageId } });
  }

  /** Apply partial updates to an existing message. */
  updateMessage(messageId: string, updates: Partial<Message>): Promise<void> {
    return this.api.command({ type: 'update-message', payload: { messageId, updates } });
  }

  /** Retrieve a single message by ID, or `null` if not found. */
  getMessageById(messageId: string): Promise<Message | null> {
    return this.api.query<Message | null>({ type: 'get-message-by-id', payload: { messageId } });
  }

  /** Remove every message belonging to a room. */
  clearRoomMessages(roomId: string): Promise<void> {
    return this.api.command({ type: 'clear-room-messages', payload: { roomId } });
  }

  /** Persist a reaction (deduplication is handled main-process side). */
  saveReaction(reaction: Reaction): Promise<void> {
    return this.api.command({ type: 'save-reaction', payload: { reaction } });
  }

  /** Remove a specific reaction (user + emoji + message). */
  removeReaction(messageId: string, userId: string, emoji: string): Promise<void> {
    return this.api.command({ type: 'remove-reaction', payload: { messageId, userId, emoji } });
  }

  /** Return all reactions for a given message. */
  getReactionsForMessage(messageId: string): Promise<Reaction[]> {
    return this.api.query<Reaction[]>({ type: 'get-reactions-for-message', payload: { messageId } });
  }

  /** Persist a user record. */
  saveUser(user: User): Promise<void> {
    return this.api.command({ type: 'save-user', payload: { user } });
  }

  /** Retrieve a user by ID, or `null` if not found. */
  getUser(userId: string): Promise<User | null> {
    return this.api.query<User | null>({ type: 'get-user', payload: { userId } });
  }

  /** Retrieve the last-authenticated ("current") user, or `null`. */
  getCurrentUser(): Promise<User | null> {
    return this.api.query<User | null>({ type: 'get-current-user', payload: {} });
  }

  /** Retrieve the persisted current user ID without loading the full user. */
  getCurrentUserId(): Promise<string | null> {
    return this.api.query<string | null>({ type: 'get-current-user-id', payload: {} });
  }

  /** Store which user ID is considered "current" (logged-in). */
  setCurrentUserId(userId: string): Promise<void> {
    return this.api.command({ type: 'set-current-user-id', payload: { userId } });
  }

  /** Retrieve users associated with a room. */
  getUsersByRoom(roomId: string): Promise<User[]> {
    return this.api.query<User[]>({ type: 'get-users-by-room', payload: { roomId } });
  }

  /** Apply partial updates to an existing user. */
  updateUser(userId: string, updates: Partial<User>): Promise<void> {
    return this.api.command({ type: 'update-user', payload: { userId, updates } });
  }

  /** Persist a room record. */
  saveRoom(room: Room): Promise<void> {
    return this.api.command({ type: 'save-room', payload: { room } });
  }

  /** Retrieve a room by ID, or `null` if not found. */
  getRoom(roomId: string): Promise<Room | null> {
    return this.api.query<Room | null>({ type: 'get-room', payload: { roomId } });
  }

  /** Return every persisted room. */
  getAllRooms(): Promise<Room[]> {
    return this.api.query<Room[]>({ type: 'get-all-rooms', payload: {} });
  }

  /** Delete a room by ID (also removes its messages). */
  deleteRoom(roomId: string): Promise<void> {
    return this.api.command({ type: 'delete-room', payload: { roomId } });
  }

  /** Apply partial updates to an existing room. */
  updateRoom(roomId: string, updates: Partial<Room>): Promise<void> {
    return this.api.command({ type: 'update-room', payload: { roomId, updates } });
  }

  /** Persist a ban entry. */
  saveBan(ban: BanEntry): Promise<void> {
    return this.api.command({ type: 'save-ban', payload: { ban } });
  }

  /** Remove a ban by the banned user's `oderId`. */
  removeBan(oderId: string): Promise<void> {
    return this.api.command({ type: 'remove-ban', payload: { oderId } });
  }

  /** Return active bans for a room. */
  getBansForRoom(roomId: string): Promise<BanEntry[]> {
    return this.api.query<BanEntry[]>({ type: 'get-bans-for-room', payload: { roomId } });
  }

  /** Check whether a user is currently banned from a room. */
  isUserBanned(userId: string, roomId: string): Promise<boolean> {
    return this.api.query<boolean>({ type: 'is-user-banned', payload: { userId, roomId } });
  }

  /** Persist attachment metadata. */
  // eslint-disable-next-line
  saveAttachment(attachment: any): Promise<void> {
    return this.api.command({ type: 'save-attachment', payload: { attachment } });
  }

  /** Return all attachment records for a message. */
  // eslint-disable-next-line
  getAttachmentsForMessage(messageId: string): Promise<any[]> {
    // eslint-disable-next-line
    return this.api.query<any[]>({ type: 'get-attachments-for-message', payload: { messageId } });
  }

  /** Return every persisted attachment record. */
  // eslint-disable-next-line
  getAllAttachments(): Promise<any[]> {
    // eslint-disable-next-line
    return this.api.query<any[]>({ type: 'get-all-attachments', payload: {} });
  }

  /** Delete all attachment records for a message. */
  deleteAttachmentsForMessage(messageId: string): Promise<void> {
    return this.api.command({ type: 'delete-attachments-for-message', payload: { messageId } });
  }

  /** Wipe every table, removing all persisted data. */
  clearAllData(): Promise<void> {
    return this.api.command({ type: 'clear-all-data', payload: {} });
  }
}
