import json
import os

# pylint: disable=unused-import
from esphome.config import load_config, _format_vol_invalid, Config
from esphome.core import CORE, DocumentRange
import esphome.config_validation as cv

# pylint: disable=unused-import, wrong-import-order
from typing import Optional


def _get_invalid_range(res, invalid):
    # type: (Config, cv.Invalid) -> Optional[DocumentRange]
    return res.get_deepest_document_range_for_path(invalid.path)


def _dump_range(range):
    # type: (Optional[DocumentRange]) -> Optional[dict]
    if range is None:
        return None
    return {
        "document": range.start_mark.document,
        "start_line": range.start_mark.line,
        "start_col": range.start_mark.column,
        "end_line": range.end_mark.line,
        "end_col": range.end_mark.column,
    }


class VSCodeResult:
    def __init__(self):
        self.yaml_errors = []
        self.validation_errors = []

    def dump(self):
        return json.dumps(
            {
                "type": "result",
                "yaml_errors": self.yaml_errors,
                "validation_errors": self.validation_errors,
            }
        )

    def add_yaml_error(self, message):
        self.yaml_errors.append(
            {
                "message": message,
            }
        )

    def add_validation_error(self, range_, message):
        self.validation_errors.append(
            {
                "range": _dump_range(range_),
                "message": message,
            }
        )


def read_config(args):
    while True:
        CORE.reset()
        data = json.loads(input())
        assert data["type"] == "validate"
        CORE.vscode = True
        CORE.ace = args.ace
        f = data["file"]
        if CORE.ace:
            CORE.config_path = os.path.join(args.configuration, f)
        else:
            CORE.config_path = data["file"]
        vs = VSCodeResult()
        try:
            res = load_config(dict(args.substitution) if args.substitution else {})
        except Exception as err:  # pylint: disable=broad-except
            vs.add_yaml_error(str(err))
        else:
            for err in res.errors:
                try:
                    range_ = _get_invalid_range(res, err)
                    vs.add_validation_error(range_, _format_vol_invalid(err, res))
                except Exception:  # pylint: disable=broad-except
                    continue
        print(vs.dump())
