import { Injectable, signal } from '@angular/core';
import type { Attachment } from '../../domain/models/attachment.model';

@Injectable({ providedIn: 'root' })
export class AttachmentRuntimeStore {
  readonly updated = signal<number>(0);

  private attachmentsByMessage = new Map<string, Attachment[]>();
  private messageRoomIds = new Map<string, string>();
  private originalFiles = new Map<string, File>();
  private cancelledTransfers = new Set<string>();
  private pendingRequests = new Map<string, Set<string>>();
  private chunkBuffers = new Map<string, ArrayBuffer[]>();
  private chunkCounts = new Map<string, number>();

  touch(): void {
    this.updated.set(this.updated() + 1);
  }

  getAttachmentsForMessage(messageId: string): Attachment[] {
    return this.attachmentsByMessage.get(messageId) ?? [];
  }

  setAttachmentsForMessage(messageId: string, attachments: Attachment[]): void {
    if (attachments.length === 0) {
      this.attachmentsByMessage.delete(messageId);
      return;
    }

    this.attachmentsByMessage.set(messageId, attachments);
  }

  hasAttachmentsForMessage(messageId: string): boolean {
    return this.attachmentsByMessage.has(messageId);
  }

  deleteAttachmentsForMessage(messageId: string): void {
    this.attachmentsByMessage.delete(messageId);
  }

  replaceAttachments(nextAttachments: Map<string, Attachment[]>): void {
    this.attachmentsByMessage = nextAttachments;
  }

  getAttachmentEntries(): IterableIterator<[string, Attachment[]]> {
    return this.attachmentsByMessage.entries();
  }

  rememberMessageRoom(messageId: string, roomId: string): void {
    this.messageRoomIds.set(messageId, roomId);
  }

  getMessageRoomId(messageId: string): string | undefined {
    return this.messageRoomIds.get(messageId);
  }

  deleteMessageRoom(messageId: string): void {
    this.messageRoomIds.delete(messageId);
  }

  setOriginalFile(key: string, file: File): void {
    this.originalFiles.set(key, file);
  }

  getOriginalFile(key: string): File | undefined {
    return this.originalFiles.get(key);
  }

  findOriginalFileByFileId(fileId: string): File | null {
    for (const [key, file] of this.originalFiles) {
      if (key.endsWith(`:${fileId}`)) {
        return file;
      }
    }

    return null;
  }

  addCancelledTransfer(key: string): void {
    this.cancelledTransfers.add(key);
  }

  hasCancelledTransfer(key: string): boolean {
    return this.cancelledTransfers.has(key);
  }

  setPendingRequestPeers(key: string, peers: Set<string>): void {
    this.pendingRequests.set(key, peers);
  }

  getPendingRequestPeers(key: string): Set<string> | undefined {
    return this.pendingRequests.get(key);
  }

  hasPendingRequest(key: string): boolean {
    return this.pendingRequests.has(key);
  }

  deletePendingRequest(key: string): void {
    this.pendingRequests.delete(key);
  }

  setChunkBuffer(key: string, buffer: ArrayBuffer[]): void {
    this.chunkBuffers.set(key, buffer);
  }

  getChunkBuffer(key: string): ArrayBuffer[] | undefined {
    return this.chunkBuffers.get(key);
  }

  deleteChunkBuffer(key: string): void {
    this.chunkBuffers.delete(key);
  }

  setChunkCount(key: string, count: number): void {
    this.chunkCounts.set(key, count);
  }

  getChunkCount(key: string): number | undefined {
    return this.chunkCounts.get(key);
  }

  deleteChunkCount(key: string): void {
    this.chunkCounts.delete(key);
  }

  clearMessageScopedState(messageId: string): void {
    const scopedPrefix = `${messageId}:`;

    for (const key of Array.from(this.originalFiles.keys())) {
      if (key.startsWith(scopedPrefix)) {
        this.originalFiles.delete(key);
      }
    }

    for (const key of Array.from(this.pendingRequests.keys())) {
      if (key.startsWith(scopedPrefix)) {
        this.pendingRequests.delete(key);
      }
    }

    for (const key of Array.from(this.chunkBuffers.keys())) {
      if (key.startsWith(scopedPrefix)) {
        this.chunkBuffers.delete(key);
      }
    }

    for (const key of Array.from(this.chunkCounts.keys())) {
      if (key.startsWith(scopedPrefix)) {
        this.chunkCounts.delete(key);
      }
    }

    for (const key of Array.from(this.cancelledTransfers)) {
      if (key.startsWith(scopedPrefix)) {
        this.cancelledTransfers.delete(key);
      }
    }
  }
}
