import 'dart:io';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/foundation.dart';
import 'device_service.dart';
import 'package:google_generative_ai/google_generative_ai.dart';
import '../secrets.dart';
import 'analysis_cache_service.dart';


class GeminiService {
  // AI Proxy Server Configuration
  static final String _proxyUrl = Secrets.aiProxyAnalyzeUrl;
  
  // レート制限対策? Proxy側で管理されているが、念のためクライアント側でも連打防止
  static DateTime? _lastApiCallTime;
  static const Duration _minApiInterval = Duration(seconds: 2); 

  GeminiService();

  /// 画像リストから日本酒ラベルを解析
  Future<SakeAnalysisResult> analyzeSakeLabel(List<String> imagePaths, {bool forceRefresh = false}) async {
    // クライアント側プロンプトでスキーマの一貫性を保証
    const prompt = '''
あなたは日本酒の専門家（ソムリエ）です。
添付の画像（日本酒のラベル）を分析し、以下のJSON形式で情報を抽出してください。

{
  "name": "銘柄名",
  "brand": "蔵元名",
  "prefecture": "都道府県名",
  "type": "特定名称（純米大吟醸など）",
  "description": "味や特徴の魅力的な説明文(100文字程度)",
  "catchCopy": "短いキャッチコピー(20文字以内)",
  "confidenceScore": 80,
  "flavorTags": ["フルーティー", "辛口", "華やか"],
  "tasteStats": {"aroma":3,"sweetness":3,"acidity":3,"bitterness":3,"body":3},
  "alcoholContent": 15.0,
  "polishingRatio": 50,
  "sakeMeterValue": 3.0,
  "riceVariety": "山田錦",
  "yeast": "きょうかい9号",
  "manufacturingYearMonth": "2023.10"
}

値が不明な場合は null または 適切な推測値を入れてください。特にtasteStatsは必ず1-5の数値で埋めてください。
''';

    return _callProxyApi(
      imagePaths: imagePaths,
      customPrompt: prompt, // Override server default
      forceRefresh: forceRefresh,
    );
  }

  /// OCRテキストと画像のハイブリッド解析
  Future<SakeAnalysisResult> analyzeSakeHybrid(String extractedText, List<String> imagePaths) async {
    final prompt = '''
あなたは日本酒の専門家（ソムリエ）です。

以下のOCR抽出テキストは参考情報です（誤字・脱落あり）。
OCRテキストはあくまで補助的なヒントとして扱い、添付の画像を優先して全項目を必ず埋めてください。

OCRテキスト（参考のみ）:
"""
$extractedText
"""

添付の日本酒ラベル画像を分析し、以下のJSON形式で情報を抽出してください。

{
  "name": "銘柄名",
  "brand": "蔵元名",
  "prefecture": "都道府県名",
  "type": "特定名称（純米大吟醸など）",
  "description": "味や特徴の魅力的な説明文(100文字程度)",
  "catchCopy": "短いキャッチコピー(20文字以内)",
  "confidenceScore": 80,
  "flavorTags": ["フルーティー", "辛口", "華やか"],
  "tasteStats": {"aroma":3,"sweetness":3,"acidity":3,"bitterness":3,"body":3},
  "alcoholContent": 15.0,
  "polishingRatio": 50,
  "sakeMeterValue": 3.0,
  "riceVariety": "山田錦",
  "yeast": "きょうかい9号",
  "manufacturingYearMonth": "2023.10"
}

★重要な指示:
- tasteStats（香り、甘味、酸味、苦味、ボディ）は必ず1-5の整数で埋めてください。不明な場合は3を設定してください。
- alcoholContent, polishingRatio, sakeMeterValue などの詳細項目も、画像から読み取れる場合は必ず設定してください。
- 値が不明な場合は null または 適切な推測値を入れてください。
''';

    return _callProxyApi(imagePaths: imagePaths, customPrompt: prompt);
  }

