import { Injectable, inject } from '@angular/core';
import { ElectronBridgeService } from '../../../../core/platform/electron/electron-bridge.service';
import type { Attachment } from '../../domain/models/attachment.model';
import {
  resolveAttachmentStorageBucket,
  resolveAttachmentStoredFilename,
  sanitizeAttachmentRoomName
} from '../util/attachment-storage.util';

@Injectable({ providedIn: 'root' })
export class AttachmentStorageService {
  private readonly electronBridge = inject(ElectronBridgeService);

  async resolveExistingPath(
    attachment: Pick<Attachment, 'filePath' | 'savedPath'>
  ): Promise<string | null> {
    return this.findExistingPath([attachment.filePath, attachment.savedPath]);
  }

  async resolveLegacyImagePath(filename: string, roomName: string): Promise<string | null> {
    const appDataPath = await this.resolveAppDataPath();

    if (!appDataPath) {
      return null;
    }

    return this.findExistingPath([`${appDataPath}/server/${sanitizeAttachmentRoomName(roomName)}/image/${filename}`]);
  }

  async readFile(filePath: string): Promise<string | null> {
    const electronApi = this.electronBridge.getApi();

    if (!electronApi || !filePath) {
      return null;
    }

    try {
      return await electronApi.readFile(filePath);
    } catch {
      return null;
    }
  }

  async saveBlob(
    attachment: Pick<Attachment, 'id' | 'filename' | 'mime'>,
    blob: Blob,
    roomName: string
  ): Promise<string | null> {
    const electronApi = this.electronBridge.getApi();
    const appDataPath = await this.resolveAppDataPath();

    if (!electronApi || !appDataPath) {
      return null;
    }

    try {
      const directoryPath = `${appDataPath}/server/${sanitizeAttachmentRoomName(roomName)}/${resolveAttachmentStorageBucket(attachment.mime)}`;

      await electronApi.ensureDir(directoryPath);

      const arrayBuffer = await blob.arrayBuffer();
      const diskPath = `${directoryPath}/${resolveAttachmentStoredFilename(attachment.id, attachment.filename)}`;

      await electronApi.writeFile(diskPath, this.arrayBufferToBase64(arrayBuffer));

      return diskPath;
    } catch {
      return null;
    }
  }

  async deleteFile(filePath: string): Promise<void> {
    const electronApi = this.electronBridge.getApi();

    if (!electronApi || !filePath) {
      return;
    }

    try {
      await electronApi.deleteFile(filePath);
    } catch { /* best-effort cleanup */ }
  }

  private async resolveAppDataPath(): Promise<string | null> {
    const electronApi = this.electronBridge.getApi();

    if (!electronApi) {
      return null;
    }

    try {
      return await electronApi.getAppDataPath();
    } catch {
      return null;
    }
  }

  private async findExistingPath(candidates: (string | null | undefined)[]): Promise<string | null> {
    const electronApi = this.electronBridge.getApi();

    if (!electronApi) {
      return null;
    }

    for (const candidatePath of candidates) {
      if (!candidatePath) {
        continue;
      }

      try {
        if (await electronApi.fileExists(candidatePath)) {
          return candidatePath;
        }
      } catch { /* keep trying remaining candidates */ }
    }

    return null;
  }

  private arrayBufferToBase64(buffer: ArrayBuffer): string {
    let binary = '';

    const bytes = new Uint8Array(buffer);

    for (let index = 0; index < bytes.byteLength; index++) {
      binary += String.fromCharCode(bytes[index]);
    }

    return btoa(binary);
  }
}
