import { randomUUID } from "crypto";
import type { TransformJob, BatchJob, VoiceParameters } from "@shared/schema";

export interface AudioFile {
  id: string;
  originalName: string;
  buffer: Buffer;
  mimeType: string;
  duration: number;
  sampleRate: number;
  channels: number;
  waveformData: number[];
}

export interface IStorage {
  saveAudioFile(file: AudioFile): Promise<void>;
  getAudioFile(id: string): Promise<AudioFile | undefined>;
  deleteAudioFile(id: string): Promise<void>;
  createTransformJob(sourceId: string, targetId: string, intensity?: number): Promise<TransformJob>;
  getTransformJob(id: string): Promise<TransformJob | undefined>;
  updateTransformJob(id: string, updates: Partial<TransformJob>): Promise<TransformJob | undefined>;
  saveResultAudio(jobId: string, buffer: Buffer, waveformData: number[]): Promise<void>;
  getResultAudio(jobId: string): Promise<{ buffer: Buffer; waveformData: number[] } | undefined>;
  createBatchJob(sourceId: string, targetIds: string[], intensity?: number): Promise<BatchJob>;
  getBatchJob(id: string): Promise<BatchJob | undefined>;
  updateBatchJob(id: string, updates: Partial<BatchJob>): Promise<BatchJob | undefined>;
}

export class MemStorage implements IStorage {
  private audioFiles: Map<string, AudioFile>;
  private transformJobs: Map<string, TransformJob>;
  private resultAudios: Map<string, { buffer: Buffer; waveformData: number[] }>;
  private batchJobs: Map<string, BatchJob>;

  constructor() {
    this.audioFiles = new Map();
    this.transformJobs = new Map();
    this.resultAudios = new Map();
    this.batchJobs = new Map();
  }

  async saveAudioFile(file: AudioFile): Promise<void> {
    this.audioFiles.set(file.id, file);
  }

  async getAudioFile(id: string): Promise<AudioFile | undefined> {
    return this.audioFiles.get(id);
  }

  async deleteAudioFile(id: string): Promise<void> {
    this.audioFiles.delete(id);
  }

  async createTransformJob(sourceId: string, targetId: string, intensity: number = 100): Promise<TransformJob> {
    const sourceFile = this.audioFiles.get(sourceId);
    const targetFile = this.audioFiles.get(targetId);

    if (!sourceFile || !targetFile) {
      throw new Error("Source or target file not found");
    }

    const job: TransformJob = {
      id: randomUUID(),
      status: "pending",
      progress: 0,
      sourceFileName: sourceFile.originalName,
      targetFileName: targetFile.originalName,
      intensity,
    };

    this.transformJobs.set(job.id, job);
    return job;
  }

  async getTransformJob(id: string): Promise<TransformJob | undefined> {
    return this.transformJobs.get(id);
  }

  async updateTransformJob(id: string, updates: Partial<TransformJob>): Promise<TransformJob | undefined> {
    const job = this.transformJobs.get(id);
    if (!job) return undefined;

    const updatedJob = { ...job, ...updates };
    this.transformJobs.set(id, updatedJob);
    return updatedJob;
  }

  async saveResultAudio(jobId: string, buffer: Buffer, waveformData: number[]): Promise<void> {
    this.resultAudios.set(jobId, { buffer, waveformData });
  }

  async getResultAudio(jobId: string): Promise<{ buffer: Buffer; waveformData: number[] } | undefined> {
    return this.resultAudios.get(jobId);
  }

  async createBatchJob(sourceId: string, targetIds: string[], intensity: number = 100): Promise<BatchJob> {
    const sourceFile = this.audioFiles.get(sourceId);
    if (!sourceFile) {
      throw new Error("Source file not found");
    }

    for (const targetId of targetIds) {
      const targetFile = this.audioFiles.get(targetId);
      if (!targetFile) {
        throw new Error(`Target file ${targetId} not found`);
      }
    }

    const jobIds: string[] = [];
    for (const targetId of targetIds) {
      const job = await this.createTransformJob(sourceId, targetId, intensity);
      jobIds.push(job.id);
    }

    const batchJob: BatchJob = {
      id: randomUUID(),
      status: "pending",
      sourceFileName: sourceFile.originalName,
      totalJobs: targetIds.length,
      completedJobs: 0,
      failedJobs: 0,
      jobIds,
      intensity,
      createdAt: Date.now(),
    };

    this.batchJobs.set(batchJob.id, batchJob);
    return batchJob;
  }

  async getBatchJob(id: string): Promise<BatchJob | undefined> {
    return this.batchJobs.get(id);
  }

  async updateBatchJob(id: string, updates: Partial<BatchJob>): Promise<BatchJob | undefined> {
    const batchJob = this.batchJobs.get(id);
    if (!batchJob) return undefined;

    const updatedBatchJob = { ...batchJob, ...updates };
    this.batchJobs.set(id, updatedBatchJob);
    return updatedBatchJob;
  }
}

export const storage = new MemStorage();
