import {
  imageProcessor,
  ImageProcessingOptions,
  ProcessingResult,
} from "./image-processor";

// 작업 상태
export type JobStatus = "pending" | "processing" | "completed" | "failed";

// 이미지 처리 작업
export interface ImageProcessingJob {
  id: string;
  uploadId: string;
  inputPath: string;
  fileName: string;
  options: ImageProcessingOptions;
  status: JobStatus;
  progress: number;
  error?: string;
  result?: ProcessingResult;
  createdAt: Date;
  startedAt?: Date;
  completedAt?: Date;
}

// 작업 큐 관리
class ImageProcessingQueue {
  private jobs: Map<string, ImageProcessingJob> = new Map();
  private processing: Set<string> = new Set();
  private maxConcurrentJobs: number = 3;

  /**
   * 새 처리 작업 추가
   */
  addJob(
    uploadId: string,
    inputPath: string,
    fileName: string,
    options: ImageProcessingOptions = {}
  ): string {
    const jobId = `job_${Date.now()}_${Math.random()
      .toString(36)
      .substring(2)}`;

    const job: ImageProcessingJob = {
      id: jobId,
      uploadId,
      inputPath,
      fileName,
      options: {
        generateWebP: true,
        generateAVIF: false,
        stripMetadata: true,
        progressive: true,
        optimize: true,
        ...options,
      },
      status: "pending",
      progress: 0,
      createdAt: new Date(),
    };

    this.jobs.set(jobId, job);

    // 즉시 처리 시작 (비동기)
    this.processNextJob();

    return jobId;
  }

  /**
   * 작업 상태 조회
   */
  getJob(jobId: string): ImageProcessingJob | undefined {
    return this.jobs.get(jobId);
  }

  /**
   * 업로드 ID로 작업 조회
   */
  getJobByUploadId(uploadId: string): ImageProcessingJob | undefined {
    for (const job of this.jobs.values()) {
      if (job.uploadId === uploadId) {
        return job;
      }
    }
    return undefined;
  }

  /**
   * 대기 중인 작업 목록
   */
  getPendingJobs(): ImageProcessingJob[] {
    return Array.from(this.jobs.values())
      .filter((job) => job.status === "pending")
      .sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
  }

  /**
   * 다음 작업 처리
   */
  private async processNextJob() {
    // 동시 처리 한도 확인
    if (this.processing.size >= this.maxConcurrentJobs) {
      return;
    }

    const pendingJobs = this.getPendingJobs();
    if (pendingJobs.length === 0) {
      return;
    }

    const job = pendingJobs[0];
    await this.processJob(job);
  }

  /**
   * 개별 작업 처리
   */
  private async processJob(job: ImageProcessingJob) {
    if (this.processing.has(job.id)) {
      return;
    }

    this.processing.add(job.id);

    try {
      // 작업 상태 업데이트
      job.status = "processing";
      job.progress = 10;
      job.startedAt = new Date();

      console.log(`Starting image processing for job ${job.id}`);

      // 이미지 처리 실행
      const result = await imageProcessor.processImage(
        job.inputPath,
        job.fileName,
        job.options
      );

      // 작업 완료
      job.status = "completed";
      job.progress = 100;
      job.result = result;
      job.completedAt = new Date();

      console.log(`Completed image processing for job ${job.id}`);

      // TODO: 데이터베이스에 처리 결과 저장
      await this.saveProcessingResult(job);
    } catch (error) {
      console.error(`Failed to process image for job ${job.id}:`, error);

      job.status = "failed";
      job.error = error instanceof Error ? error.message : "Unknown error";
      job.completedAt = new Date();
    } finally {
      this.processing.delete(job.id);

      // 다음 작업 시작
      setTimeout(() => this.processNextJob(), 100);
    }
  }

