from oarepo_model_builder.model_preprocessors import ModelPreprocessor
from oarepo_model_builder.utils.camelcase import camel_case, snake_case
from oarepo_model_builder.utils.deepmerge import deepmerge


def last_item(x):
    return x.rsplit(".", maxsplit=1)[-1]


class InvenioModelPreprocessor(ModelPreprocessor):
    TYPE = "invenio"

    def transform(self, schema, settings):
        deepmerge(
            settings,
            {
                "python": {
                    "record-prefix": camel_case(
                        settings.package.rsplit(".", maxsplit=1)[-1]
                    ),
                    # just make sure that the templates is always there
                    "templates": {},
                    "marshmallow": {"mapping": {}},
                }
            },
        )



        record_prefix = settings.python.record_prefix

        extension_suffix = snake_case(record_prefix)
        extension_suffix_upper = extension_suffix.upper()
        self.set(settings.python, "extension-suffix", lambda: extension_suffix)
        self.set(settings.python, "profile-package", lambda: "records")


        #self.set(settings.python, "extension-suffix", lambda: f"_{record_prefix}")

        self.set(
            settings.python,
            "record-prefix-snake",
            lambda: snake_case(settings.python.record_prefix),
        )

        # level-1 packages

        self.set(
            settings.python,
            "record-resources-package",
            lambda: f"{settings.package}.resources.{settings.python.profile_package}",
        )

        self.set(
            settings.python,
            "record-services-package",
            lambda: f"{settings.package}.services.{settings.python.profile_package}",
        )

        self.set(
            settings.python,
            "record-records-package",
            lambda: f"{settings.package}.{settings.python.profile_package}",
        )

        # config
        self.set(
            settings.python, "config-package", lambda: f"{settings.package}.config"
        )
        self.set(
            settings.python,
            "config-dummy-class",
            lambda: f"{settings.package}.config.DummyClass",
        )
        # todo "config prefix"
        self.set(
            settings.python,
            "config-resource-config-key",
            lambda: f"{settings.package_base_upper}_RESOURCE_CONFIG_{extension_suffix_upper}",
        )
        self.set(
            settings.python,
            "config-resource-class-key",
            lambda: f"{settings.package_base_upper}_RESOURCE_CLASS_{extension_suffix_upper}",
        )
        self.set(
            settings.python,
            "config-service-config-key",
            lambda: f"{settings.package_base_upper}_SERVICE_CONFIG_{extension_suffix_upper}",
        )
        self.set(
            settings.python,
            "config-service-class-key",
            lambda: f"{settings.package_base_upper}_SERVICE_CLASS_{extension_suffix_upper}",
        )
        self.set(
            settings.python,
            "config-resource-register-blueprint-key",
            lambda: f"{settings.package_base_upper}_REGISTER_BLUEPRINT",
        )

        # ext
        self.set(
            settings.python,
            "ext-class",
            lambda: f"{settings.package}.ext.{record_prefix}Ext",
        )
        self.set(
            settings.python, "flask-extension-name", lambda: extension_suffix
        )

        # cli
        self.set(
            settings.python,
            "cli-function",
            lambda: f"{settings.package}.cli.group",
        )

        # proxies
        self.set(
            settings.python,
            "proxies-current-resource",
            lambda: f"{settings.package}.proxies.current_resource",
        )
        self.set(
            settings.python,
            "proxies-current-service",
            lambda: f"{settings.package}.proxies.current_service",
        )

        # record
        self.set(
            settings.python,
            "record-class",
            lambda: f"{settings.python.record_records_package}.api.{record_prefix}Record",
        )
        self.set(
            settings.python,
            "record-metadata-class",
            lambda: f"{settings.python.record_records_package}.models.{record_prefix}Metadata",
        )
        self.set(
            settings.python,
            "record-metadata-table-name",
            lambda: f"{record_prefix.lower()}_metadata",
        )
        #   - setup.cfg
        self.set(
            settings.python,
            "record-mapping-setup-cfg",
            lambda: f"{settings.package_base}",
        )
        self.set(
            settings.python,
            "record-jsonschemas-setup-cfg",
            lambda: f"{settings.package_base}",
        )

        # resource
        self.set(
            settings.python,
            "record-resource-config-class",
            lambda: f"{settings.python.record_resources_package}.config.{record_prefix}ResourceConfig",
        )
        self.set(
            settings.python,
            "record-resource-class",
            lambda: f"{settings.python.record_resources_package}.resource.{record_prefix}Resource",
        )
        self.set(
            settings.python,
            "record-permissions-class",
            lambda: f"{settings.python.record_services_package}.permissions.{record_prefix}PermissionPolicy",
        )

        # service
        self.set(
            settings.python,
            "record-service-class",
            lambda: f"{settings.python.record_services_package}.service.{record_prefix}Service",
        )
        self.set(
            settings.python,
            "record-service-config-class",
            lambda: f"{settings.python.record_services_package}.config.{record_prefix}ServiceConfig",
        )

        settings.python.setdefault("record-service-config-generate-links", True)
        #   - schema
        self.set(
            settings.python,
            "record-schema-class",
            lambda: f"{settings.python.record_services_package}.schema.{record_prefix}Schema",
        )
        self.set(
            settings.python,
            "record-schema-metadata-class",
            lambda: f"{settings.python.record_services_package}.schema.{record_prefix}MetadataSchema",
        )
        #   - dumper
        self.set(
            settings.python,
            "record-dumper-class",
            lambda: f"{settings.python.record_records_package}.dumper.{record_prefix}Dumper",
        )
        #   - search
        if not ("record-search-options-class" in settings.python and settings.python.record_search_options_class == ""): # files plugin requires this to be empty
            self.set(
                settings.python,
                "record-search-options-class",
                lambda: f"{settings.python.record_services_package}.search.{record_prefix}SearchOptions",
            )

        #   - facets
        self.set(
            settings.python,
            "record-facets-class",
            lambda: f"{settings.python.record_services_package}.facets.Test",
        )

        # alembic
        self.set(
            settings.python,
            "record-schema-metadata-alembic",
            lambda: f"{settings.package_base}",
        )
        self.set(
            settings.python,
            "record-schema-metadata-setup-cfg",
            lambda: f"{settings.package_base}",
        )

        self.set(
            settings.python, "record-resource-blueprint-name", lambda: record_prefix
        )
        self.set(
            settings.python,
            "create-blueprint-from-app",
            lambda: f"{settings.package}.views.create_blueprint_from_app_{extension_suffix}",
        )
        settings.python.setdefault("invenio-config-extra-code", "")
        settings.python.setdefault("invenio-ext-extra-code", "")
        settings.python.setdefault("invenio-proxies-extra-code", "")
        settings.python.setdefault("invenio-record-extra-code", "")
        settings.python.setdefault("invenio-record-dumper-extra-code", "")
        settings.python.setdefault("invenio-record-facets-extra-code", "")
        settings.python.setdefault("invenio-record-metadata-extra-code", "")
        settings.python.setdefault("invenio-record-object-schema-extra-code", "")
        settings.python.setdefault("invenio-record-permissions-extra-code", "")
        settings.python.setdefault("invenio-record-resource-extra-code", "")
        settings.python.setdefault("invenio-record-resource-config-extra-code", "")
        settings.python.setdefault("invenio-record-schema-extra-code", "")
        settings.python.setdefault("invenio-record-search-options-extra-code", "")
        settings.python.setdefault("invenio-record-service-extra-code", "")
        settings.python.setdefault("invenio-record-service-config-extra-code", "")
        settings.python.setdefault("invenio-version-extra-code", "")
        settings.python.setdefault("invenio-views-extra-code", "")

        if "model" in schema.schema:
            schema_class = settings.python.record_schema_class
            schema_metadata_class = settings.python.record_schema_metadata_class
            schema_class_base_classes = settings.python.get(
                "record_schema_metadata_bases", []
            ) + [
                "ma.Schema"  # alias will be recognized automatically
            ]

            if (
                "properties" in schema.schema.model
                and "metadata" in schema.schema.model.properties
            ):
                deepmerge(
                    schema.schema.model.properties.metadata.setdefault(
                        "oarepo:marshmallow", {}
                    ),
                    {
                        "class": schema_metadata_class,
                        "base-classes": schema_class_base_classes,
                        "generate": True,
                    },
                )
            if (
                "oarepo:marshmallow" in schema.schema
                and "base-schema" in schema.schema["oarepo:marshmallow"]
            ):
                schema_class_base_classes = settings.python.get(
                    "record_schema_metadata_bases", []
                ) + [
                    schema.schema["oarepo:marshmallow"][
                        "base_schema"
                    ]  # alias will be recognized automatically
                ]

            deepmerge(
                schema.schema.model.setdefault("oarepo:marshmallow", {}),
                {
                    "class": schema_class,
                    "base-classes": schema_class_base_classes,
                    "generate": True,
                },
            )

        settings.python.setdefault("generate-record-pid-field", True)
        settings.python.setdefault("record-dumper-extensions", [])

        # default import prefixes
        _prefixes = settings.python.setdefault("always-defined-import-prefixes", [])
        for _prefix in ["ma", "ma_fields", "ma_valid"]:
            if _prefix not in _prefixes:
                _prefixes.append(_prefix)

        # script sample data importer
        settings.python.setdefault(
            "script-import-sample-data-cli", "scripts.import_sample_data.cli"
        )
        settings.setdefault("script-import-sample-data", "scripts/sample_data.yaml")
        self.set(settings.python, "service-id", lambda: settings.python.flask_extension_name)



