"""Schema strategy"""

import json
import logging
from pprint import pprint

from jsonmerge import Merger
from prettytable import PrettyTable

from kheops.plugin.common import PluginStrategyClass
from kheops.utils import str_ellipsis


log = logging.getLogger(__name__)


class Plugin(PluginStrategyClass):
    """Schema strategy plugin"""

    _plugin_name = "schema"
    _schema_props_new = {
        "schema": {
            "default": None,
            "optional": True,
            "oneOf": [
                {
                    "type": "null",
                },
                {
                    "type": "string",
                },
                {
                    "type": "array",
                },
                {
                    "type": "object",
                    "additionalProperties": True,
                    "default": {},
                    "properties": {
                        "data": {
                            "default": None,
                            "optional": False,
                            "anyOf": [
                                {"type": "null"},
                                {"type": "string"},
                                {"type": "array"},
                            ],
                        },
                        "var": {
                            "type": "string",
                            "default": "loop_item",
                            "optional": True,
                        },
                    },
                },
            ],
        }
    }

    default_merge_schema = {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "oneOf": [
            {
                "type": "array",
                "mergeStrategy": "append",
                #                    "mergeStrategy": "arrayMergeById",
            },
            {
                "type": "object",
                "mergeStrategy": "objectMerge",
            },
            {
                "type": "boolean",
                "mergeStrategy": "overwrite",
            },
            {
                "type": "string",
                "mergeStrategy": "overwrite",
            },
            {
                "type": "integer",
                "mergeStrategy": "overwrite",
            },
            {
                "type": "number",
                "mergeStrategy": "overwrite",
            },
            {
                "type": "null",
                "mergeStrategy": "overwrite",
            },
        ],
    }

    def process(self, candidates: list, rule=None) -> (list, dict):
        """Return results"""

        trace = rule["trace"]
        explain = rule["explain"]

        schema = rule.get("schema", None) or self.default_merge_schema
        merger = Merger(schema)
        t = PrettyTable()
        t1 = PrettyTable()

        new_candidate = None
        for index, item in enumerate(candidates):
            new_value = item["data"]
            result = merger.merge(new_candidate, new_value)

            backend_info = dict(item["parent"])
            backend_run = backend_info.pop("_run")
            if explain:
                t1.add_row(
                    [
                        index,
                        "\nBackendRun: "
                        + str_ellipsis(
                            json.dumps(
                                backend_run,
                                default=lambda o: "<not serializable>",
                                indent=2,
                            ),
                            70,
                        ),
                        "\nRuleRun: "
                        + str_ellipsis(
                            json.dumps(
                                item["run"],
                                default=lambda o: "<not serializable>",
                                indent=2,
                            ),
                            70,
                        ),
                        "---\nResult: "
                        + str_ellipsis(
                            json.dumps(
                                result, default=lambda o: "<not serializable>", indent=2
                            ),
                            70,
                        ),
                    ]
                )

            if trace:
                t.add_row(
                    [
                        index,
                        "---\nBackendConfig: "
                        + str_ellipsis(
                            json.dumps(
                                backend_info,
                                default=lambda o: "<not serializable>",
                                indent=2,
                            ),
                            70,
                        )
                        + "\nBackendRun: "
                        + str_ellipsis(
                            json.dumps(
                                backend_run,
                                default=lambda o: "<not serializable>",
                                indent=2,
                            ),
                            70,
                        ),
                        "---\nRuleConfig: "
                        + str_ellipsis(
                            json.dumps(
                                rule, default=lambda o: "<not serializable>", indent=2
                            ),
                            70,
                        )
                        + "\nRuleRun: "
                        + str_ellipsis(
                            json.dumps(
                                item["run"],
                                default=lambda o: "<not serializable>",
                                indent=2,
                            ),
                            70,
                        )
                        +
                        #'\nSource: ' + str_ellipsis(json.dumps(
                        #        new_candidate,
                        #        default=lambda o: '<not serializable>', indent=2), 70) +
                        "\nNew data: "
                        + str_ellipsis(
                            json.dumps(
                                new_value,
                                default=lambda o: "<not serializable>",
                                indent=2,
                            ),
                            70,
                        ),
                        "---\nResult: "
                        + str_ellipsis(
                            json.dumps(
                                result, default=lambda o: "<not serializable>", indent=2
                            ),
                            70,
                        ),
                    ]
                )
            new_candidate = result

        if trace:
            t.field_names = ["Index", "Backend", "Rule", "Data"]
            t.align = "l"
            print(t)
        if explain:
            t1.field_names = ["Index", "Backend", "Rule", "Data"]
            t1.align = "l"
            print("Explain:\n" + repr(t1))

        return new_candidate
