"""Small sqlite compatibility layer for CPython and MicroPython.

The module exposes a tiny wrapper around the available sqlite driver so the
same code can run on CPython (`sqlite3`) and MicroPython (`sqlite3` or
`usqlite`, depending on the port).
"""

try:
	import sqlite3 as _sqlite
	DRIVER_NAME = "sqlite3"
except ImportError:
	try:
		import usqlite as _sqlite
		DRIVER_NAME = "usqlite"
	except ImportError as exc:
		raise ImportError("No sqlite driver found. Expected sqlite3 or usqlite.") from exc


def _connect(database_path, **connect_kwargs):
	if connect_kwargs:
		try:
			return _sqlite.connect(database_path, **connect_kwargs)
		except TypeError:
			pass
	return _sqlite.connect(database_path)


class Database:
	"""Lightweight connection wrapper with a consistent API."""

	def __init__(self, database_path, **connect_kwargs):
		self._database_path = database_path
		self._connect_kwargs = connect_kwargs
		self._connection = None

	def open(self):
		if self._connection is None:
			self._connection = _connect(self._database_path, **self._connect_kwargs)
		return self._connection

	def close(self):
		if self._connection is not None:
			self._connection.close()
			self._connection = None

	def commit(self):
		connection = self.open()
		if hasattr(connection, "commit"):
			connection.commit()

	def cursor(self):
		return self.open().cursor()

	def execute(self, sql, params=None):
		cursor = self.cursor()
		if params is None:
			cursor.execute(sql)
		else:
			cursor.execute(sql, params)
		return cursor

	def executemany(self, sql, params_list):
		cursor = self.cursor()
		cursor.executemany(sql, params_list)
		return cursor

	def fetchone(self, sql, params=None):
		return self.execute(sql, params).fetchone()

	def fetchall(self, sql, params=None):
		return self.execute(sql, params).fetchall()

	def executescript(self, script):
		connection = self.open()
		if hasattr(connection, "executescript"):
			return connection.executescript(script)
		raise NotImplementedError("executescript is not available on this sqlite backend")

	def __enter__(self):
		self.open()
		return self

	def __exit__(self, exc_type, exc, traceback):
		if exc_type is None:
			self.commit()
		self.close()


def connect(database_path, **connect_kwargs):
	return Database(database_path, **connect_kwargs)


def execute(database_path, sql, params=None, **connect_kwargs):
	return connect(database_path, **connect_kwargs).execute(sql, params)


def fetchone(database_path, sql, params=None, **connect_kwargs):
	return connect(database_path, **connect_kwargs).fetchone(sql, params)


def fetchall(database_path, sql, params=None, **connect_kwargs):
	return connect(database_path, **connect_kwargs).fetchall(sql, params)
