# Responsible for building the storage dict into a set of rules ("JSON Schema") acceptable via the API
# Probably other ways to solve this when the backend switches to some ORM
from changedetectionio.notification import valid_notification_formats


def build_time_between_check_json_schema():
    # Setup time between check schema
    schema_properties_time_between_check = {
        "type": "object",
        "additionalProperties": False,
        "properties": {}
    }
    for p in ['weeks', 'days', 'hours', 'minutes', 'seconds']:
        schema_properties_time_between_check['properties'][p] = {
            "anyOf": [
                {
                    "type": "integer"
                },
                {
                    "type": "null"
                }
            ]
        }

    return schema_properties_time_between_check

def build_watch_json_schema(d):
    # Base JSON schema
    schema = {
        'type': 'object',
        'properties': {},
    }

    for k, v in d.items():
        # @todo 'integer' is not covered here because its almost always for internal usage

        if isinstance(v, type(None)):
            schema['properties'][k] = {
                "anyOf": [
                    {"type": "null"},
                ]
            }
        elif isinstance(v, list):
            schema['properties'][k] = {
                "anyOf": [
                    {"type": "array",
                     # Always is an array of strings, like text or regex or something
                     "items": {
                         "type": "string",
                         "maxLength": 5000
                     }
                     },
                ]
            }
        elif isinstance(v, bool):
            schema['properties'][k] = {
                "anyOf": [
                    {"type": "boolean"},
                ]
            }
        elif isinstance(v, str):
            schema['properties'][k] = {
                "anyOf": [
                    {"type": "string",
                     "maxLength": 5000},
                ]
            }

    # Can also be a string (or None by default above)
    for v in ['body',
              'notification_body',
              'notification_format',
              'notification_title',
              'proxy',
              'tag',
              'title',
              'webdriver_js_execute_code'
              ]:
        schema['properties'][v]['anyOf'].append({'type': 'string', "maxLength": 5000})

    for v in ['last_viewed']:
        schema['properties'][v] = {
            "type": "integer",
            "description": "Unix timestamp in seconds of the last time the watch was viewed.",
            "minimum": 0
        }

    # None or Boolean
    schema['properties']['track_ldjson_price_data']['anyOf'].append({'type': 'boolean'})

    schema['properties']['method'] = {"type": "string",
                                      "enum": ["GET", "POST", "DELETE", "PUT"]
                                      }

    schema['properties']['fetch_backend']['anyOf'].append({"type": "string",
                                                           "enum": ["html_requests", "html_webdriver"]
                                                           })



    # All headers must be key/value type dict
    schema['properties']['headers'] = {
        "type": "object",
        "patternProperties": {
            # Should always be a string:string type value
            ".*": {"type": "string"},
        }
    }

    schema['properties']['notification_format'] = {'type': 'string',
                                                   'enum': list(valid_notification_formats.keys())
                                                   }

    # Stuff that shouldn't be available but is just state-storage
    for v in ['previous_md5', 'last_error', 'has_ldjson_price_data', 'previous_md5_before_filters', 'uuid']:
        del schema['properties'][v]

    schema['properties']['webdriver_delay']['anyOf'].append({'type': 'integer'})

    schema['properties']['time_between_check'] = build_time_between_check_json_schema()

    schema['properties']['time_between_check_use_default'] = {
        "type": "boolean",
        "default": True,
        "description": "Whether to use global settings for time between checks - defaults to true if not set"
    }

    schema['properties']['browser_steps'] = {
        "anyOf": [
            {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "operation": {
                            "type": ["string", "null"],
                            "maxLength": 5000  # Allows null and any string up to 5000 chars (including "")
                        },
                        "selector": {
                            "type": ["string", "null"],
                            "maxLength": 5000
                        },
                        "optional_value": {
                            "type": ["string", "null"],
                            "maxLength": 5000
                        }
                    },
                    "required": ["operation", "selector", "optional_value"],
                    "additionalProperties": False  # No extra keys allowed
                }
            },
            {"type": "null"},  # Allows null for `browser_steps`
            {"type": "array", "maxItems": 0}  # Allows empty array []
        ]
    }

    # headers ?
    return schema

