import 'dart:core';
import 'dart:io';
import 'package:e_commerce_training/src/model/response/product_detail_response.dart';
import 'package:e_commerce_training/src/util/logger.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';

class DatabaseHelper {
  static final DatabaseHelper _instance = DatabaseHelper._();

  static Database? _database;

  DatabaseHelper._();

  factory DatabaseHelper() {
    return _instance;
  }

  Future<Database> init() async {
    Directory directory = await getApplicationDocumentsDirectory();
    String dbPath = p.join(directory.toString(), 'shopping_cart.db');
    var database = openDatabase(dbPath,
        version: 1, onCreate: _onCreate, onUpgrade: _onUpgrade);
    return database;
  }

  Future<Database?> get db async {
    if (_database != null) {
      return _database;
    }
    _database = await init();

    return _database;
  }

  Future<void> _onCreate(Database db, int version) async {
    await db.execute(
        'CREATE TABLE cart(id INT PRIMARY KEY, name TEXT, price REAL, discount REAL, imageUrl TEXT, count INT, isMark INT, sku_id INT, sku_code TEXT)');
    print("Database was created!");
  }

  void _onUpgrade(Database db, int oldVersion, int newVersion) {
    // Run migration according database versions
    logger.i(
      "Migration: $oldVersion, $newVersion",
    );
    if (oldVersion == 1 && newVersion == 2) {
      db.execute('ALTER TABLE cart ADD COLUMN attributes TEXT');
      db.delete("cart");
//        db.execute('ALTER TABLE product ADD COLUMN unit TEXT');
    }
    db.execute('DROP TABLE IF EXISTS product');
    db.delete("cart");
  }

  Future<void> addProduct(DetailProductData product) async {
    var client = await db;
    DetailProductData? oldProduct = await fetchProduct(product.itemId!);
    if (oldProduct == null)
      await client!.insert('cart', product.toJson(),
          conflictAlgorithm: ConflictAlgorithm.replace);
    else {
      //oldProduct.rowNumber = product.rowNumber!;
      await updateProduct(oldProduct);
    }
  }

  Future<List<DetailProductData>> fetchAllProduct() async {
    var client = await db;
    var res = await client!.query('cart');
    if (res.isNotEmpty) {
      var products = res
          .map((productMap) => DetailProductData.fromJson(productMap))
          .toList();
      return products;
    }
    return [];
  }

  Future<void> decreaseProduct(DetailProductData product) async {
    if (product.rowNumber! > 1) {
      product.rowNumber! - 1;
      updateProduct(product);
    }
  }

  Future<void> increaseProduct(DetailProductData product) async {
     product.rowNumber! + 1;
    updateProduct(product);
  }

  Future<DetailProductData?> fetchProduct(int id) async {
    var client = await db;
    final Future<List<Map<String, dynamic>>> futureMaps =
        client!.query('cart', where: 'id = ?', whereArgs: [id]);
    var maps = await futureMaps;
    if (maps.length != 0) {
      return DetailProductData.fromJson(maps.first);
    }
    return null;
  }

  Future<void> deleteAllProduct() async {
    var client = await db;
    await client!.delete('cart');
  }

  Future<List<DetailProductData>> getAllProductSelected() async {
    var client = await db;
    var res = await client!.query('cart', where: 'isMark = ?', whereArgs: [1]);

    if (res.isNotEmpty) {
      var products = res
          .map((productMap) => DetailProductData.fromJson(productMap))
          .toList();
      return products;
    }
    return [];
  }

  Future<void> deleteProductSelected() async {
    var client = await db;
    await client!.delete('cart', where: 'isMark = ?', whereArgs: [1]);
  }

  Future<int> updateProduct(DetailProductData pr) async {
    var client = await db;
    return client!.update('cart', pr.toJson(),
        where: 'id = ?',
        whereArgs: [pr.itemId],
        conflictAlgorithm: ConflictAlgorithm.replace);
  }

  Future<int> removeProduct(int id) async {
    var client = await db;
    return client!.delete('cart', where: 'id = ?', whereArgs: [id]);
  }

  Future<List<Map<String, dynamic>>> countProduct({Database? database}) async {
    var client = database ?? await db;
    return client!.rawQuery('SELECT COUNT (id) FROM cart', null);
  }

  Future<int> getCountProduct({Database? database}) async {
    var client = database ?? await db;
    var countDb = await countProduct(database: client);
    if (countDb == null) return 0;
    return countDb[0]['COUNT (id)'];
  }

  Future closeDb() async {
    var client = await db;
    client!.close();
  }
}
