import 'dart:convert';
import 'dart:developer';
import 'package:enaklo_pos/core/database/database_handler.dart';
import 'package:enaklo_pos/data/models/response/category_response_model.dart';
import 'package:sqflite/sqflite.dart';

class CategoryLocalDatasource {
  static CategoryLocalDatasource? _instance;

  CategoryLocalDatasource._internal();

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

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

  // ========================================
  // CACHING SYSTEM
  // ========================================
  final Map<String, List<CategoryModel>> _queryCache = {};
  final Duration _cacheExpiry =
      Duration(minutes: 10); // Lebih lama untuk categories
  final Map<String, DateTime> _cacheTimestamps = {};

  // ========================================
  // BATCH SAVE CATEGORIES
  // ========================================
  Future<void> saveCategoriesBatch(List<CategoryModel> categories,
      {bool clearFirst = false}) async {
    final db = await _db;

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

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

        // Batch insert categories
        final batch = txn.batch();
        for (final category in categories) {
          batch.insert(
            'categories',
            _categoryToMap(category),
            conflictAlgorithm: ConflictAlgorithm.replace,
          );
        }
        await batch.commit(noResult: true);
      });

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

  // ========================================
  // CACHED QUERY
  // ========================================
  Future<List<CategoryModel>> getCachedCategories({
    int page = 1,
    int limit = 10,
    bool isActive = true,
    String? search,
  }) async {
    final cacheKey = _generateCacheKey(page, limit, isActive, 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} categories)');
        return _queryCache[cacheKey]!;
      }
    }

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

    // Cache miss, query database
    final categories = await getCategories(
      page: page,
      limit: limit,
      isActive: isActive,
      search: search,
    );

    // Store in cache
    _queryCache[cacheKey] = categories;
    _cacheTimestamps[cacheKey] = now;

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

  // ========================================
  // REGULAR GET CATEGORIES
  // ========================================
  Future<List<CategoryModel>> getCategories({
    int page = 1,
    int limit = 10,
    bool isActive = true,
    String? search,
  }) async {
    final db = await _db;

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

      // Note: Assuming is_active will be added to database schema
      if (isActive) {
        query += ' AND is_active = ?';
        whereArgs.add(1);
      }

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

      // query += ' ORDER BY name ASC';

      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<CategoryModel> categories = [];
      for (final map in maps) {
        categories.add(_mapToCategory(map));
      }

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

  // ========================================
  // GET ALL CATEGORIES (For dropdowns)
  // ========================================
  Future<List<CategoryModel>> getAllCategories() async {
    const cacheKey = 'all_categories';
    final now = DateTime.now();

    // Check cache
    if (_queryCache.containsKey(cacheKey) &&
        _cacheTimestamps.containsKey(cacheKey)) {
      final cacheTime = _cacheTimestamps[cacheKey]!;
      if (now.difference(cacheTime) < _cacheExpiry) {
        return _queryCache[cacheKey]!;
      }
    }

    final db = await _db;

    try {
      final List<Map<String, dynamic>> maps = await db.query(
        'categories',
        orderBy: 'name ASC',
      );

      final categories = maps.map((map) => _mapToCategory(map)).toList();

      // Cache all categories
      _queryCache[cacheKey] = categories;
      _cacheTimestamps[cacheKey] = now;

      log('📊 Retrieved ${categories.length} total categories');
      return categories;
    } catch (e) {
      log('❌ Error getting all categories: $e');
      return [];
    }
  }

  // ========================================
  // GET CATEGORY BY ID
  // ========================================
  Future<CategoryModel?> getCategoryById(String id) async {
    final db = await _db;

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

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

      final category = _mapToCategory(maps.first);
      log('✅ Category found: ${category.name}');
      return category;
    } catch (e) {
      log('❌ Error getting category by ID: $e');
      return null;
    }
  }

  // ========================================
  // GET TOTAL COUNT
  // ========================================
  Future<int> getTotalCount({bool isActive = true, String? search}) async {
    final db = await _db;

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

      if (isActive) {
        query += ' AND is_active = ?';
        whereArgs.add(1);
      }

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

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

  // ========================================
  // HAS CATEGORIES
  // ========================================
  Future<bool> hasCategories() async {
    final count = await getTotalCount();
    final hasData = count > 0;
    log('🔍 Has categories: $hasData ($count categories)');
    return hasData;
  }

  // ========================================
  // CLEAR ALL CATEGORIES
  // ========================================
  Future<void> clearAllCategories() async {
    final db = await _db;

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

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

  void clearCache() {
    final count = _queryCache.length;
    _queryCache.clear();
    _cacheTimestamps.clear();
    log('🧹 Category 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 category cache cleared: ${expiredKeys.length} entries');
    }
  }

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

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

      final activeCount = Sqflite.firstIntValue(await db.rawQuery(
              'SELECT COUNT(*) FROM categories WHERE is_active = 1')) ??
          0;

      final stats = {
        'total_categories': categoryCount,
        'active_categories': activeCount,
        'cache_entries': _queryCache.length,
      };

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

  // ========================================
  // HELPER METHODS
  // ========================================
  Map<String, dynamic> _categoryToMap(CategoryModel category) {
    return {
      'id': category.id,
      'organization_id': category.organizationId,
      'name': category.name,
      'description': category.description,
      'business_type': category.businessType,
      'metadata': json.encode(category.metadata),
      'is_active': 1, // Assuming all synced categories are active
      'created_at': category.createdAt.toIso8601String(),
      'updated_at': category.updatedAt.toIso8601String(),
    };
  }

  CategoryModel _mapToCategory(Map<String, dynamic> map) {
    return CategoryModel(
      id: map['id'],
      organizationId: map['organization_id'],
      name: map['name'],
      description: map['description'],
      businessType: map['business_type'],
      metadata: map['metadata'] != null ? json.decode(map['metadata']) : {},
      createdAt: DateTime.parse(map['created_at']),
      updatedAt: DateTime.parse(map['updated_at']),
    );
  }
}
