import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:enaklo_pos/core/database/database_handler.dart';
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart' as p;

class ProductLocalDatasource {
  static ProductLocalDatasource? _instance;

  ProductLocalDatasource._internal();

  static ProductLocalDatasource get instance {
    _instance ??= ProductLocalDatasource._internal();
    return _instance!;
  }

  Future<Database> get _db async => await DatabaseHelper.instance.database;

  // ========================================
  // CACHING SYSTEM
  // ========================================
  final Map<String, List<Product>> _queryCache = {};
  final Duration _cacheExpiry = Duration(minutes: 5);
  final Map<String, DateTime> _cacheTimestamps = {};

  // ========================================
  // ENHANCED BATCH SAVE
  // ========================================
  Future<void> saveProductsBatch(List<Product> products,
      {bool clearFirst = false}) async {
    final db = await _db;

    try {
      await db.transaction((txn) async {
        if (clearFirst) {
          log('🗑️ Clearing existing products...');
          await txn.delete('product_variants');
          await txn.delete('products');
        }

        log('💾 Batch saving ${products.length} products...');

        // ✅ BATCH INSERT PRODUCTS - Much faster than individual inserts
        final batch = txn.batch();
        for (final product in products) {
          batch.insert(
            'products',
            _productToMap(product),
            conflictAlgorithm: ConflictAlgorithm.replace,
          );
        }
        await batch.commit(noResult: true);

        // ✅ BATCH INSERT VARIANTS
        final variantBatch = txn.batch();
        for (final product in products) {
          if (product.variants?.isNotEmpty == true) {
            // Delete existing variants in batch
            variantBatch.delete(
              'product_variants',
              where: 'product_id = ?',
              whereArgs: [product.id],
            );

            // Insert new variants
            for (final variant in product.variants!) {
              variantBatch.insert(
                'product_variants',
                _variantToMap(variant),
                conflictAlgorithm: ConflictAlgorithm.replace,
              );
            }
          }
        }
        await variantBatch.commit(noResult: true);
      });

      // Clear cache after update
      clearCache();
      log('✅ Successfully batch saved ${products.length} products');
    } catch (e) {
      log('❌ Error batch saving products: $e');
      rethrow;
    }
  }

  // ========================================
  // CACHED QUERY - HIGH PERFORMANCE
  // ========================================
  Future<List<Product>> getCachedProducts({
    int page = 1,
    int limit = 10,
    String? categoryId,
    String? search,
  }) async {
    final cacheKey = _generateCacheKey(page, limit, categoryId, search);
    final now = DateTime.now();

    // ✅ CHECK CACHE FIRST
    if (_queryCache.containsKey(cacheKey) &&
        _cacheTimestamps.containsKey(cacheKey)) {
      final cacheTime = _cacheTimestamps[cacheKey]!;
      if (now.difference(cacheTime) < _cacheExpiry) {
        log('🚀 Cache HIT: $cacheKey (${_queryCache[cacheKey]!.length} products)');
        return _queryCache[cacheKey]!; // Return from cache - SUPER FAST
      }
    }

    log('📀 Cache MISS: $cacheKey, querying database...');

    // Cache miss, query database
    final products = await getProducts(
      page: page,
      limit: limit,
      categoryId: categoryId,
      search: search,
    );

    // ✅ STORE IN CACHE for next time
    _queryCache[cacheKey] = products;
    _cacheTimestamps[cacheKey] = now;

    log('💾 Cached ${products.length} products for key: $cacheKey');
    return products;
  }

  // ========================================
  // REGULAR GET PRODUCTS (No Cache)
  // ========================================
  Future<List<Product>> getProducts({
    int page = 1,
    int limit = 10,
    String? categoryId,
    String? search,
  }) async {
    final db = await _db;

    try {
      String query = 'SELECT * FROM products WHERE 1=1';
      List<dynamic> whereArgs = [];

      if (categoryId != null && categoryId.isNotEmpty) {
        query += ' AND category_id = ?';
        whereArgs.add(categoryId);
      }

      if (search != null && search.isNotEmpty) {
        query += ' AND (name LIKE ? OR sku LIKE ? OR description LIKE ?)';
        whereArgs.add('%$search%');
        whereArgs.add('%$search%');
        whereArgs.add('%$search%');
      }

      query += ' ORDER BY created_at DESC';

      if (limit > 0) {
        query += ' LIMIT ?';
        whereArgs.add(limit);

        if (page > 1) {
          query += ' OFFSET ?';
          whereArgs.add((page - 1) * limit);
        }
      }

      final List<Map<String, dynamic>> maps =
          await db.rawQuery(query, whereArgs);

      List<Product> products = [];
      for (final map in maps) {
        final variants = await _getProductVariants(db, map['id']);
        final product = _mapToProduct(map, variants);
        products.add(product);
      }

      log('📊 Retrieved ${products.length} products from database');
      return products;
    } catch (e) {
      log('❌ Error getting products: $e');
      return [];
    }
  }

