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

class PrinterLocalDatasource {
  static PrinterLocalDatasource? _instance;

  PrinterLocalDatasource._internal();

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

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

  // Create new printer
  Future<int> createPrinter(PrintModel printer) async {
    final db = await _db;

    try {
      log('Creating printer: ${printer.toString()}');

      final id = await db.insert(
        'printers',
        printer.toMapForInsert(),
        conflictAlgorithm:
            ConflictAlgorithm.abort, // Fail if code already exists
      );

      log('Successfully created printer with ID: $id');
      return id;
    } catch (e) {
      log('Error creating printer: $e');
      rethrow;
    }
  }

  // Update existing printer
  Future<void> updatePrinter(PrintModel printer, int id) async {
    final db = await _db;

    try {
      log('Updating printer ID $id: ${printer.toString()}');

      final updatedRows = await db.update(
        'printers',
        printer.toMapForUpdate(),
        where: 'id = ?',
        whereArgs: [id],
      );

      if (updatedRows == 0) {
        throw Exception('Printer with ID $id not found');
      }

      log('Successfully updated printer ID: $id');
    } catch (e) {
      log('Error updating printer: $e');
      rethrow;
    }
  }

  // Delete printer by ID
  Future<void> deletePrinter(int id) async {
    final db = await _db;

    try {
      log('Deleting printer ID: $id');

      final deletedRows = await db.delete(
        'printers',
        where: 'id = ?',
        whereArgs: [id],
      );

      if (deletedRows == 0) {
        throw Exception('Printer with ID $id not found');
      }

      log('Successfully deleted printer ID: $id');
    } catch (e) {
      log('Error deleting printer: $e');
      rethrow;
    }
  }

  // Get printer by code
  Future<PrintModel?> getPrinterByCode(String code) async {
    final db = await _db;

    try {
      log('Getting printer by code: $code');

      final result = await db.query(
        'printers',
        where: 'code = ?',
        whereArgs: [code],
      );

      if (result.isEmpty) {
        log('Printer with code $code not found');
        return null;
      }

      final printer = PrintModel.fromMap(result.first);
      log('Found printer: ${printer.toString()}');
      return printer;
    } catch (e) {
      log('Error getting printer by code: $e');
      return null;
    }
  }

  // Get printer by ID
  Future<PrintModel?> getPrinterById(int id) async {
    final db = await _db;

    try {
      log('Getting printer by ID: $id');

      final result = await db.query(
        'printers',
        where: 'id = ?',
        whereArgs: [id],
      );

      if (result.isEmpty) {
        log('Printer with ID $id not found');
        return null;
      }

      final printer = PrintModel.fromMap(result.first);
      log('Found printer: ${printer.toString()}');
      return printer;
    } catch (e) {
      log('Error getting printer by ID: $e');
      return null;
    }
  }

  // Get all printers
  Future<List<PrintModel>> getAllPrinters() async {
    final db = await _db;

    try {
      log('Getting all printers');

      final result = await db.query(
        'printers',
        orderBy: 'name ASC',
      );

      final printers = result.map((map) => PrintModel.fromMap(map)).toList();
      log('Found ${printers.length} printers');

      return printers;
    } catch (e) {
      log('Error getting all printers: $e');
      return [];
    }
  }

  // Get printers by type
  Future<List<PrintModel>> getPrintersByType(String type) async {
    final db = await _db;

    try {
      log('Getting printers by type: $type');

      final result = await db.query(
        'printers',
        where: 'type = ?',
        whereArgs: [type],
        orderBy: 'name ASC',
      );

      final printers = result.map((map) => PrintModel.fromMap(map)).toList();
      log('Found ${printers.length} printers with type $type');

      return printers;
    } catch (e) {
      log('Error getting printers by type: $e');
      return [];
    }
  }

  // Search printers by name
  Future<List<PrintModel>> searchPrintersByName(String query) async {
    final db = await _db;

    try {
      log('Searching printers by name: $query');

      final result = await db.query(
        'printers',
        where: 'name LIKE ?',
        whereArgs: ['%$query%'],
        orderBy: 'name ASC',
      );

      final printers = result.map((map) => PrintModel.fromMap(map)).toList();
      log('Found ${printers.length} printers matching "$query"');

      return printers;
    } catch (e) {
      log('Error searching printers: $e');
      return [];
    }
  }

  // Check if printer code exists
  Future<bool> isPrinterCodeExists(String code, {int? excludeId}) async {
    final db = await _db;

    try {
      String whereClause = 'code = ?';
      List<dynamic> whereArgs = [code];

      if (excludeId != null) {
        whereClause += ' AND id != ?';
        whereArgs.add(excludeId);
      }

      final result = await db.query(
        'printers',
        where: whereClause,
        whereArgs: whereArgs,
      );

      final exists = result.isNotEmpty;
      log('Printer code "$code" exists: $exists');
      return exists;
    } catch (e) {
      log('Error checking printer code existence: $e');
      return false;
    }
  }

  // Get printer statistics
  Future<Map<String, dynamic>> getPrinterStats() async {
    final db = await _db;

    try {
      // Total count
      final totalResult =
          await db.rawQuery('SELECT COUNT(*) as total FROM printers');
      final totalCount = totalResult.first['total'] as int;

      // Count by type
      final typeResult = await db.rawQuery('''
        SELECT type, COUNT(*) as count 
        FROM printers 
        WHERE type IS NOT NULL 
        GROUP BY type
      ''');

      final typeStats = <String, int>{};
      for (final row in typeResult) {
        typeStats[row['type'] as String] = row['count'] as int;
      }

      final stats = {
        'total_printers': totalCount,
        'by_type': typeStats,
      };

      log('Printer stats: $stats');
      return stats;
    } catch (e) {
      log('Error getting printer stats: $e');
      return {
        'total_printers': 0,
        'by_type': <String, int>{},
      };
    }
  }

  // Clear all printers (for testing/reset purposes)
  Future<void> clearAllPrinters() async {
    final db = await _db;

    try {
      log('Clearing all printers');
      await db.delete('printers');
      log('All printers cleared');
    } catch (e) {
      log('Error clearing printers: $e');
      rethrow;
    }
  }

  // Batch insert printers
  Future<void> insertPrinters(List<PrintModel> printers) async {
    final db = await _db;

    try {
      log('Batch inserting ${printers.length} printers');

      await db.transaction((txn) async {
        for (final printer in printers) {
          await txn.insert(
            'printers',
            printer.toMapForInsert(),
            conflictAlgorithm: ConflictAlgorithm.replace,
          );
        }
      });

      log('Successfully batch inserted ${printers.length} printers');
    } catch (e) {
      log('Error batch inserting printers: $e');
      rethrow;
    }
  }
}
