import copy
import pathlib
from typing import Any

from ._build_docs import get_plugin_documentation


JSON_SCHEMA = {
    "$id": "https://github.com/equinor/webviz-config",
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "Webviz",
    "type": "object",
    "properties": {
        "title": {"description": "Title of your Webviz application.", "type": "string"},
        "shared_settings": {"type": "object"},
        "options": {
            "type": "object",
            "menu": {
                "description": "Define the menu options.",
                "type": "object",
                "properties": {
                    "show_logo": {
                        "description": "State if a logo shall be shown in the menu.",
                        "type": "boolean",
                    },
                    "bar_position": {
                        "description": "Define where the menu bar shall be positioned:"
                        " left, top, right, bottom.",
                        "type": "string",
                    },
                    "drawer_position": {
                        "description": "Define where the menu drawer shall be positioned:"
                        " left or right.",
                        "type": "string",
                    },
                    "initially_pinned": {
                        "description": "State if the menu shall be pinned when initially showing.",
                        "type": "boolean",
                    },
                    "initially_collapsed": {
                        "description": "State if all groups in menu shall initially be collapsed",
                        "type": "boolean",
                    },
                    "homepage": {
                        "description": """
                        Set a custom page as homepage to which the user returns when clicking on the logo.
                        Use the page's title.
                        """,
                        "type": "string",
                    },
                },
                "additionalProperties": False,
            },
            "plotly_theme": {
                "type": "object",
                "description": """
                Option to define modifications to the theme's Plotly figure layout.
                Examples are e.g. axis formatting and color palettes. Will be merged
                with existing theme layout, with options defined here prioritized if
                conflicting with the existing theme. The layout is defined as a
                dictionary, for details see:
                https://plotly.com/python/reference/layout/
                """,
            },
        },
        "layout": {
            "description": "Define the pages (and potential sections and groups)"
            " in your Webviz application.",
            "type": "array",
            "minLength": 1,
            "items": {
                "oneOf": [
                    {
                        "type": "object",
                        "properties": {
                            "section": {
                                "description": "Title of the section.",
                                "type": "string",
                            },
                            "icon": {
                                "description": "Optionally set an icon for the section.",
                                "type": "string",
                            },
                            "content": {
                                "description": "Define the pages (and potential subgroups)"
                                " of this section.",
                                "type": "array",
                                "minLength": 1,
                                "items": {
                                    "type": "object",
                                    "oneOf": [
                                        {"$ref": "#/properties/layout/items/oneOf/1"},
                                        {"$ref": "#/properties/layout/items/oneOf/2"},
                                    ],
                                },
                            },
                        },
                        "required": ["section", "content"],
                        "additionalProperties": False,
                    },
                    {
                        "type": "object",
                        "properties": {
                            "group": {
                                "description": "Title of the group.",
                                "type": "string",
                            },
                            "icon": {
                                "description": "Optionally define an icon for the group.",
                                "type": "string",
                            },
                            "content": {
                                "description": "Content of the group.",
                                "type": "array",
                                "minLength": 1,
                                "items": {
                                    "oneOf": [
                                        {"$ref": "#/properties/layout/items/oneOf/1"},
                                        {"$ref": "#/properties/layout/items/oneOf/2"},
                                    ]
                                },
                            },
                        },
                        "required": ["group", "content"],
                        "additionalProperties": False,
                    },
                    {
                        "type": "object",
                        "properties": {
                            "page": {
                                "description": "Title of the page.",
                                "type": "string",
                            },
                            "icon": {
                                "description": "Optionally define an icon for the page.",
                                "type": "string",
                            },
                            "content": {
                                "description": "Content of the page.",
                                "type": "array",
                                "minLength": 1,
                                "items": {"oneOf": [{"type": "string"}]},
                            },
                        },
                        "required": ["page", "content"],
                        "additionalProperties": False,
                    },
                ],
            },
        },
    },
    "required": ["title", "layout"],
    "additionalProperties": False,
}

CONTACT_PERSON = {
    "contact_person": {
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "email": {"type": "string"},
            "phone": {"type": ["integer", "string"]},
        },
        "additionalProperties": False,
    }
}


def create_schema() -> dict:
    def json_type(typehint: Any) -> dict:
        # pylint: disable=too-many-return-statements
        if typehint == list:
            return {"type": "array", "items": {}}
        if typehint in (str, pathlib.Path):
            return {"type": "string"}
        if typehint == bool:
            return {"type": "boolean"}
        if typehint == int:
            return {"type": "integer"}
        if typehint == float:
            return {"type": "number"}
        if typehint == dict:
            return {"type": "object"}
        return {}

    json_schema = copy.deepcopy(JSON_SCHEMA)

    # fmt: off
    content_schemas = json_schema["properties"]["layout"][  # type: ignore
        "items"]["oneOf"][2]["properties"]["content"]["items"]["oneOf"]
    # fmt: on

    for package_doc in get_plugin_documentation().values():
        for plugin_doc in package_doc["plugins"]:
            content_schemas.append(
                {
                    "type": "object",
                    "properties": {
                        plugin_doc["name"]: {
                            "description": plugin_doc["description"]
                            or " PLUGIN MISSING DESCRIPTION ",
                            "type": "object",
                            "properties": {
                                **{
                                    arg_name: json_type(arg_info.get("typehint"))
                                    for arg_name, arg_info in plugin_doc[
                                        "arg_info"
                                    ].items()
                                },
                                **CONTACT_PERSON,
                            },
                            "required": [
                                arg_name
                                for arg_name, arg_info in plugin_doc["arg_info"].items()
                                if arg_info["required"]
                            ],
                            "additionalProperties": False,
                        }
                    },
                    "required": [plugin_doc["name"]],
                    "additionalProperties": False,
                    "minProperties": 1,
                    "maxProperties": 1,
                }
            )

    return json_schema