  // ========================================
  // OPTIMIZED SEARCH with RANKING
  // ========================================
  Future<List<Product>> searchProductsOptimized(String query) async {
    final db = await _db;

    try {
      log('🔍 Optimized search for: "$query"');

      // ✅ Smart query with prioritization
      final List<Map<String, dynamic>> maps = await db.rawQuery('''
        SELECT * FROM products 
        WHERE name LIKE ? OR sku LIKE ? OR description LIKE ?
        ORDER BY 
          CASE 
            WHEN name LIKE ? THEN 1      -- Highest priority: name match
            WHEN sku LIKE ? THEN 2       -- Second priority: SKU match  
            ELSE 3                       -- Lowest priority: description
          END,
          name ASC
        LIMIT 50
      ''', [
        '%$query%', '%$query%', '%$query%',
        '$query%', '$query%' // Prioritize results that start with query
      ]);

      List<Product> products = [];
      for (final map in maps) {
        final variants = await _getProductVariants(db, map['id']);
        products.add(_mapToProduct(map, variants));
      }

      log('🎯 Optimized search found ${products.length} results');
      return products;
    } catch (e) {
      log('❌ Error in optimized search: $e');
      return [];
    }
  }

  // ========================================
  // DATABASE ANALYTICS & MONITORING
  // ========================================
  Future<Map<String, dynamic>> getDatabaseStats() async {
    final db = await _db;

    try {
      final productCount = Sqflite.firstIntValue(
              await db.rawQuery('SELECT COUNT(*) FROM products')) ??
          0;

      final variantCount = Sqflite.firstIntValue(
              await db.rawQuery('SELECT COUNT(*) FROM product_variants')) ??
          0;

      final categoryCount = Sqflite.firstIntValue(await db.rawQuery(
              'SELECT COUNT(DISTINCT category_id) FROM products WHERE category_id IS NOT NULL')) ??
          0;

      final dbSize = await _getDatabaseSize();

      final stats = {
        'total_products': productCount,
        'total_variants': variantCount,
        'total_categories': categoryCount,
        'database_size_mb': dbSize,
        'cache_entries': _queryCache.length,
        'cache_size_mb': _getCacheSize(),
      };

      log('📊 Database Stats: $stats');
      return stats;
    } catch (e) {
      log('❌ Error getting database stats: $e');
      return {};
    }
  }

  Future<double> _getDatabaseSize() async {
    try {
      final dbPath = p.join(await getDatabasesPath(), 'pos_database.db');
      final file = File(dbPath);
      if (await file.exists()) {
        final size = await file.length();
        return size / (1024 * 1024); // Convert to MB
      }
    } catch (e) {
      log('Error getting database size: $e');
    }
    return 0.0;
  }

  double _getCacheSize() {
    double totalSize = 0;
    _queryCache.forEach((key, products) {
      totalSize += products.length * 0.001; // Rough estimate in MB
    });
    return totalSize;
  }

  // ========================================
  // CACHE MANAGEMENT
  // ========================================
  String _generateCacheKey(
      int page, int limit, String? categoryId, String? search) {
    return 'products_${page}_${limit}_${categoryId ?? 'null'}_${search ?? 'null'}';
  }

  void clearCache() {
    final count = _queryCache.length;
    _queryCache.clear();
    _cacheTimestamps.clear();
    log('🧹 Cache cleared: $count entries removed');
  }

  void clearExpiredCache() {
    final now = DateTime.now();
    final expiredKeys = <String>[];

    _cacheTimestamps.forEach((key, timestamp) {
      if (now.difference(timestamp) > _cacheExpiry) {
        expiredKeys.add(key);
      }
    });

    for (final key in expiredKeys) {
      _queryCache.remove(key);
      _cacheTimestamps.remove(key);
    }

    if (expiredKeys.isNotEmpty) {
      log('⏰ Expired cache cleared: ${expiredKeys.length} entries');
    }
  }

  // ========================================
  // OTHER METHODS (Same as basic but with enhanced logging)
  // ========================================

  Future<Product?> getProductById(String id) async {
    final db = await _db;

    try {
      final List<Map<String, dynamic>> maps = await db.query(
        'products',
        where: 'id = ?',
        whereArgs: [id],
      );

      if (maps.isEmpty) {
        log('❌ Product not found: $id');
        return null;
      }

      final variants = await _getProductVariants(db, id);
      final product = _mapToProduct(maps.first, variants);
      log('✅ Product found: ${product.name}');
      return product;
    } catch (e) {
      log('❌ Error getting product by ID: $e');
      return null;
    }
  }

