import sharp from "sharp";
import path from "path";

export interface WatermarkOptions {
  text?: string;
  image?: string; // 워터마크 이미지 경로
  position:
    | "top-left"
    | "top-right"
    | "bottom-left"
    | "bottom-right"
    | "center";
  opacity: number; // 0-1 사이
  fontSize?: number; // 텍스트 워터마크용
  fontColor?: string; // 텍스트 워터마크용
  margin?: number; // 가장자리로부터의 여백 (픽셀)
  scale?: number; // 워터마크 크기 비율 (0-1 사이)
}

export interface WatermarkResult {
  success: boolean;
  outputPath?: string;
  error?: string;
  metadata?: {
    width: number;
    height: number;
    format: string;
    size: number;
  };
}

export class WatermarkService {
  private defaultOptions: Partial<WatermarkOptions> = {
    position: "bottom-right",
    opacity: 0.5,
    fontSize: 24,
    fontColor: "#ffffff",
    margin: 20,
    scale: 0.1,
  };

  /**
   * 이미지에 워터마크 적용
   */
  async applyWatermark(
    inputPath: string,
    outputPath: string,
    options: WatermarkOptions
  ): Promise<WatermarkResult> {
    try {
      const mergedOptions = { ...this.defaultOptions, ...options };

      // 원본 이미지 정보 가져오기
      const imageInfo = await sharp(inputPath).metadata();
      if (!imageInfo.width || !imageInfo.height) {
        throw new Error("이미지 크기 정보를 가져올 수 없습니다.");
      }

      let pipeline = sharp(inputPath);

      if (mergedOptions.text) {
        // 텍스트 워터마크 적용
        pipeline = await this.applyTextWatermark(
          pipeline,
          mergedOptions.text,
          imageInfo.width,
          imageInfo.height,
          mergedOptions
        );
      } else if (mergedOptions.image) {
        // 이미지 워터마크 적용
        pipeline = await this.applyImageWatermark(
          pipeline,
          mergedOptions.image,
          imageInfo.width,
          imageInfo.height,
          mergedOptions
        );
      } else {
        throw new Error("텍스트 또는 이미지 워터마크가 필요합니다.");
      }

      // 결과 저장
      await pipeline.jpeg({ quality: 90 }).toFile(outputPath);

      // 결과 메타데이터 가져오기
      const outputInfo = await sharp(outputPath).metadata();

      return {
        success: true,
        outputPath,
        metadata: {
          width: outputInfo.width || 0,
          height: outputInfo.height || 0,
          format: outputInfo.format || "unknown",
          size: outputInfo.size || 0,
        },
      };
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : "워터마크 적용 실패",
      };
    }
  }

  /**
   * 텍스트 워터마크 적용
   */
  private async applyTextWatermark(
    pipeline: sharp.Sharp,
    text: string,
    imageWidth: number,
    imageHeight: number,
    options: WatermarkOptions
  ): Promise<sharp.Sharp> {
    const fontSize = options.fontSize || this.defaultOptions.fontSize || 24;
    const fontColor =
      options.fontColor || this.defaultOptions.fontColor || "#ffffff";
    const margin = options.margin || this.defaultOptions.margin || 20;
    const opacity = Math.round((options.opacity || 0.5) * 255);

    // SVG로 텍스트 워터마크 생성
    const textSvg = this.createTextSvg(text, fontSize, fontColor, opacity);
    const textBuffer = Buffer.from(textSvg);

    // 텍스트 이미지 생성
    const textImage = await sharp(textBuffer).png().toBuffer();
    const textInfo = await sharp(textImage).metadata();

    if (!textInfo.width || !textInfo.height) {
      throw new Error("텍스트 워터마크 크기 정보를 가져올 수 없습니다.");
    }

    // 위치 계산
    const position = this.calculatePosition(
      imageWidth,
      imageHeight,
      textInfo.width,
      textInfo.height,
      options.position,
      margin
    );

    // 워터마크 합성
    return pipeline.composite([
      {
        input: textImage,
        top: position.top,
        left: position.left,
        blend: "over",
      },
    ]);
  }

  /**
   * 이미지 워터마크 적용
   */
  private async applyImageWatermark(
    pipeline: sharp.Sharp,
    watermarkPath: string,
    imageWidth: number,
    imageHeight: number,
    options: WatermarkOptions
  ): Promise<sharp.Sharp> {
    const margin = options.margin || this.defaultOptions.margin || 20;
    const scale = options.scale || this.defaultOptions.scale || 0.1;
    const opacity = options.opacity || 0.5;

    // 워터마크 이미지 크기 조정
    const watermarkSize = Math.min(imageWidth, imageHeight) * scale;

    const watermarkImage = await sharp(watermarkPath)
      .resize({
        width: Math.round(watermarkSize),
        height: Math.round(watermarkSize),
        fit: "inside",
        withoutEnlargement: true,
      })
      .png()
      .toBuffer();

    // 투명도 적용
    const watermarkWithOpacity = await sharp(watermarkImage)
      .composite([
        {
          input: {
            create: {
              width: Math.round(watermarkSize),
              height: Math.round(watermarkSize),
              channels: 4,
              background: { r: 255, g: 255, b: 255, alpha: opacity },
            },
          },
          blend: "dest-in",
        },
      ])
      .png()
      .toBuffer();

    const watermarkInfo = await sharp(watermarkWithOpacity).metadata();

    if (!watermarkInfo.width || !watermarkInfo.height) {
      throw new Error("워터마크 이미지 크기 정보를 가져올 수 없습니다.");
    }

    // 위치 계산
    const position = this.calculatePosition(
      imageWidth,
      imageHeight,
      watermarkInfo.width,
      watermarkInfo.height,
      options.position,
      margin
    );

    // 워터마크 합성
    return pipeline.composite([
      {
        input: watermarkWithOpacity,
        top: position.top,
        left: position.left,
        blend: "over",
      },
    ]);
  }

  /**
   * 텍스트 SVG 생성
   */
  private createTextSvg(
    text: string,
    fontSize: number,
    fontColor: string,
    opacity: number
  ): string {
    const textWidth = text.length * fontSize * 0.6; // 대략적인 텍스트 너비
    const textHeight = fontSize * 1.2;

    return `
      <svg width="${textWidth}" height="${textHeight}" xmlns="http://www.w3.org/2000/svg">
        <text 
          x="0" 
          y="${fontSize}" 
          font-family="Arial, sans-serif" 
          font-size="${fontSize}" 
          fill="${fontColor}" 
          fill-opacity="${opacity / 255}"
          font-weight="bold"
        >${text}</text>
      </svg>
    `;
  }

  /**
   * 워터마크 위치 계산
   */
  private calculatePosition(
    imageWidth: number,
    imageHeight: number,
    watermarkWidth: number,
    watermarkHeight: number,
    position: WatermarkOptions["position"],
    margin: number
  ): { top: number; left: number } {
    switch (position) {
      case "top-left":
        return { top: margin, left: margin };
      case "top-right":
        return { top: margin, left: imageWidth - watermarkWidth - margin };
      case "bottom-left":
        return { top: imageHeight - watermarkHeight - margin, left: margin };
      case "bottom-right":
        return {
          top: imageHeight - watermarkHeight - margin,
          left: imageWidth - watermarkWidth - margin,
        };
      case "center":
        return {
          top: Math.round((imageHeight - watermarkHeight) / 2),
          left: Math.round((imageWidth - watermarkWidth) / 2),
        };
      default:
        return { top: margin, left: margin };
    }
  }

  /**
   * 배치 워터마킹
   */
  async applyWatermarkBatch(
    inputPaths: string[],
    outputDir: string,
    options: WatermarkOptions,
    onProgress?: (completed: number, total: number, currentFile: string) => void
  ): Promise<{
    successful: string[];
    failed: Array<{ path: string; error: string }>;
  }> {
    const successful: string[] = [];
    const failed: Array<{ path: string; error: string }> = [];

    for (let i = 0; i < inputPaths.length; i++) {
      const inputPath = inputPaths[i];
      const fileName = path.basename(inputPath, path.extname(inputPath));
      const outputPath = path.join(outputDir, `${fileName}_watermarked.jpg`);

      if (onProgress) {
        onProgress(i, inputPaths.length, inputPath);
      }

      const result = await this.applyWatermark(inputPath, outputPath, options);

      if (result.success) {
        successful.push(outputPath);
      } else {
        failed.push({
          path: inputPath,
          error: result.error || "Unknown error",
        });
      }
    }

    if (onProgress) {
      onProgress(inputPaths.length, inputPaths.length, "완료");
    }

    return { successful, failed };
  }

  /**
   * 워터마크 제거 (원본 복원)
   */
  async removeWatermark(
    watermarkedPath: string,
    originalPath: string
  ): Promise<boolean> {
    try {
      // 실제로는 원본 파일을 복사하거나 데이터베이스에서 원본 경로를 찾아 복원
      // 여기서는 간단히 파일 복사로 구현
      await sharp(originalPath).toFile(watermarkedPath);
      return true;
    } catch {
      return false;
    }
  }

  /**
   * 워터마크 설정 검증
   */
  validateOptions(options: WatermarkOptions): {
    valid: boolean;
    errors: string[];
  } {
    const errors: string[] = [];

    if (!options.text && !options.image) {
      errors.push("텍스트 또는 이미지 워터마크가 필요합니다.");
    }

    if (options.opacity < 0 || options.opacity > 1) {
      errors.push("투명도는 0과 1 사이의 값이어야 합니다.");
    }

    if (options.fontSize && options.fontSize < 1) {
      errors.push("폰트 크기는 1보다 커야 합니다.");
    }

    if (options.scale && (options.scale < 0 || options.scale > 1)) {
      errors.push("크기 비율은 0과 1 사이의 값이어야 합니다.");
    }

    if (options.margin && options.margin < 0) {
      errors.push("여백은 0보다 커야 합니다.");
    }

    return {
      valid: errors.length === 0,
      errors,
    };
  }
}

// 싱글톤 인스턴스
let watermarkServiceInstance: WatermarkService | null = null;

export function getWatermarkService(): WatermarkService {
  if (!watermarkServiceInstance) {
    watermarkServiceInstance = new WatermarkService();
  }
  return watermarkServiceInstance;
}

// 편의 함수들
export async function addTextWatermark(
  inputPath: string,
  outputPath: string,
  text: string,
  options?: Partial<WatermarkOptions>
): Promise<WatermarkResult> {
  const service = getWatermarkService();
  return service.applyWatermark(inputPath, outputPath, {
    text,
    position: "bottom-right",
    opacity: 0.5,
    ...options,
  });
}

export async function addImageWatermark(
  inputPath: string,
  outputPath: string,
  watermarkImagePath: string,
  options?: Partial<WatermarkOptions>
): Promise<WatermarkResult> {
  const service = getWatermarkService();
  return service.applyWatermark(inputPath, outputPath, {
    image: watermarkImagePath,
    position: "bottom-right",
    opacity: 0.5,
    scale: 0.1,
    ...options,
  });
}