  /// テキストのみの解析 (画像なし)
  Future<SakeAnalysisResult> analyzeSakeText(String extractedText) async {
    final prompt = '''
以下のOCRで抽出された日本酒ラベルのテキスト情報を分析してください。
誤字やノイズが含まれることが多いですが、文脈から積極的に正しい情報を推測・補完してください。

抽出テキスト:
"""
$extractedText
"""

以下の情報をJSON形式で返してください：
{
  "name": "銘柄名",
  "brand": "蔵元名",
  "prefecture": "都道府県名",
  "type": "特定名称",
  "description": "特徴(100文字)",
  "catchCopy": "キャッチコピー(20文字)",
  "confidenceScore": 0-100,
  "flavorTags": ["タグ"],
  "tasteStats": {"aroma":3,"sweetness":3,"acidity":3,"bitterness":3,"body":3},
  "alcoholContent": 15.5,
  "polishingRatio": 50,
  "sakeMeterValue": 3.0,
  "riceVariety": "山田錦",
  "yeast": "きょうかい9号",
  "manufacturingYearMonth": "2023.10"
}
''';

    return _callProxyApi(imagePaths: [], customPrompt: prompt);
  }

  /// 共通実装: ProxyへのAPIコール
  Future<SakeAnalysisResult> _callProxyApi({
    required List<String> imagePaths,
    String? customPrompt,
    bool forceRefresh = false,
  }) async {
    // Check Mode: Direct vs Proxy
    if (!Secrets.useProxy) {
       debugPrint('🚀 Direct Cloud Mode: Connecting to Gemini API directly...');
       return _callDirectApi(imagePaths, customPrompt, forceRefresh: forceRefresh);
    }

    try {
      // 1. レート制限 (クライアント側連打防止)
      if (_lastApiCallTime != null) {
        final elapsed = DateTime.now().difference(_lastApiCallTime!);
        if (elapsed < _minApiInterval) {
           await Future.delayed(_minApiInterval - elapsed);
        }
      }
      _lastApiCallTime = DateTime.now();

      // 2. 画像をBase64変換（撮影時に圧縮済み）
      List<String> base64Images = [];
      for (final path in imagePaths) {
        // Read already-compressed images directly (compressed at capture time)
        final bytes = await File(path).readAsBytes();
        final base64String = base64Encode(bytes);
        base64Images.add(base64String);
        debugPrint('Encoded processed image: ${(bytes.length / 1024).toStringAsFixed(1)}KB');
      }

      // 3. デバイスID取得
      final deviceId = await DeviceService.getDeviceId();
      debugPrint('Device ID: $deviceId');

      // 4. リクエスト作成
      final requestBody = jsonEncode({
        "device_id": deviceId,
        "images": base64Images,
        "prompt": customPrompt,
      });

      debugPrint('Calling Proxy: $_proxyUrl');

      // 5. 送信（Bearer Token認証付き）
      final headers = {
        "Content-Type": "application/json",
        if (Secrets.proxyAuthToken.isNotEmpty)
          "Authorization": "Bearer ${Secrets.proxyAuthToken}",
      };
      final response = await http.post(
        Uri.parse(_proxyUrl),
        headers: headers,
        body: requestBody,
      ).timeout(const Duration(seconds: 60)); // 拡張: 60秒 (画像サイズ最適化済み)

      // 6. レスポンス処理
      if (response.statusCode == 200) {
        // 成功時のレスポンス形式: { "success": true, "data": {...}, "usage": {...} }
        final jsonResponse = jsonDecode(utf8.decode(response.bodyBytes));
        
        if (jsonResponse['success'] == true) {
           final data = jsonResponse['data'];
           if (data == null) throw Exception("サーバーからのデータが空です");
           
           // 使用状況ログ
           if (jsonResponse['usage'] != null) {
             final usage = jsonResponse['usage'];
             debugPrint('API Usage: ${usage['today']}/${usage['limit']}');
           }

           final result = SakeAnalysisResult.fromJson(data);

           // スキーマ準拠チェック
           if (result.tasteStats.isEmpty || 
               result.tasteStats.values.every((v) => v == 0)) {
              debugPrint('⚠️ WARNING: AI returned empty or zero taste stats. This item will not form a valid chart.');
           } else {
             // Simple check
             final requiredKeys = ['aroma', 'sweetness', 'acidity', 'bitterness', 'body'];
             final actualKeys = result.tasteStats.keys.toList();
             final missing = requiredKeys.where((k) => !actualKeys.contains(k)).toList();
             
             if (missing.isNotEmpty) {
                debugPrint('⚠️ WARNING: AI response missing keys: $missing. Old schema?');
                // We could throw here, but for now let's just log.
                // In strict mode, we might want to fail the analysis to force retry.
             }
           }

           return result;
        } else {
          // Proxy側での論理エラー (レート制限超過など)
          throw Exception(jsonResponse['error'] ?? '不明なエラーが発生しました');
        }
      } else {
        // HTTPエラー
        debugPrint('Proxy Error: ${response.statusCode} ${response.body}');
        throw Exception('サーバーエラー (${response.statusCode}): ${response.body}');
      }

    } catch (e) {
      debugPrint('Proxy Call Failed: $e');
      // エラーメッセージを整形
      final errorMsg = e.toString().toLowerCase();
      if (errorMsg.contains('limit') || errorMsg.contains('上限')) {
         throw Exception('本日のAI解析リクエスト上限に達しました。\n明日またお試しください。');
      }
      rethrow;
    }
  }

