import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
import 'package:image/image.dart' as img; // CR-005: 画像圧縮・リサイズ用

/// 画像圧縮サービス
/// Gemini APIのトークン消費を削減するため、画像を最適化します
class ImageCompressionService {
  /// 最大画像サイズ(長辺): 1024px
  /// Geminiは高解像度でなくても十分な認識精度があります
  static const int maxDimension = 1024;

  /// JPEG品質: 85% (品質と容量のバランス)
  static const int jpegQuality = 85;

  /// 画像を圧縮してGemini API用に最適化
  ///
  /// [sourcePath] 元画像のパス
  /// [targetPath] 圧縮後の保存先パス(nullの場合は自動生成)
  ///
  /// 戻り値: 圧縮後の画像パス
  static Future<String> compressForGemini(String sourcePath, {String? targetPath}) async {
    try {
      final File sourceFile = File(sourcePath);
      if (!await sourceFile.exists()) {
        throw Exception('Source image not found: $sourcePath');
      }

      // CR-005: 画像をデコード（image packageを使用）
      final Uint8List imageBytes = await sourceFile.readAsBytes();
      final img.Image? originalImage = img.decodeImage(imageBytes);
      
      if (originalImage == null) {
        debugPrint('Failed to decode image, returning original');
        return sourcePath;
      }

      final int originalWidth = originalImage.width;
      final int originalHeight = originalImage.height;

      // リサイズが不要な場合は、圧縮のみ実施
      if (originalWidth <= maxDimension && originalHeight <= maxDimension) {
        debugPrint('Image dimensions OK: ${originalWidth}x$originalHeight, applying JPEG compression');
        
        // 保存先パス決定
        final String outputPath = targetPath ?? await _generateCompressedPath(sourcePath);
        
        // JPEG圧縮のみ適用
        final compressedBytes = img.encodeJpg(originalImage, quality: jpegQuality);
        await File(outputPath).writeAsBytes(compressedBytes);
        
        final originalSize = imageBytes.length;
        final compressedSize = compressedBytes.length;
        
        debugPrint('Compression result: ${(originalSize / 1024).toStringAsFixed(1)}KB -> ${(compressedSize / 1024).toStringAsFixed(1)}KB');
        
        return outputPath;
      }

      // CR-005: リサイズが必要な場合
      debugPrint('Resizing image: ${originalWidth}x$originalHeight -> max $maxDimension');

      // アスペクト比を保ったままリサイズ
      final img.Image resized = img.copyResize(
        originalImage,
        width: originalWidth > originalHeight ? maxDimension : null,
        height: originalHeight > originalWidth ? maxDimension : null,
        interpolation: img.Interpolation.linear, // 高品質な補間
      );

      // 保存先パス決定
      final String outputPath = targetPath ?? await _generateCompressedPath(sourcePath);

      // JPEG形式で保存
      final compressedBytes = img.encodeJpg(resized, quality: jpegQuality);
      await File(outputPath).writeAsBytes(compressedBytes);

      final originalSize = imageBytes.length;
      final compressedSize = compressedBytes.length;

      debugPrint('Resize & Compression result: ${originalWidth}x$originalHeight (${(originalSize / 1024).toStringAsFixed(1)}KB) -> ${resized.width}x${resized.height} (${(compressedSize / 1024).toStringAsFixed(1)}KB)');

      return outputPath;

    } catch (e) {
      debugPrint('Image compression error: $e');
      // エラー時は元のパスを返す(フォールバック)
      return sourcePath;
    }
  }

  /// 圧縮画像の保存先パスを生成（一時ディレクトリ）
  /// 
  /// 🔒 一時ファイルは getTemporaryDirectory() に保存
  static Future<String> _generateCompressedPath(String sourcePath) async {
    final directory = await getTemporaryDirectory();
    final fileName = path.basenameWithoutExtension(sourcePath);
    final extension = path.extension(sourcePath);
    return path.join(directory.path, '${fileName}_compressed$extension');
  }

  /// ファイルサイズを取得(デバッグ用)
  static Future<int> getFileSize(String filePath) async {
    final file = File(filePath);
    return await file.length();
  }

  /// ファイルサイズを人間が読みやすい形式で取得
  static Future<String> getFileSizeString(String filePath) async {
    final size = await getFileSize(filePath);
    if (size < 1024) {
      return '$size B';
    } else if (size < 1024 * 1024) {
      return '${(size / 1024).toStringAsFixed(1)} KB';
    } else {
      return '${(size / (1024 * 1024)).toStringAsFixed(1)} MB';
    }
  }

  /// ギャラリー保存用に画像を圧縮（高品質版）
  ///
  /// [sourcePath] 元画像のパス
  /// [targetPath] 圧縮後の保存先パス(nullの場合は自動生成)
  /// [maxDimension] 最大画像サイズ(デフォルト: 2000px)
  /// [quality] JPEG品質(デフォルト: 90%)
  ///
  /// 戻り値: 圧縮後の画像パス
  static Future<String> compressForGallery(
    String sourcePath, {
    String? targetPath,
    int maxDimension = 2000,
    int quality = 90,
  }) async {
    try {
      final File sourceFile = File(sourcePath);
      if (!await sourceFile.exists()) {
        throw Exception('Source image not found: $sourcePath');
      }

      final Uint8List imageBytes = await sourceFile.readAsBytes();
      final img.Image? originalImage = img.decodeImage(imageBytes);
      
      if (originalImage == null) {
        debugPrint('Failed to decode image, returning original');
        return sourcePath;
      }

      final int originalWidth = originalImage.width;
      final int originalHeight = originalImage.height;

      // リサイズが不要な場合は、圧縮のみ実施
      if (originalWidth <= maxDimension && originalHeight <= maxDimension) {
        debugPrint('Gallery: Image dimensions OK: ${originalWidth}x$originalHeight, applying JPEG compression');
        
        final String outputPath = targetPath ?? await _generateCompressedPath(sourcePath);
        final compressedBytes = img.encodeJpg(originalImage, quality: quality);
        await File(outputPath).writeAsBytes(compressedBytes);
        
        final originalSize = imageBytes.length;
        final compressedSize = compressedBytes.length;
        
        debugPrint('Gallery compression: ${(originalSize / 1024).toStringAsFixed(1)}KB -> ${(compressedSize / 1024).toStringAsFixed(1)}KB');
        
        return outputPath;
      }

      // リサイズが必要な場合
      debugPrint('Gallery: Resizing image: ${originalWidth}x$originalHeight -> max $maxDimension');

      final img.Image resized = img.copyResize(
        originalImage,
        width: originalWidth > originalHeight ? maxDimension : null,
        height: originalHeight > originalWidth ? maxDimension : null,
        interpolation: img.Interpolation.cubic, // ギャラリー用は最高品質
      );

      final String outputPath = targetPath ?? await _generateCompressedPath(sourcePath);
      final compressedBytes = img.encodeJpg(resized, quality: quality);
      await File(outputPath).writeAsBytes(compressedBytes);

      final originalSize = imageBytes.length;
      final compressedSize = compressedBytes.length;

      debugPrint('Gallery resize & compression: ${originalWidth}x$originalHeight (${(originalSize / 1024).toStringAsFixed(1)}KB) -> ${resized.width}x${resized.height} (${(compressedSize / 1024).toStringAsFixed(1)}KB)');

      return outputPath;

    } catch (e) {
      debugPrint('Gallery image compression error: $e');
      return sourcePath;
    }
  }
}
