using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Sqlite3Plugin;

public class DBProxy : IDisposable
{
	public IntPtr DBHandle { get; private set; }

	public string dbPath { get; private set; }

	~DBProxy()
	{
		CloseDB();
	}

	public DBProxy()
	{
		dbPath = null;
		DBHandle = IntPtr.Zero;
	}

	public bool Open(string fileName, string vfsName = null)
	{
		dbPath = fileName;
		IntPtr ppDB = IntPtr.Zero;
		byte[] bytes = Encoding.UTF8.GetBytes(fileName + "\0");
		byte[] zVfs = null;
		if (!string.IsNullOrEmpty(vfsName))
		{
			zVfs = Encoding.UTF8.GetBytes(vfsName + "\0");
		}
		int num = Sqlite3LibImport.sqlite3_open_v2(bytes, out ppDB, 1, zVfs);
		DBHandle = ppDB;
		bool num2 = num == 0;
		if (num2)
		{
			Exec("pragma journal_mode=OFF");
			Exec("pragma synchronous=0");
			Exec("pragma locking_mode=EXCLUSIVE");
			return num2;
		}
		Debug.LogError("sqlite3_open failed: code " + num);
		return num2;
	}

	public bool OpenWritable(string fileName)
	{
		dbPath = fileName;
		IntPtr ppDB = IntPtr.Zero;
		bool flag = true;
		try
		{
			int num = Sqlite3LibImport.sqlite3_open(Encoding.UTF8.GetBytes(fileName + "\0"), out ppDB);
			DBHandle = ppDB;
			flag = num == 0;
			if (flag)
			{
				Exec("pragma journal_mode=MEMORY");
				Exec("pragma synchronous=1");
				Exec("pragma locking_mode=EXCLUSIVE");
			}
			else
			{
				Debug.LogError("sqlite3_open failed: " + num);
			}
		}
		catch (Exception ex)
		{
			if (ppDB != IntPtr.Zero)
			{
				Sqlite3LibImport.sqlite3_close(ppDB);
				DBHandle = IntPtr.Zero;
			}
			throw ex;
		}
		return flag;
	}

	public bool Begin()
	{
		return Exec("BEGIN;");
	}

	public bool Commit()
	{
		return Exec("COMMIT;");
	}

	public bool Rollback()
	{
		return Exec("ROLLBACK;");
	}

	public bool Vacuum()
	{
		return Exec("VACUUM;");
	}

	public virtual void Dispose()
	{
		CloseDB();
	}

	protected virtual void Dispose(bool disposing)
	{
		CloseDB();
	}

	private void Terminate()
	{
		CloseDB();
	}

	public virtual void CloseDB()
	{
		if (DBHandle != IntPtr.Zero)
		{
			int num = Sqlite3LibImport.sqlite3_close(DBHandle);
			if (num != 0)
			{
				Debug.LogError("failed to close db at " + dbPath + ": " + num);
			}
			DBHandle = IntPtr.Zero;
		}
	}

	public bool Exec(string sql)
	{
		byte[] bytes = Encoding.UTF8.GetBytes(sql + "\0");
		IntPtr pzErrMsg;
		int num = Sqlite3LibImport.sqlite3_exec(DBHandle, bytes, IntPtr.Zero, IntPtr.Zero, out pzErrMsg);
		if (num != 0)
		{
			string text = ((pzErrMsg == IntPtr.Zero) ? "" : Marshal.PtrToStringAnsi(pzErrMsg));
			Debug.LogError($"sqlite3_exec failed (code {num}: {text}) with sql: {sql}");
			ResultCode.CheckCorruption(num, text);
		}
		return num == 0;
	}

	public Query Query(string sql)
	{
		return new Query(this, sql);
	}

	public PreparedQuery PreparedQuery(string sql)
	{
		return new PreparedQuery(this, sql);
	}
}
