# -*- coding: utf-8 -*-

from quartzbio.resource.quartzbio_object import convert_to_quartzbio_object


class Fake201Response(object):
    status_code = 201
    class_name = None

    def __init__(self, data):
        self.object = {"id": data.get("id", 100), "class_name": self.class_name}

    def json(self):
        return self.object

    def create(self, *args, **kwargs):
        return convert_to_quartzbio_object(self.object)

    def save(self, *args, **kwargs):
        return self.create(*args, **kwargs)

    def retrieve(self, r_id, *args, **kwargs):
        obj = self.create()
        obj.id = r_id
        return obj

    def _retrieve_helper(self, model_name, field_name, error_value, *args, **kwargs):
        obj = self.create()
        for k, v in kwargs.items():
            obj[k] = v

        return obj

    def all(self, *args, **kwargs):
        class ExtendedList(list):
            def quartzbio_objects(self):
                return convert_to_quartzbio_object(self)

        return ExtendedList([self.create()])

    def update_paths(self):
        """Sets vault_name, path and full_path based on mock inputs"""
        if not self.object["vault_name"]:
            self.object["vault_name"] = "mock_vault"

        if not self.object["path"]:
            self.object["path"] = "/{0}".format(
                self.object.get("filename", self.object.get("vault_object_filename"))
            )

        if not self.object["full_path"]:
            self.object["full_path"] = "quartzbio:{0}:{1}".format(
                self.object["vault_name"], self.object["path"]
            )

    def update_dataset(self):
        """Sets dataset_id if object is a dataset"""
        if self.object["object_type"] == "dataset":
            self.object["dataset_id"] = self.object["id"]


class FakeMigrationResponse(Fake201Response):
    class_name = "DatasetMigration"

    def __init__(self, data):
        # Set the default properties of DatasetMigration
        self.object = {
            "class_name": self.class_name,
            "id": 100,
            "commit_mode": "append",
            "source": dict(id=data.get("source_id")),
            "source_params": {
                "fields": None,
                "route": None,
                "exclude_fields": None,
                "filters": None,
                "limit": None,
                "debug": False,
            },
            "target": dict(id=data.get("target_id")),
            "target_fields": [],
            "include_errors": False,
        }
        self.object.update(data)


class FakeExportResponse(Fake201Response):
    class_name = "DatasetExport"

    def __init__(self, data):
        # Set the default properties of DatasetExport
        self.object = {
            "class_name": self.class_name,
            "id": 100,
            "target_fields": [],
            "documents_count": 0,
            "dataset_id": data.get("dataset_id"),
            "dataset": dict(id=data.get("dataset_id")),
            "params": {
                "fields": None,
                "exclude_fields": None,
                "entities": None,
                "genome_build": None,
                "limit": None,
                "filters": None,
                "offset": None,
                "query": None,
                "debug": False,
            },
            "annotator_params": [],
            "metadata": {},
        }
        self.object.update(data)


class FakeVaultResponse(Fake201Response):
    class_name = "Vault"

    def __init__(self, data):
        self.object = {
            "class_name": self.class_name,
            "name": "test_vault",
            "require_unique_paths": True,
            "vault_type": "general",
            "provider": "QuartzBio",
            "id": 100,
            "full_path": "quartzbio:test_vault",
        }
        self.object.update(data)


class FakeObjectResponse(Fake201Response):
    class_name = "Object"

    def __init__(self, data):
        self.object = {
            "class_name": self.class_name,
            "id": 100,
            "parent_object_id": 99,
            "path": None,
            "full_path": None,
            "upload_url": None,
            "size": None,
            "md5": None,
            "filename": "file.json.gz",
            "path": None,
            "full_path": None,
            "vault_name": None,
            "vault_id": None,
            "object_type": "folder",
            "tags": [],
        }
        self.object.update(data)
        self.update_paths()
        self.update_dataset()


class FakeDatasetResponse(Fake201Response):
    class_name = "Dataset"

    def __init__(self, data):
        # Override default object options
        overrides = {
            "object_type": "dataset",
            "filename": data.get("name", "test-dataset"),
            "vault_object_name": data.get("name", "test-dataset"),
            "path": None,
            "full_path": None,
            "class_name": self.class_name,
        }
        data.update(overrides)
        self.object = FakeObjectResponse(data).object
        self.update_paths()


class FakeDatasetTemplateResponse(Fake201Response):
    class_name = "DatasetTemplate"

    def __init__(self, data):
        self.object = {
            "class_name": self.class_name,
            "name": None,
            "id": 100,
            "vault_parent_object_id": 99,
            "account": {
                "name": None,
                "domain": None,
            },
            "fields": None,
            "entity_type": None,
            "validation_params": None,
            "entity_params": None,
            "reader_params": None,
            "annotator_params": None,
        }
        self.object.update(data)


class FakeDatasetTask(Fake201Response):
    class_name = "DatasetTask"

    def __init__(self, data):
        self.object = {
            "class_name": self.class_name,
            "vault_id": None,
            "id": 100,
            "status": "completed",
            "dataset": FakeDatasetResponse(dict(name="fake_dataset")).object,  # noqa
            "account": {
                "name": None,
                "domain": None,
            },
        }
        self.object.update(data)


class FakeDatasetImport(FakeDatasetTask):
    class_name = "DatasetImport"

    def __init__(self, data):
        super(FakeDatasetImport, self).__init__(data)
        self.object["dataset_commits"] = []


def fake_vault_create(*args, **kwargs):
    return FakeVaultResponse(kwargs).create()


def fake_vault_all(*args, **kwargs):
    return FakeVaultResponse(kwargs).all()


def fake_object_all(*args, **kwargs):
    return FakeObjectResponse(kwargs).all()


def fake_object_create(*args, **kwargs):
    return FakeObjectResponse(kwargs).create()


def fake_object_save(*args, **kwargs):
    return FakeObjectResponse(kwargs).save()


def fake_object_retrieve(*args, **kwargs):
    return FakeObjectResponse(kwargs)._retrieve_helper("LogicalObject", *args, **kwargs)


def fake_dataset_create(*args, **kwargs):
    # Dataset.create() is deprecated
    print("WARNING: Your code likely wants to be using FakeObjectCreate.")
    return FakeDatasetResponse(kwargs).create()


def fake_dataset_get_or_create(*args, **kwargs):
    from quartzbio.resource import Object

    dataset_obj = FakeObjectResponse(kwargs).create()

    # Dataset.create requires a full_path, override with this
    full_path, path_dict = Object.validate_full_path(args[0])
    dataset_obj.name = path_dict["filename"]
    dataset_obj.path = path_dict["path"]
    dataset_obj.full_path = full_path
    return FakeDatasetResponse(dict(dataset_obj)).create()


def fake_dataset_import_create(*args, **kwargs):
    return FakeDatasetImport(kwargs).create()


def fake_dataset_tmpl_create(*args, **kwargs):
    return FakeDatasetTemplateResponse(kwargs).create()


def fake_dataset_tmpl_retrieve(rid, *args, **kwargs):
    return FakeDatasetTemplateResponse(kwargs).retrieve(rid)


def fake_migration_create(*args, **kwargs):
    return FakeMigrationResponse(kwargs).create()


def fake_export_create(*args, **kwargs):
    return FakeExportResponse(kwargs).create()