  /**
   * 처리 결과를 데이터베이스에 저장
   */
  private async saveProcessingResult(job: ImageProcessingJob) {
    if (!job.result) return;

    // TODO: 실제 Prisma 연결 시 구현
    console.log(`Saving processing result for upload ${job.uploadId}`);

    // Mock implementation
    const mockPrisma = {
      upload: {
        update: async (data: {
          where: { id: string };
          data: {
            status: string;
            isProcessed: boolean;
            optimizedUrl?: string;
            thumbnailUrl?: string;
            webpUrl?: string;
            width: number;
            height: number;
            aspectRatio: number;
          };
        }) => {
          console.log("Updated upload with processing results:", data);
          return { id: job.uploadId };
        },
      },
      mediaProcessingJob: {
        update: async (data: {
          where: { id: string };
          data: {
            status: string;
            progress: number;
            result: string;
            completedAt?: Date;
          };
        }) => {
          console.log("Updated processing job:", data);
          return { id: job.id };
        },
      },
    };

    try {
      // Upload 테이블 업데이트
      await mockPrisma.upload.update({
        where: { id: job.uploadId },
        data: {
          status: "completed",
          isProcessed: true,
          optimizedUrl: job.result.processed[0]?.url,
          thumbnailUrl: job.result.processed.find((p) => p.size === "thumbnail")
            ?.url,
          webpUrl: job.result.webp?.[0]?.url,
          width: job.result.original.width,
          height: job.result.original.height,
          aspectRatio: job.result.original.width / job.result.original.height,
        },
      });

      // 처리 작업 상태 업데이트
      await mockPrisma.mediaProcessingJob.update({
        where: { id: job.id },
        data: {
          status: "completed",
          progress: 100,
          result: JSON.stringify(job.result),
          completedAt: job.completedAt,
        },
      });
    } catch (error) {
      console.error("Failed to save processing result:", error);
    }
  }

  /**
   * 작업 취소
   */
  cancelJob(jobId: string): boolean {
    const job = this.jobs.get(jobId);
    if (!job || job.status !== "pending") {
      return false;
    }

    job.status = "failed";
    job.error = "Cancelled by user";
    job.completedAt = new Date();

    return true;
  }

  /**
   * 완료된 작업 정리
   */
  cleanup(maxAge: number = 24 * 60 * 60 * 1000) {
    // 24시간
    const cutoff = new Date(Date.now() - maxAge);

    for (const [jobId, job] of this.jobs) {
      if (job.completedAt && job.completedAt < cutoff) {
        this.jobs.delete(jobId);
      }
    }
  }

  /**
   * 큐 통계
   */
  getStats() {
    const jobs = Array.from(this.jobs.values());

    return {
      total: jobs.length,
      pending: jobs.filter((j) => j.status === "pending").length,
      processing: jobs.filter((j) => j.status === "processing").length,
      completed: jobs.filter((j) => j.status === "completed").length,
      failed: jobs.filter((j) => j.status === "failed").length,
      concurrentJobs: this.processing.size,
      maxConcurrentJobs: this.maxConcurrentJobs,
    };
  }
}

// 글로벌 이미지 처리 큐
export const imageProcessingQueue = new ImageProcessingQueue();

// API 헬퍼 함수들
export async function queueImageProcessing(
  uploadId: string,
  inputPath: string,
  fileName: string,
  options?: ImageProcessingOptions
): Promise<string> {
  return imageProcessingQueue.addJob(uploadId, inputPath, fileName, options);
}

export function getProcessingStatus(
  jobId: string
): ImageProcessingJob | undefined {
  return imageProcessingQueue.getJob(jobId);
}

export function getProcessingStatusByUpload(
  uploadId: string
): ImageProcessingJob | undefined {
  return imageProcessingQueue.getJobByUploadId(uploadId);
}

export function cancelProcessing(jobId: string): boolean {
  return imageProcessingQueue.cancelJob(jobId);
}

export function getQueueStats() {
  return imageProcessingQueue.getStats();
}

// 주기적인 정리 작업 (1시간마다)
if (typeof setInterval !== "undefined") {
  setInterval(() => {
    imageProcessingQueue.cleanup();
  }, 60 * 60 * 1000);
}
