"""
A module to register Avro schemas to Confluent Schema Registry.
"""

import json
from collections import OrderedDict

import requests
from requests import Response

from avro_preprocessor.avro_naming import AvroNaming
from avro_preprocessor.colored_json import ColoredJson
from avro_preprocessor.preprocessor_module import PreprocessorModule

__author__ = "Nicola Bova"
__copyright__ = "Copyright 2018, Jaumo GmbH"
__email__ = "nicola.bova@jaumo.com"


class SchemaRegistrar(PreprocessorModule):
    """
    Register schemas to Confluent Schema Registry.
    """
    schema_registry_url: str = ''
    url: str = ''
    payload: str = ''

    def process(self) -> None:
        """Process all schemas."""

        # If a key_schema is defined, it means we have a default common key.
        default_common_key = self.schemas.paths.key_schema

        # In that case, we process it with the schema registry.
        if default_common_key and \
                self.schemas.paths.key_subject_name_strategy == "RecordNameStrategy":
            common_key_schema = self.schemas.processed[self.schemas.paths.key_schema]
            self.perform_request_to_schema_registry("", default_common_key, common_key_schema)

        current_topic = ""

        for name, schema in self.processed_schemas_iter():

            if not self.schemas.paths.is_rpc_resource(name):
                # RPC protocols cannot be registered to the schema registry

                topic = AvroNaming.get_topic(self.schemas.paths.base_namespace, name)
                value_subject_name = AvroNaming.get_subject_name_for_value(
                    self.schemas.paths.base_namespace, name)
                self.perform_request_to_schema_registry(topic, value_subject_name, schema)

                if self.schemas.paths.is_event_resource(name) and topic != current_topic:
                    key_subject_name = AvroNaming.get_subject_name_for_key(
                        self.schemas.paths.base_namespace,
                        AvroNaming.get_key_fully_qualified_name(name))

                    if default_common_key and self.schemas.paths.key_subject_name_strategy \
                            == "TopicRecordNameStrategy":
                        key_schema = self.schemas.processed[self.schemas.paths.key_schema]
                        self.perform_request_to_schema_registry(topic, key_subject_name, key_schema)
                    else:
                        # if we were requested to generate keys (KeysGenerator module active),
                        # and the key_subject_name_strategy is not TopicRecordNameStrategy,
                        # we also register them to the schema registry
                        key_name = AvroNaming.get_key_fully_qualified_name(name)
                        if key_name in self.schemas.autogenerated_keys:
                            key_schema = self.schemas.autogenerated_keys[key_name]
                            self.perform_request_to_schema_registry(
                                topic, key_subject_name, key_schema)

                current_topic = topic

    def perform_request_to_schema_registry(
            self, topic: str, subject_name: str, schema: OrderedDict) -> None:
        """
        Register a schema in the schema registry.
        :param topic: The Kafka topic
        :param subject_name: The subject name for this schema
        :param schema: The schema
        """
        schema_text = json.dumps(schema, indent=ColoredJson.json_indent)

        self.payload = "{ \"schema\": \"" \
                  + schema_text.replace("\"", "\\\"").replace("\t", "").replace("\n", "") \
                  + "\" }"
        # print("Payload: " + self.payload)

        self.url = self.get_request_url(subject_name)

        headers = {"Content-Type": "application/vnd.schemaregistry.v1+json"}

        if self.schemas.verbose:
            print("Schema Registry URL: " + self.schema_registry_url)
            print("Topic: " + topic)
            print("Subject name: " + subject_name)
            print("URL: " + self.url)
            print("Headers :", headers)

        req = requests.post(self.url, headers=headers, data=self.payload)
        self.process_response(req)

    def get_request_url(self, subject: str) -> str:
        """
        Returns the URL for this request
        :param subject: The Avro subject name
        :return: The full URL
        """
        return self.schema_registry_url + "/subjects/" + subject + "/versions"

    def process_response(self, response: Response) -> None:
        """
        Process the response.
        :param response: The response
        """
        if response.status_code == requests.codes.ok:  # pylint: disable=E1101
            if self.schemas.verbose:
                print('Response: Success!', json.loads(response.content), '\n')
        else:
            print('\n\nFailure, request payload:\n', self.payload)
            print('Response: ', json.loads(response.content), '\n')
            response.raise_for_status()
