"""
this is from bw2data sqlite, but is not in all version of bw2data
"""
import json
import pickle
from pathlib import Path

from peewee import BlobField, SqliteDatabase, TextField


class PickleField(BlobField):
    def db_value(self, value):
        return super(PickleField, self).db_value(pickle.dumps(value, protocol=4))

    def python_value(self, value):
        return pickle.loads(bytes(value))


class SubstitutableDatabase:
    def __init__(self, filepath, tables):
        self._filepath = filepath
        self._tables = tables
        self._database = self._create_database()

    def _create_database(self):
        db = SqliteDatabase(self._filepath)
        for model in self._tables:
            model.bind(db, bind_refs=False, bind_backrefs=False)
        db.connect()
        db.create_tables(self._tables)
        return db

    @property
    def db(self):
        return self._database

    def change_path(self, filepath):
        self.db.close()
        self._filepath = filepath
        self._database = self._create_database()

    def atomic(self):
        return self.db.atomic()

    def execute_sql(self, *args, **kwargs):
        return self.db.execute_sql(*args, **kwargs)

    def transaction(self):
        return self.db.transaction()

    def vacuum(self):
        print("Vacuuming database ")
        self.execute_sql("VACUUM;")


class JSONField(TextField):
    """Simpler JSON field that doesn't support advanced querying and is human-readable"""

    def db_value(self, value):
        return super().db_value(
            json.dumps(
                value,
                ensure_ascii=False,
                indent=2,
                default=lambda x: x.isoformat() if hasattr(x, "isoformat") else x,
            )
        )

    def python_value(self, value):
        return json.loads(value)


class TupleJSONField(JSONField):
    def python_value(self, value):
        data = json.loads(value)
        if isinstance(data, list):
            data = tuple(data)
        return data


class PathField(TextField):
    def db_value(self, value):
        if value is not None:
            return str(value)

    def python_value(self, value):
        if value is not None:
            return Path(value)