  /// Direct Cloud API Implementation (No Proxy)
  Future<SakeAnalysisResult> _callDirectApi(List<String> imagePaths, String? customPrompt, {bool forceRefresh = false}) async {
    // 1. キャッシュチェック（同じ画像なら即座に返す）
    // forceRefresh=trueの場合はキャッシュをスキップ
    if (!forceRefresh && imagePaths.isNotEmpty) {
      final imageHash = await AnalysisCacheService.computeCombinedHash(imagePaths);
      final cached = await AnalysisCacheService.getCached(imageHash);
      if (cached != null) {
        debugPrint('💰 API呼び出しをスキップ（キャッシュヒット）');
        return cached;
      }
    }

    // 2. API Key確認
    final apiKey = Secrets.geminiApiKey;
    if (apiKey.isEmpty) {
      throw Exception('Gemini API Key is missing. Please set GEMINI_API_KEY.');
    }

    final model = GenerativeModel(
      model: 'gemini-2.5-flash', // ⚠️ FIXED MODEL NAME - DO NOT CHANGE without explicit user approval (confirmed working on 2026-01-17)
      apiKey: apiKey,
      generationConfig: GenerationConfig(
        responseMimeType: 'application/json',
        temperature: 0.2, // チャート一貫性向上のため 0.4→0.2 に変更 (2026-02-09)
      ),
    );

    // Prepare Prompt
    final promptText = customPrompt ?? '''
あなたは日本酒の専門家（ソムリエ）です。
添付の画像（日本酒のラベル）を分析し、以下のJSON形式で情報を抽出してください。

{
  "name": "銘柄名",
  "brand": "蔵元名",
  "prefecture": "都道府県名",
  "type": "特定名称（純米大吟醸など）",
  "description": "味や特徴の魅力的な説明文(100文字程度)",
  "catchCopy": "短いキャッチコピー(20文字以内)",
  "confidenceScore": 80,
  "flavorTags": ["フルーティー", "辛口", "華やか"],
  "tasteStats": {"aroma":3,"sweetness":3,"acidity":3,"bitterness":3,"body":3},
  "alcoholContent": 15.0,
  "polishingRatio": 50,
  "sakeMeterValue": 3.0,
  "riceVariety": "山田錦",
  "yeast": "きょうかい9号",
  "manufacturingYearMonth": "2023.10"
}

値が不明な場合は null または 適切な推測値を入れてください。
''';

    // Prepare Content
    final contentParts = <Part>[TextPart(promptText)];
    for (var path in imagePaths) {
      // 撮影時に圧縮済み
      final bytes = await File(path).readAsBytes();
      contentParts.add(DataPart('image/jpeg', bytes));
    }

    try {
      final response = await model.generateContent([Content.multi(contentParts)]);

      final jsonString = response.text;
      if (jsonString == null) throw Exception('Empty response from Gemini');

      final jsonMap = jsonDecode(jsonString);
      final result = SakeAnalysisResult.fromJson(jsonMap);

      // 3. キャッシュに保存（次回は即座に返せる）
      if (imagePaths.isNotEmpty) {
        final imageHash = await AnalysisCacheService.computeCombinedHash(imagePaths);
        await AnalysisCacheService.saveCache(imageHash, result);
        // 4. 銘柄名インデックスに登録（v1.0.15: チャート一貫性向上）
        await AnalysisCacheService.registerBrandIndex(result.name, imageHash);
      }

      return result;

    } catch (e) {
      debugPrint('Direct API Error: $e');
      throw Exception('AI解析エラー(Direct): $e');
    }
  }
}

