/*
 * 版权所有 (c) 2010-2011，MiCode 开源社区 (www.micode.net)
 * 根据 Apache 许可证 2.0 版本（"许可证"）授权；
 * 除非符合许可证的规定，否则不得使用本文件。
 * 您可以从以下网址获取许可证副本：
 * http://www.apache.org/licenses/LICENSE-2.0
 * 除非适用法律要求或书面同意，本软件按"原样"分发，
 * 没有任何明示或暗示的保证或条件。
 * 详见许可证中规定的权限和限制。
 * （注：这是一份标准的Apache许可证2.0版本的开源声明）
 */

// 定义当前类所在的包路径
package net.micode.notes.gtask.data;

// 导入Android内容提供者相关类
import android.content.ContentResolver;   // 内容解析器，用于访问ContentProvider
import android.content.ContentUris;       // 用于构建带有ID的URI
import android.content.ContentValues;     // 键值对存储，用于数据库操作
import android.content.Context;          // 应用上下文
import android.database.Cursor;          // 数据库查询结果集
import android.net.Uri;                  // 通用资源标识符
import android.os.Build;                 // 获取Android版本信息
import android.util.Log;                 // 日志工具

// 导入AndroidX注解（版本检查）
import androidx.annotation.RequiresApi;

// 导入笔记应用数据相关常量
import net.micode.notes.data.Notes;             // 笔记数据常量
import net.micode.notes.data.Notes.DataColumns;       // 数据列名常量
import net.micode.notes.data.Notes.DataConstants;     // 数据相关常量
import net.micode.notes.data.Notes.NoteColumns;        // 笔记列名常量
import net.micode.notes.data.NotesDatabaseHelper.TABLE;  // 数据库表名
// 导入同步异常类
import net.micode.notes.gtask.exception.ActionFailureException;

// 导入JSON处理相关类
import org.json.JSONException;   // JSON异常
import org.json.JSONObject;      // JSON对象

// 导入Java工具类
import java.util.Objects;   // 对象工具类

/**
 * SqlData类 - 处理笔记数据的SQLite数据库操作
 * 功能：
 * 1. 封装笔记数据的增删改查操作
 * 2. 管理本地数据与JSON格式的相互转换
 * 3. 处理数据版本控制
 */
public class SqlData {
    // 日志标签
    private static final String TAG = SqlData.class.getSimpleName();

    // 无效ID常量
    private static final int INVALID_ID = -99999;

    // 数据查询的列投影（指定需要查询的列）
    public static final String[] PROJECTION_DATA = new String[] {
            DataColumns.ID,         // 数据ID
            DataColumns.MIME_TYPE,  // MIME类型
            DataColumns.CONTENT,    // 内容
            DataColumns.DATA1,      // 扩展数据1
            DataColumns.DATA3       // 扩展数据3
    };

    // 列索引常量
    public static final int DATA_ID_COLUMN = 0;            // ID列索引
    public static final int DATA_MIME_TYPE_COLUMN = 1;     // MIME类型列索引
    public static final int DATA_CONTENT_COLUMN = 2;      // 内容列索引
    public static final int DATA_CONTENT_DATA_1_COLUMN = 3; // 扩展数据1列索引
    public static final int DATA_CONTENT_DATA_3_COLUMN = 4; // 扩展数据3列索引

    // 内容解析器实例
    private final ContentResolver mContentResolver;

    // 是否为新创建数据的标志
    private boolean mIsCreate;

    // 数据字段
    private long mDataId;           // 数据ID
    private String mDataMimeType;   // MIME类型
    private String mDataContent;     // 内容
    private long mDataContentData1; // 扩展数据1（长整型）
    private String mDataContentData3; // 扩展数据3（字符串）

    // 存储有变动的数据值（用于增量更新）
    private final ContentValues mDiffDataValues;

    /**
     * 构造函数（用于创建新数据）
     * @param context 应用上下文
     */
    public SqlData(Context context) {
        mContentResolver = context.getContentResolver();
        mIsCreate = true;          // 标记为新创建
        mDataId = INVALID_ID;      // 初始化无效ID
        mDataMimeType = DataConstants.NOTE; // 默认MIME类型
        mDataContent = "";         // 空内容
        mDataContentData1 = 0;     // 默认扩展数据1
        mDataContentData3 = "";    // 空扩展数据3
        mDiffDataValues = new ContentValues(); // 初始化变更集合
    }

    /**
     * 构造函数（基于Cursor加载已有数据）
     * @param context 应用上下文
     * @param c 数据库Cursor对象
     */
    public SqlData(Context context, Cursor c) {
        mContentResolver = context.getContentResolver();
        mIsCreate = false;         // 标记为已存在数据
        loadFromCursor(c);         // 从Cursor加载数据
        mDiffDataValues = new ContentValues(); // 初始化变更集合
    }

