import 'dart:developer';
import 'dart:ui';

import 'package:enaklo_pos/data/models/response/print_model.dart';
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
import 'package:enaklo_pos/data/models/response/table_model.dart';
import 'package:enaklo_pos/presentation/home/models/order_model.dart';
import 'package:enaklo_pos/presentation/table/models/draft_order_item.dart';
import 'package:enaklo_pos/presentation/table/models/draft_order_model.dart';
import 'package:sqflite/sqflite.dart';

import '../../presentation/home/models/product_quantity.dart';

class ProductLocalDatasource {
  ProductLocalDatasource._init();

  static final ProductLocalDatasource instance = ProductLocalDatasource._init();

  final String tableProduct = 'products';
  final String tableOrder = 'orders';
  final String tableOrderItem = 'order_items';
  final String tableManagement = 'table_management';
  final String tablePrint = 'prints';
  static Database? _database;

  // "id": 1,
  //           "category_id": 1,
  //           "name": "Mie Ayam",
  //           "description": "Ipsa dolorem impedit dolor. Libero nisi quidem expedita quod mollitia ad. Voluptas ut quia nemo nisi odit fuga. Fugit autem qui ratione laborum eum.",
  //           "image": "https://via.placeholder.com/640x480.png/002200?text=nihil",
  //           "price": "2000.44",
  //           "stock": 94,
  //           "status": 1,
  //           "is_favorite": 1,
  //           "created_at": "2024-02-08T14:30:22.000000Z",
  //           "updated_at": "2024-02-08T15:14:22.000000Z"

  Future<void> _createDb(Database db, int version) async {
    await db.execute('''
      CREATE TABLE $tableProduct (
        id INTEGER PRIMARY KEY,
        product_id INTEGER,
        name TEXT,
        printer_type TEXT,
        categoryId INTEGER,
        categoryName TEXT,
        description TEXT,
        image TEXT,
        price TEXT,
        stock INTEGER,
        status INTEGER,
        isFavorite INTEGER,
        createdAt TEXT,
        updatedAt TEXT
      )
    ''');

    await db.execute('''
      CREATE TABLE $tableOrder (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        payment_amount INTEGER,
        sub_total INTEGER,
        tax INTEGER,
        discount INTEGER,
        discount_amount INTEGER,
        service_charge INTEGER,
        total INTEGER,
        payment_method TEXT,
        total_item INTEGER,
        id_kasir INTEGER,
        nama_kasir TEXT,
        transaction_time TEXT,
        table_number INTEGER,
        customer_name TEXT,
        status TEXT,
        payment_status TEXT,
        order_type TEXT DEFAULT 'DINE IN',
        is_sync INTEGER DEFAULT 0
      )
    ''');

    await db.execute('''
      CREATE TABLE $tableOrderItem (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        id_order INTEGER,
        id_product INTEGER,
        quantity INTEGER,
        price INTEGER,
        notes TEXT DEFAULT ''
      )
    ''');

    await db.execute('''
        CREATE TABLE $tableManagement (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        table_name Text,
        start_time Text,
        order_id INTEGER,
        payment_amount INTEGER,
        x_position REAL NOT NULL,
        y_position REAL NOT NULL,
        status TEXT
      )
    ''');

    await db.execute('''
      CREATE TABLE draft_orders (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        total_item INTEGER,
        subtotal INTEGER,
        tax INTEGER,
        discount INTEGER,
        discount_amount INTEGER,
        service_charge INTEGER,
        total INTEGER,
        transaction_time TEXT,
        table_number INTEGER,
        draft_name TEXT
      )
    ''');

    await db.execute('''
      CREATE TABLE draft_order_items (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        id_draft_order INTEGER,
        id_product INTEGER,
        quantity INTEGER,
        price INTEGER
      )
    ''');

    await db.execute('''
      CREATE TABLE $tablePrint (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        code TEXT,
        name TEXT,
        address TEXT,
        paper TEXT,
        type TEXT
      )
    ''');
  }

