package com.unibuy.smartdevice.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.unibuy.smartdevice.MyApp;
import com.unibuy.smartdevice.devices.SlotField;
import com.unibuy.smartdevice.exception.Logs;
import com.unibuy.smartdevice.exception.LogsNoSuchElementException;
import com.unibuy.smartdevice.structure.ProductStructure;
import com.unibuy.smartdevice.structure.SlotStructure;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SlotsDao {
    private Logs logs;
    private final SQLiteDatabase database;

    public SlotsDao(Context context) {
        logs = new Logs(this.getClass());
        DatabaseHelper dbHelper = new DatabaseHelper(context);
        database = dbHelper.getWritableDatabase();
    }

    // 插入單一 Product
    public void insertOne(SlotStructure data) {
        ContentValues values = new ContentValues();
        values.put(DatabaseHelper.slot.FIELD.getName(), data.getField());
        values.put(DatabaseHelper.slot.SLOT.getName(), data.getSlot());
        values.put(DatabaseHelper.slot.PRODUCT_ID.getName(), data.getProduct().getProductID());
        values.put(DatabaseHelper.slot.COUNT.getName(), data.getCount());
        values.put(DatabaseHelper.slot.LOCK.getName(), data.isLock());
        values.put(DatabaseHelper.slot.OTHER_DATA.getName(), data.getOtherData().toString());
        values.put(DatabaseHelper.slot.LOCK_REV.getName(), data.getLockRev());
        values.put(DatabaseHelper.slot.LOCK_SYNCED_REV.getName(), data.getLockSyncedRev());
        values.put(DatabaseHelper.slot.EXPIRY_REV.getName(), data.getExpiryRev());
        values.put(DatabaseHelper.slot.EXPIRY_SYNCED_REV.getName(), data.getExpirySyncedRev());

        database.insert(DatabaseHelper.slot.TABLE.getName(), null, values);
    }

    /**
     * 單行更新一個貨道（count/lock/otherData/4 個 rev），依 field+slot 定位。
     * 取代 MQTT 下行/局部更新時 deleteAll()+insertAll() 全表重寫，避免與 UI 存檔互相 race。
     */
    public void updateSlot(SlotStructure data) {
        ContentValues values = new ContentValues();
        values.put(DatabaseHelper.slot.PRODUCT_ID.getName(), data.getProduct().getProductID());
        values.put(DatabaseHelper.slot.COUNT.getName(), data.getCount());
        values.put(DatabaseHelper.slot.LOCK.getName(), data.isLock());
        values.put(DatabaseHelper.slot.OTHER_DATA.getName(), data.getOtherData() != null ? data.getOtherData().toString() : "{}");
        values.put(DatabaseHelper.slot.LOCK_REV.getName(), data.getLockRev());
        values.put(DatabaseHelper.slot.LOCK_SYNCED_REV.getName(), data.getLockSyncedRev());
        values.put(DatabaseHelper.slot.EXPIRY_REV.getName(), data.getExpiryRev());
        values.put(DatabaseHelper.slot.EXPIRY_SYNCED_REV.getName(), data.getExpirySyncedRev());

        String whereClause = DatabaseHelper.slot.FIELD.getName() + "=? AND " + DatabaseHelper.slot.SLOT.getName() + "=?";
        String[] whereArgs = { String.valueOf(data.getField()), String.valueOf(data.getSlot()) };
        database.update(DatabaseHelper.slot.TABLE.getName(), values, whereClause, whereArgs);
    }

    // 更新指定 field 和 slot 的數量（count）
    public void updateCount(int field, int slot, int newCount) {
        ContentValues values = new ContentValues();
        values.put(DatabaseHelper.slot.COUNT.getName(), newCount);

        String whereClause = DatabaseHelper.slot.FIELD.getName() + "=? AND " + DatabaseHelper.slot.SLOT.getName() + "=?";
        String[] whereArgs = { String.valueOf(field), String.valueOf(slot) };

        database.update(DatabaseHelper.slot.TABLE.getName(), values, whereClause, whereArgs);
    }


    // 批量插入 Products
    public void insertAll(Map<Integer, List<SlotStructure>> slotMap) {
        if (slotMap.size() == 0) {
            return;
        }

        database.beginTransaction();
        try {
            for(SlotField slotField: SlotField.values()) {
                if (slotMap.containsKey(slotField.getField())) {
                    List<SlotStructure> slotList = slotMap.get(slotField.getField());
                    for (SlotStructure data : slotList) {
                        insertOne(data);
                    }
                }
            }

            database.setTransactionSuccessful();
        } finally {
            database.endTransaction();
        }
    }

    /**
     * 以單一交易「清空後重建」整個 slot 表，避免 deleteAll() 與 insertAll() 之間的空窗被其他連線讀到空表，
     * 或與背景下行寫入互相覆蓋。供 UI 存檔使用。
     */
    public void replaceAll(Map<Integer, List<SlotStructure>> slotMap) {
        database.beginTransaction();
        try {
            database.delete(DatabaseHelper.slot.TABLE.getName(), null, null);
            for (SlotField slotField : SlotField.values()) {
                if (slotMap.containsKey(slotField.getField())) {
                    List<SlotStructure> slotList = slotMap.get(slotField.getField());
                    if (slotList == null) continue;
                    for (SlotStructure data : slotList) {
                        insertOne(data);
                    }
                }
            }
            database.setTransactionSuccessful();
        } finally {
            database.endTransaction();
        }
    }

    // 獲取所有 Products
    public Map<Integer, List<SlotStructure>> getAll() {
        Map<Integer, List<SlotStructure>> slotMap = new HashMap<>();

        Cursor cursor = database.query(
                DatabaseHelper.slot.TABLE.getName(),
                null, // 全部欄位
                null, // 無條件
                null,
                null,
                null,
                null);

        if (cursor != null) {
            while (cursor.moveToNext()) {
                int id = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseHelper.column.COLUMN_ID.getName()));
                int field = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseHelper.slot.FIELD.getName()));
                int slot = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseHelper.slot.SLOT.getName()));
                String productId = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseHelper.slot.PRODUCT_ID.getName()));
                int count = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseHelper.slot.COUNT.getName()));
                boolean lock = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseHelper.slot.LOCK.getName())) == 1;
                String otherData = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseHelper.slot.OTHER_DATA.getName()));
                int lockRev = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseHelper.slot.LOCK_REV.getName()));
                int lockSyncedRev = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseHelper.slot.LOCK_SYNCED_REV.getName()));
                int expiryRev = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseHelper.slot.EXPIRY_REV.getName()));
                int expirySyncedRev = cursor.getInt(cursor.getColumnIndexOrThrow(DatabaseHelper.slot.EXPIRY_SYNCED_REV.getName()));

                JSONObject jsonObject = new JSONObject();
                try {
                    jsonObject = new JSONObject(otherData);
                } catch (JSONException e) {}

                ProductStructure product = null;

                try {
                    product = MyApp.getInstance().getProduct(productId);
                } catch (LogsNoSuchElementException e) {
                    product = new ProductStructure("?", "","",0,0,0,8, "", "","","");
                }

                if (!slotMap.containsKey(field)) {
                    slotMap.put(field, new ArrayList<>());
                }

                SlotStructure slotData = new SlotStructure(field, slot, product, count, lock, jsonObject);
                slotData.setLockRev(lockRev);
                slotData.setLockSyncedRev(lockSyncedRev);
                slotData.setExpiryRev(expiryRev);
                slotData.setExpirySyncedRev(expirySyncedRev);
                slotMap.get(field).add(slotData);
            }
            cursor.close();
        }

        return slotMap;
    }

    // 刪除所有 Products
    public void deleteAll() {
        database.delete(DatabaseHelper.slot.TABLE.getName(), null, null);
    }

    // 關閉資料庫
    public void close() {
        database.close();
    }
}

