import 'dart:convert';
import 'package:http/http.dart' as http;
import '../models/sakenowa/sakenowa_models.dart';

/// さけのわAPI クライアントサービス
/// 
/// API Documentation: https://muro.sakenowa.com/sakenowa-data/api/
/// 利用規約: 無料・商用OK、帰属表示必須（"Powered by さけのわデータ"）
class SakenowaService {
  static const _baseUrl = 'https://muro.sakenowa.com/sakenowa-data/api';
  
  // キャッシュ（メモリ内）
  List<SakenowaBrand>? _brandsCache;
  List<SakenowaBrewery>? _breweriesCache;
  List<SakenowaArea>? _areasCache;
  List<SakenowaFlavorChart>? _flavorChartsCache;
  DateTime? _lastFetch;
  
  // キャッシュ有効期限（24時間）
  static const _cacheDuration = Duration(hours: 24);

  /// 全銘柄データを取得
  Future<List<SakenowaBrand>> getBrands({bool forceRefresh = false}) async {
    if (!forceRefresh && _brandsCache != null && _isCacheValid()) {
      return _brandsCache!;
    }
    
    final response = await http.get(Uri.parse('$_baseUrl/brands'));
    if (response.statusCode != 200) {
      throw Exception('Failed to fetch brands: ${response.statusCode}');
    }
    
    final data = jsonDecode(response.body);
    _brandsCache = (data['brands'] as List)
        .map((e) => SakenowaBrand.fromJson(e))
        .toList();
    _lastFetch = DateTime.now();
    
    return _brandsCache!;
  }

  /// 全蔵元データを取得
  Future<List<SakenowaBrewery>> getBreweries({bool forceRefresh = false}) async {
    if (!forceRefresh && _breweriesCache != null && _isCacheValid()) {
      return _breweriesCache!;
    }
    
    final response = await http.get(Uri.parse('$_baseUrl/breweries'));
    if (response.statusCode != 200) {
      throw Exception('Failed to fetch breweries: ${response.statusCode}');
    }
    
    final data = jsonDecode(response.body);
    _breweriesCache = (data['breweries'] as List)
        .map((e) => SakenowaBrewery.fromJson(e))
        .toList();
    
    return _breweriesCache!;
  }

  /// 全地域データを取得
  Future<List<SakenowaArea>> getAreas({bool forceRefresh = false}) async {
    if (!forceRefresh && _areasCache != null && _isCacheValid()) {
      return _areasCache!;
    }
    
    final response = await http.get(Uri.parse('$_baseUrl/areas'));
    if (response.statusCode != 200) {
      throw Exception('Failed to fetch areas: ${response.statusCode}');
    }
    
    final data = jsonDecode(response.body);
    _areasCache = (data['areas'] as List)
        .map((e) => SakenowaArea.fromJson(e))
        .toList();
    
    return _areasCache!;
  }

  /// 全フレーバーチャートを取得
  Future<List<SakenowaFlavorChart>> getFlavorCharts({bool forceRefresh = false}) async {
    if (!forceRefresh && _flavorChartsCache != null && _isCacheValid()) {
      return _flavorChartsCache!;
    }
    
    final response = await http.get(Uri.parse('$_baseUrl/flavor-charts'));
    if (response.statusCode != 200) {
      throw Exception('Failed to fetch flavor charts: ${response.statusCode}');
    }
    
    final data = jsonDecode(response.body);
    _flavorChartsCache = (data['flavorCharts'] as List)
        .map((e) => SakenowaFlavorChart.fromJson(e))
        .toList();
    
    return _flavorChartsCache!;
  }

  /// 銘柄IDからフレーバーチャートを取得
  Future<SakenowaFlavorChart?> getFlavorChartByBrandId(int brandId) async {
    final charts = await getFlavorCharts();
    return charts.cast<SakenowaFlavorChart?>().firstWhere(
      (c) => c?.brandId == brandId,
      orElse: () => null,
    );
  }

  /// ランキングを取得（全国）
  Future<List<SakenowaRanking>> getRankings() async {
    try {
      final response = await http.get(Uri.parse('$_baseUrl/rankings'));
      if (response.statusCode != 200) {
        throw Exception('Failed to fetch rankings: ${response.statusCode}');
      }
      
      final data = jsonDecode(response.body);
      // APIレスポンスは 'overall' キーに全国ランキングが入っている
      final overallList = data['overall'] as List?;
      if (overallList == null) {
        throw Exception('Rankings data not found in response');
      }
      return overallList
          .map((e) => SakenowaRanking.fromJson(e))
          .toList();
    } catch (e) {
      rethrow;
    }
  }

  /// フレーバータグ一覧を取得
  Future<List<SakenowaFlavorTag>> getFlavorTags() async {
    final response = await http.get(Uri.parse('$_baseUrl/flavor-tags'));
    if (response.statusCode != 200) {
      throw Exception('Failed to fetch flavor tags: ${response.statusCode}');
    }
    
    final data = jsonDecode(response.body);
    return (data['tags'] as List)
        .map((e) => SakenowaFlavorTag.fromJson(e))
        .toList();
  }

  /// 銘柄名で検索（部分一致）
  Future<List<SakenowaBrand>> searchBrandsByName(String query) async {
    final brands = await getBrands();
    final normalizedQuery = query.toLowerCase();
    
    return brands.where((brand) {
      return brand.name.toLowerCase().contains(normalizedQuery);
    }).toList();
  }

  /// 銘柄名から最も近いマッチを取得
  Future<SakenowaBrand?> findBestMatch(String name) async {
    final brands = await getBrands();
    final normalizedName = name.toLowerCase().replaceAll(' ', '');
    
    // 完全一致を優先
    for (final brand in brands) {
      if (brand.name.toLowerCase().replaceAll(' ', '') == normalizedName) {
        return brand;
      }
    }
    
    // 部分一致
    for (final brand in brands) {
      if (brand.name.toLowerCase().contains(normalizedName) ||
          normalizedName.contains(brand.name.toLowerCase())) {
        return brand;
      }
    }
    
    return null;
  }

  /// 銘柄の蔵元情報を取得
  Future<SakenowaBrewery?> getBreweryByBrandId(int brandId) async {
    final brands = await getBrands();
    final brand = brands.cast<SakenowaBrand?>().firstWhere(
      (b) => b?.id == brandId,
      orElse: () => null,
    );
    
    if (brand == null) return null;
    
    final breweries = await getBreweries();
    return breweries.cast<SakenowaBrewery?>().firstWhere(
      (b) => b?.id == brand.breweryId,
      orElse: () => null,
    );
  }

  /// キャッシュが有効かチェック
  bool _isCacheValid() {
    if (_lastFetch == null) return false;
    return DateTime.now().difference(_lastFetch!) < _cacheDuration;
  }

  /// キャッシュをクリア
  void clearCache() {
    _brandsCache = null;
    _breweriesCache = null;
    _areasCache = null;
    _flavorChartsCache = null;
    _lastFetch = null;
  }
}