  Future<Database> _initDB(String filePath) async {
    final dbPath = await getDatabasesPath();
    final path = dbPath + filePath;

    // Force delete existing database to ensure new schema
    try {
      final dbExists = await databaseExists(path);
      if (dbExists) {
        log("Deleting existing database to ensure new schema with order_type column");
        // await deleteDatabase(path);
      }
    } catch (e) {
      log("Error deleting database: $e");
    }

    return await openDatabase(
      path,
      version: 2,
      onCreate: _createDb,
      onUpgrade: _onUpgrade,
    );
  }

  Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
    if (oldVersion < 2) {
      // Add order_type column to orders table if it doesn't exist
      try {
        await db.execute(
            'ALTER TABLE $tableOrder ADD COLUMN order_type TEXT DEFAULT "DINE IN"');
        log("Added order_type column to orders table");
      } catch (e) {
        log("order_type column might already exist: $e");
      }
    }
  }

  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDB('dbresto36.db');
    return _database!;
  }

  //save order
  Future<int> saveOrder(OrderModel order) async {
    final db = await instance.database;

    // Since we're forcing database recreation, order_type column should exist
    final orderMap = order.toMap(includeOrderType: true);
    log("Final orderMap for insertion: $orderMap");

    int id = await db.insert(tableOrder, orderMap,
        conflictAlgorithm: ConflictAlgorithm.replace);

    for (var item in order.orderItems) {
      log("Item: ${item.toLocalMap(id)}");
      await db.insert(tableOrderItem, item.toLocalMap(id),
          conflictAlgorithm: ConflictAlgorithm.replace);
    }
    log("Success Order: ${order.toMap()}");
    return id;
  }

  //get data order
  Future<List<OrderModel>> getOrderByIsNotSync() async {
    final db = await instance.database;
    final List<Map<String, dynamic>> maps =
        await db.query(tableOrder, where: 'is_sync = ?', whereArgs: [0]);
    return List.generate(maps.length, (i) {
      return OrderModel.fromMap(maps[i]);
    });
  }

  Future<List<OrderModel>> getAllOrder(
    DateTime date,
  ) async {
    final db = await instance.database;
    //date to iso8601
    final dateIso = date.toIso8601String();
    //get yyyy-MM-dd
    final dateYYYYMMDD = dateIso.substring(0, 10);
    // final formattedDate = DateFormat('yyyy-MM-dd').format(date);
    final List<Map<String, dynamic>> maps = await db.query(
      tableOrder,
      where: 'transaction_time like ?',
      whereArgs: ['$dateYYYYMMDD%'],
      // where: 'transaction_time BETWEEN ? AND ?',
      // whereArgs: [
      //   DateFormat.yMd().format(start),
      //   DateFormat.yMd().format(end)
      // ],
    );
    return List.generate(maps.length, (i) {
      log("Save save OrderModel: ${OrderModel.fromMap(maps[i])}");
      return OrderModel.fromMap(maps[i]);
    });
  }

  Future<List<OrderModel>> getAllOrderByRange(
      DateTime start, DateTime end) async {
    final db = await instance.database;

    // Format ke ISO 8601 untuk range, hasil: yyyy-MM-ddTHH:mm:ss
    final startIso = start.toIso8601String();
    final endIso = end.toIso8601String();

    final startDateYYYYMMDD = startIso.substring(0, 10);
    final endDateYYYYMMDD = endIso.substring(0, 10);

    final List<Map<String, dynamic>> maps = await db.query(
      tableOrder,
      where: 'substr(transaction_time, 1, 10) BETWEEN ? AND ?',
      whereArgs: [startDateYYYYMMDD, endDateYYYYMMDD],
      orderBy: 'transaction_time DESC',
    );
    log("Get All Order By Range: $startDateYYYYMMDD $endDateYYYYMMDD");

    return List.generate(maps.length, (i) {
      log("Save save OrderModel: ${OrderModel.fromMap(maps[i])}");
      return OrderModel.fromMap(maps[i]);
    });
  }

  //get order item by order id
  Future<List<ProductQuantity>> getOrderItemByOrderId(int orderId) async {
    final db = await instance.database;
    final List<Map<String, dynamic>> maps = await db
        .query(tableOrderItem, where: 'id_order = ?', whereArgs: [orderId]);
    return List.generate(maps.length, (i) {
      log("ProductQuantity: ${ProductQuantity.fromLocalMap(maps[i])}");
      return ProductQuantity.fromLocalMap(maps[i]);
    });
  }

  //update payment status by order id
  Future<void> updatePaymentStatus(
      int orderId, String paymentStatus, String status) async {
    final db = await instance.database;
    await db.update(
        tableOrder, {'payment_status': paymentStatus, 'status': status},
        where: 'id = ?', whereArgs: [orderId]);
    log('update payment status success | order id: $orderId | payment status: $paymentStatus | status: $status');
  }

  //update order is sync
  Future<void> updateOrderIsSync(int orderId) async {
    final db = await instance.database;
    await db.update(tableOrder, {'is_sync': 1},
        where: 'id = ?', whereArgs: [orderId]);
  }

  //insert data product

  Future<void> insertProduct(Product product) async {
    log("Product: ${product.toMap()}");
    final db = await instance.database;
    await db.insert(tableProduct, product.toMap(),
        conflictAlgorithm: ConflictAlgorithm.replace);
  }

  //update product
  Future<void> updateProduct(Product product) async {
    log("Update Product: ${product.toMap()}");
    final db = await instance.database;
    await db.update(
      tableProduct,
      product.toLocalMap(),
      where: 'product_id = ?',
      whereArgs: [product.productId],
    );
  }

  //insert list of product
  Future<void> insertProducts(List<Product> products) async {
    final db = await instance.database;
    log("Save Products to Local");
    for (var product in products) {
      await db.insert(tableProduct, product.toLocalMap(),
          conflictAlgorithm: ConflictAlgorithm.replace);
      log('inserted success id: ${product.productId} | name: ${product.name} | price: ${product.price} | Printer Type ${product.printerType}');
    }
  }

  //get all products
  Future<List<Product>> getProducts() async {
    final db = await instance.database;
    final List<Map<String, dynamic>> maps = await db.query(tableProduct);
    return List.generate(maps.length, (i) {
      return Product.fromLocalMap(maps[i]);
    });
  }

  Future<Product?> getProductById(int id) async {
    final db = await instance.database;
    final result =
        await db.query(tableProduct, where: 'product_id = ?', whereArgs: [id]);

    if (result.isEmpty) {
      return null;
    }

    return Product.fromMap(result.first);
  }

  // get Last Table Management

  Future<TableModel?> getLastTableManagement() async {
    final db = await instance.database;
    final List<Map<String, dynamic>> maps =
        await db.query(tableManagement, orderBy: 'id DESC', limit: 1);
    if (maps.isEmpty) {
      return null;
    }
    return TableModel.fromMap(maps[0]);
  }

  // generate table managent with count
  Future<void> createTableManagement(String tableName, Offset position) async {
    final db = await instance.database;
    TableModel newTable = TableModel(
      tableName: tableName,
      status: 'available',
      orderId: 0,
      paymentAmount: 0,
      startTime: DateTime.now().toIso8601String(),
      position: position,
    );
    await db.insert(
      tableManagement,
      newTable.toMap(),
    );
  }

  // change position table
  Future<void> changePositionTable(int id, Offset position) async {
    final db = await instance.database;
    await db.update(
      tableManagement,
      {'x_position': position.dx, 'y_position': position.dy},
      where: 'id = ?',
      whereArgs: [id],
    );
  }

  // update table
  Future<void> updateTable(TableModel table) async {
    final db = await instance.database;
    await db.update(
      tableManagement,
      table.toMap(),
      where: 'id = ?',
      whereArgs: [table.id],
    );
  }

  // get all table
  Future<List<TableModel>> getAllTable() async {
    final db = await instance.database;
    final List<Map<String, dynamic>> maps = await db.query(tableManagement);
    log("Table Management: $maps");
    return List.generate(maps.length, (i) {
      return TableModel.fromMap(maps[i]);
    });
  }

  // get last order where table number
  Future<OrderModel?> getLastOrderTable(int tableNumber) async {
    final db = await instance.database;
    final List<Map<String, dynamic>> maps = await db.query(
      tableOrder,
      where: 'table_number = ?',
      whereArgs: [tableNumber],
      orderBy: 'id DESC', // Urutkan berdasarkan id dari yang terbesar (terbaru)
      limit: 1, // Ambil hanya satu data terakhir
    );

    if (maps.isEmpty) {
      return null;
    }

    return OrderModel.fromMap(maps[0]);
  }

  // get table by status
  Future<List<TableModel>> getTableByStatus(String status) async {
    final db = await instance.database;
    List<Map<String, dynamic>> maps;

    if (status == 'all') {
      // Get all tables
      maps = await db.query(tableManagement);
      log("Getting all tables, found: ${maps.length}");

      // If no tables exist, create some default tables
      if (maps.isEmpty) {
        log("No tables found, creating default tables...");
        await _createDefaultTables();
        maps = await db.query(tableManagement);
        log("After creating default tables, found: ${maps.length}");
      }
    } else {
      // Get tables by specific status
      maps = await db.query(
        tableManagement,
        where: 'status = ?',
        whereArgs: [status],
      );
      log("Getting tables with status '$status', found: ${maps.length}");
    }

    final tables = List.generate(maps.length, (i) {
      return TableModel.fromMap(maps[i]);
    });

    log("Returning ${tables.length} tables");
    tables.forEach((table) {
      log("Table: ${table.tableName} (ID: ${table.id}, Status: ${table.status})");
    });

    return tables;
  }

  // Create default tables if none exist
  Future<void> _createDefaultTables() async {
    final db = await instance.database;

    // Create 5 default tables
    for (int i = 1; i <= 5; i++) {
      await db.insert(tableManagement, {
        'table_name': 'Table $i',
        'start_time': DateTime.now().toIso8601String(),
        'order_id': 0,
        'payment_amount': 0,
        'x_position': 100.0 + (i * 50.0),
        'y_position': 100.0 + (i * 50.0),
        'status': 'available',
      });
      log("Created default table: Table $i");
    }
  }

  // update status tabel
  Future<void> updateStatusTable(TableModel table) async {
    log("Updating table status: ${table.toMap()}");
    final db = await instance.database;
    await db.update(tableManagement, table.toMap(),
        where: 'id = ?', whereArgs: [table.id]);
    log("Success Update Status Table: ${table.toMap()}");

    // Verify the update
    final updatedTable = await db.query(
      tableManagement,
      where: 'id = ?',
      whereArgs: [table.id],
    );
    if (updatedTable.isNotEmpty) {
      log("Verified table update: ${updatedTable.first}");
    }
  }

  // Debug method to reset all tables to available status
  Future<void> resetAllTablesToAvailable() async {
    log("Resetting all tables to available status...");
    final db = await instance.database;
    await db.update(
      tableManagement,
      {
        'status': 'available',
        'order_id': 0,
        'payment_amount': 0,
        'start_time': DateTime.now().toIso8601String(),
      },
    );
    log("All tables reset to available status");
  }

  //delete all products
  Future<void> deleteAllProducts() async {
    final db = await instance.database;
    await db.delete(tableProduct);
  }

  Future<int> saveDraftOrder(DraftOrderModel order) async {
    log("save draft order: ${order.toMapForLocal()}");
    final db = await instance.database;
    int id = await db.insert('draft_orders', order.toMapForLocal());
    log("draft order id: $id | ${order.discountAmount}");
    for (var orderItem in order.orders) {
      await db.insert('draft_order_items', orderItem.toMapForLocal(id));
      log("draft order item  ${orderItem.toMapForLocal(id)}");
    }

    return id;
  }

  //get all draft order
  Future<List<DraftOrderModel>> getAllDraftOrder() async {
    final db = await instance.database;
    final result = await db.query('draft_orders', orderBy: 'id ASC');

    List<DraftOrderModel> results = await Future.wait(result.map((item) async {
      // Your asynchronous operation here
      final draftOrderItem =
          await getDraftOrderItemByOrderId(item['id'] as int);
      return DraftOrderModel.newFromLocalMap(item, draftOrderItem);
    }));
    return results;
  }

  // get Darft Order by id
  Future<DraftOrderModel?> getDraftOrderById(int id) async {
    final db = await instance.database;
    final result =
        await db.query('draft_orders', where: 'id = ?', whereArgs: [id]);
    if (result.isEmpty) {
      return null;
    }
    final draftOrderItem =
        await getDraftOrderItemByOrderId(result.first['id'] as int);
    log("draft order item: $draftOrderItem | ${result.first.toString()}");
    return DraftOrderModel.newFromLocalMap(result.first, draftOrderItem);
  }

  //get draft order item by id order
  Future<List<DraftOrderItem>> getDraftOrderItemByOrderId(int idOrder) async {
    final db = await instance.database;
    final result =
        await db.query('draft_order_items', where: 'id_draft_order = $idOrder');

    List<DraftOrderItem> results = await Future.wait(result.map((item) async {
      // Your asynchronous operation here
      final product = await getProductById(item['id_product'] as int);
      return DraftOrderItem(
          product: product!, quantity: item['quantity'] as int);
    }));
    return results;
  }

  //remove draft order by id
  Future<void> removeDraftOrderById(int id) async {
    final db = await instance.database;
    await db.delete('draft_orders', where: 'id = ?', whereArgs: [id]);
    await db.delete('draft_order_items',
        where: 'id_draft_order = ?', whereArgs: [id]);
  }

  //update draft order
  Future<void> updateDraftOrder(DraftOrderModel draftOrder) async {
    final db = await instance.database;

    // Update the draft order
    await db.update(
      'draft_orders',
      draftOrder.toMapForLocal(),
      where: 'id = ?',
      whereArgs: [draftOrder.id],
    );

    // Remove existing items and add new ones
    await db.delete('draft_order_items',
        where: 'id_draft_order = ?', whereArgs: [draftOrder.id]);

    for (var orderItem in draftOrder.orders) {
      await db.insert(
          'draft_order_items', orderItem.toMapForLocal(draftOrder.id!));
    }
  }

  /// create printer
  Future<void> createPrinter(PrintModel print) async {
    final db = await instance.database;
    await db.insert(tablePrint, print.toMap());
  }

  Future<void> updatePrinter(PrintModel print, int id) async {
    final db = await instance.database;
    log("Update Printer: ${print.toMap()} | id: $id");
    await db
        .update(tablePrint, print.toMap(), where: 'id = ?', whereArgs: [id]);
  }

  Future<void> deletePrinter(int id) async {
    final db = await instance.database;
    await db.delete(tablePrint, where: 'id = ?', whereArgs: [id]);
  }

  // get printer by code
  Future<PrintModel?> getPrinterByCode(String code) async {
    final db = await instance.database;
    final result =
        await db.query(tablePrint, where: 'code = ?', whereArgs: [code]);
    if (result.isEmpty) {
      return null;
    }
    return PrintModel.fromMap(result.first);
  }
}