  Future<int> getTotalCount({String? categoryId, String? search}) async {
    final db = await _db;

    try {
      String query = 'SELECT COUNT(*) FROM products WHERE 1=1';
      List<dynamic> whereArgs = [];

      if (categoryId != null && categoryId.isNotEmpty) {
        query += ' AND category_id = ?';
        whereArgs.add(categoryId);
      }

      if (search != null && search.isNotEmpty) {
        query += ' AND (name LIKE ? OR sku LIKE ? OR description LIKE ?)';
        whereArgs.add('%$search%');
        whereArgs.add('%$search%');
        whereArgs.add('%$search%');
      }

      final result = await db.rawQuery(query, whereArgs);
      final count = Sqflite.firstIntValue(result) ?? 0;
      log('📊 Total count: $count (categoryId: $categoryId, search: $search)');
      return count;
    } catch (e) {
      log('❌ Error getting total count: $e');
      return 0;
    }
  }

  Future<bool> hasProducts() async {
    final count = await getTotalCount();
    final hasData = count > 0;
    log('🔍 Has products: $hasData ($count products)');
    return hasData;
  }

  Future<void> clearAllProducts() async {
    final db = await _db;

    try {
      await db.transaction((txn) async {
        await txn.delete('product_variants');
        await txn.delete('products');
      });
      clearCache();
      log('🗑️ All products cleared from local DB');
    } catch (e) {
      log('❌ Error clearing products: $e');
      rethrow;
    }
  }

  // ========================================
  // HELPER METHODS
  // ========================================

  Future<List<ProductVariant>> _getProductVariants(
      Database db, String productId) async {
    try {
      final List<Map<String, dynamic>> maps = await db.query(
        'product_variants',
        where: 'product_id = ?',
        whereArgs: [productId],
        orderBy: 'name ASC',
      );

      return maps.map((map) => _mapToVariant(map)).toList();
    } catch (e) {
      log('❌ Error getting variants for product $productId: $e');
      return [];
    }
  }

  Map<String, dynamic> _productToMap(Product product) {
    return {
      'id': product.id,
      'organization_id': product.organizationId,
      'category_id': product.categoryId,
      'sku': product.sku,
      'name': product.name,
      'description': product.description,
      'price': product.price,
      'cost': product.cost,
      'business_type': product.businessType,
      'image_url': product.imageUrl,
      'printer_type': product.printerType,
      'metadata':
          product.metadata != null ? json.encode(product.metadata) : null,
      'is_active': product.isActive == true ? 1 : 0,
      'created_at': product.createdAt?.toIso8601String(),
      'updated_at': product.updatedAt?.toIso8601String(),
    };
  }

  Map<String, dynamic> _variantToMap(ProductVariant variant) {
    return {
      'id': variant.id,
      'product_id': variant.productId,
      'name': variant.name,
      'price_modifier': variant.priceModifier,
      'cost': variant.cost,
      'metadata':
          variant.metadata != null ? json.encode(variant.metadata) : null,
      'created_at': variant.createdAt?.toIso8601String(),
      'updated_at': variant.updatedAt?.toIso8601String(),
    };
  }

  Product _mapToProduct(
      Map<String, dynamic> map, List<ProductVariant> variants) {
    return Product(
      id: map['id'],
      organizationId: map['organization_id'],
      categoryId: map['category_id'],
      sku: map['sku'],
      name: map['name'],
      description: map['description'],
      price: map['price'],
      cost: map['cost'],
      businessType: map['business_type'],
      imageUrl: map['image_url'],
      printerType: map['printer_type'],
      metadata: map['metadata'] != null ? json.decode(map['metadata']) : null,
      isActive: map['is_active'] == 1,
      createdAt:
          map['created_at'] != null ? DateTime.parse(map['created_at']) : null,
      updatedAt:
          map['updated_at'] != null ? DateTime.parse(map['updated_at']) : null,
      variants: variants,
    );
  }

  ProductVariant _mapToVariant(Map<String, dynamic> map) {
    return ProductVariant(
      id: map['id'],
      productId: map['product_id'],
      name: map['name'],
      priceModifier: map['price_modifier'],
      cost: map['cost'],
      metadata: map['metadata'] != null ? json.decode(map['metadata']) : null,
      createdAt:
          map['created_at'] != null ? DateTime.parse(map['created_at']) : null,
      updatedAt:
          map['updated_at'] != null ? DateTime.parse(map['updated_at']) : null,
    );
  }
}