// Analysis Result Model
class SakeAnalysisResult {
  final String? name;
  final String? brand;
  final String? prefecture;
  final String? type;
  final String? description;
  final String? catchCopy;
  final int? confidenceScore;
  final List<String> flavorTags;
  final Map<String, int> tasteStats;
  
  // New Fields
  final double? alcoholContent;
  final int? polishingRatio;
  final double? sakeMeterValue;
  final String? riceVariety;
  final String? yeast;
  final String? manufacturingYearMonth;

  SakeAnalysisResult({
    this.name,
    this.brand,
    this.prefecture,
    this.type,
    this.description,
    this.catchCopy,
    this.confidenceScore,
    this.flavorTags = const [],
    this.tasteStats = const {},
    this.alcoholContent,
    this.polishingRatio,
    this.sakeMeterValue,
    this.riceVariety,
    this.yeast,
    this.manufacturingYearMonth,
  });

  factory SakeAnalysisResult.fromJson(Map<String, dynamic> json) {
    // Helper to extract int from map safely
    Map<String, int> stats = {};
    if (json['tasteStats'] is Map) {
      final map = json['tasteStats'] as Map;
      stats = map.map((key, value) => MapEntry(key.toString(), (value as num?)?.toInt() ?? 3));
    }

    return SakeAnalysisResult(
      name: json['name'] as String?,
      brand: json['brand'] as String?,
      prefecture: json['prefecture'] as String?,
      type: json['type'] as String?,
      description: json['description'] as String?,
      catchCopy: json['catchCopy'] as String?,
      confidenceScore: json['confidenceScore'] as int?,
      flavorTags: (json['flavorTags'] as List<dynamic>?)?.map((e) => e.toString()).toList() ?? [],
      tasteStats: stats,
      alcoholContent: (json['alcoholContent'] as num?)?.toDouble(),
      polishingRatio: (json['polishingRatio'] as num?)?.toInt(),
      sakeMeterValue: (json['sakeMeterValue'] as num?)?.toDouble(),
      riceVariety: json['riceVariety'] as String?,
      yeast: json['yeast'] as String?,
      manufacturingYearMonth: json['manufacturingYearMonth'] as String?,
    );
  }

  /// JSON形式に変換（キャッシュ保存用）
  Map<String, dynamic> toJson() {
    return {
      'name': name,
      'brand': brand,
      'prefecture': prefecture,
      'type': type,
      'description': description,
      'catchCopy': catchCopy,
      'confidenceScore': confidenceScore,
      'flavorTags': flavorTags,
      'tasteStats': tasteStats,
      'alcoholContent': alcoholContent,
      'polishingRatio': polishingRatio,
      'sakeMeterValue': sakeMeterValue,
      'riceVariety': riceVariety,
      'yeast': yeast,
      'manufacturingYearMonth': manufacturingYearMonth,
    };
  }
}