    /**
     * 从Cursor加载数据
     * @param c 数据库Cursor对象
     */
    private void loadFromCursor(Cursor c) {
        mDataId = c.getLong(DATA_ID_COLUMN);
        mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);
        mDataContent = c.getString(DATA_CONTENT_COLUMN);
        mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN);
        mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN);
    }

    /**
     * 设置内容（从JSON对象）
     * @param js 包含数据的JSON对象
     * @throws JSONException JSON解析异常
     */
    public void setContent(JSONObject js) throws JSONException {
        // 处理数据ID
        long dataId = js.has(DataColumns.ID)  ? js.getLong(DataColumns.ID)  : INVALID_ID;
        if (mIsCreate || mDataId != dataId) {
            mDiffDataValues.put(DataColumns.ID,  dataId);
        }
        mDataId = dataId;

        // 处理MIME类型
        String dataMimeType = js.has(DataColumns.MIME_TYPE)  ? js.getString(DataColumns.MIME_TYPE)
                : DataConstants.NOTE;
        if (mIsCreate || !mDataMimeType.equals(dataMimeType))  {
            mDiffDataValues.put(DataColumns.MIME_TYPE,  dataMimeType);
        }
        mDataMimeType = dataMimeType;

        // 处理内容
        String dataContent = js.has(DataColumns.CONTENT)  ? js.getString(DataColumns.CONTENT)  : "";
        if (mIsCreate || !mDataContent.equals(dataContent))  {
            mDiffDataValues.put(DataColumns.CONTENT,  dataContent);
        }
        mDataContent = dataContent;

        // 处理扩展数据1
        long dataContentData1 = js.has(DataColumns.DATA1)  ? js.getLong(DataColumns.DATA1)  : 0;
        if (mIsCreate || mDataContentData1 != dataContentData1) {
            mDiffDataValues.put(DataColumns.DATA1,  dataContentData1);
        }
        mDataContentData1 = dataContentData1;

        // 处理扩展数据3
        String dataContentData3 = js.has(DataColumns.DATA3)  ? js.getString(DataColumns.DATA3)  : "";
        if (mIsCreate || !mDataContentData3.equals(dataContentData3))  {
            mDiffDataValues.put(DataColumns.DATA3,  dataContentData3);
        }
        mDataContentData3 = dataContentData3;
    }

    /**
     * 获取内容（转换为JSON对象）
     * @return 包含数据的JSON对象
     * @throws JSONException JSON构造异常
     */
    public JSONObject getContent() throws JSONException {
        if (mIsCreate) {
            Log.e(TAG, "it seems that we haven't created this in database yet");
            return null;
        }
        // 构建JSON对象
        JSONObject js = new JSONObject();
        js.put(DataColumns.ID,  mDataId);
        js.put(DataColumns.MIME_TYPE,  mDataMimeType);
        js.put(DataColumns.CONTENT,  mDataContent);
        js.put(DataColumns.DATA1,  mDataContentData1);
        js.put(DataColumns.DATA3,  mDataContentData3);
        return js;
    }

    /**
     * 提交数据到数据库
     * @param noteId 关联的笔记ID
     * @param validateVersion 是否验证版本
     * @param version 版本号（当validateVersion为true时使用）
     */
    @RequiresApi(api = Build.VERSION_CODES.R)
    public void commit(long noteId, boolean validateVersion, long version) {
        // 处理新建数据的情况
        if (mIsCreate) {
            // 如果ID无效且有ID变更，移除无效ID
            if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID))  {
                mDiffDataValues.remove(DataColumns.ID);
            }

            // 设置关联笔记ID
            mDiffDataValues.put(DataColumns.NOTE_ID,  noteId);
            // 插入新数据
            Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI,  mDiffDataValues);
            try {
                // 从返回的URI中解析出新数据的ID
                mDataId = Long.parseLong(Objects.requireNonNull(uri).getPathSegments().get(1));
            } catch (NumberFormatException e) {
                Log.e(TAG, "Get note id error :" + e);
                throw new ActionFailureException("create note failed");
            }
        } else {
            // 处理更新已有数据的情况
            if (!mDiffDataValues.isEmpty())  {
                int result;
                if (!validateVersion) {
                    // 不验证版本的普通更新
                    result = mContentResolver.update(
                            ContentUris.withAppendedId(Notes.CONTENT_DATA_URI,  mDataId),
                            mDiffDataValues,
                            null,
                            null
                    );
                } else {
                    // 带版本验证的更新
                    result = mContentResolver.update(
                            ContentUris.withAppendedId(Notes.CONTENT_DATA_URI,  mDataId),
                            mDiffDataValues,
                            " ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE
                                    + " WHERE " + NoteColumns.VERSION + "=?)",
                            new String[] { String.valueOf(noteId),  String.valueOf(version)  }
                    );
                }
                if (result == 0) {
                    Log.w(TAG, "there is no update. maybe user updates note when syncing");
                }
            }
        }

        // 重置状态
        mDiffDataValues.clear();
        mIsCreate = false;
    }
    /**
     * 获取数据ID
     * @return 数据ID
     */
    public long getId() {
        return mDataId;
    }
}
