# SPDX-License-Identifier: Apache-2.0
# Copyright 2021 The Meson development team

from abc import ABCMeta, abstractmethod
from pathlib import Path
import re
import typing as T

from .model import (
    NamedObject,
    FeatureCheck,
    ArgBase,
    PosArg,
    DataTypeInfo,
    Type,
    Function,
    Method,
    Object,
    ObjectType,
    ReferenceManual,
)

from mesonbuild import mlog

class _Resolver:
    def __init__(self) -> None:
        self.type_map: T.Dict[str, Object] = {}
        self.func_map: T.Dict[str, T.Union[Function, Method]] = {}
        self.processed_funcs: T.Set[str] = set()

    def _validate_named_object(self, obj: NamedObject) -> None:
        name_regex = re.compile(r'[a-zA-Z0-9_]+')
        obj.name = obj.name.strip()
        obj.description = obj.description.strip()
        assert obj.name and obj.description, 'Both name and description must be set'
        assert obj.name.islower(), f'Object names must be lower case ({obj.name})'
        assert name_regex.match(obj.name) or obj.name == '[index]', f'Invalid name {obj.name}'

    def _validate_feature_check(self, obj: FeatureCheck) -> None:
        meson_version_reg = re.compile(r'[0-9]+\.[0-9]+\.[0-9]+')
        obj.since = obj.since.strip()
        obj.deprecated = obj.deprecated.strip()
        if obj.since:
            assert meson_version_reg.match(obj.since)
        if obj.deprecated:
            assert meson_version_reg.match(obj.deprecated)

    def _resolve_type(self, raw: str) -> Type:
        typ = Type(raw)
        # We can't use `types = raw.split('|')`, because of `list[str | env]`
        types: T.List[str] = ['']
        stack = 0
        for c in raw:
            if stack == 0 and c == '|':
                types += ['']
                continue
            if c == '[':
                stack += 1
            if c == ']':
                stack -= 1
            types[-1] += c
        types = [x.strip() for x in types]
        for t in types:
            t = t.strip()
            idx = t.find('[')
            base_type = t
            held_type = None
            if idx > 0:
                base_type = t[:idx]
                held_type = self._resolve_type(t[idx+1:-1])
            assert base_type in self.type_map, f'No known object {t}'
            obj = self.type_map[base_type]
            typ.resolved += [DataTypeInfo(obj, held_type)]
        return typ

    def _validate_func(self, func: T.Union[Function, Method]) -> None:
        # Always run basic checks, since they also slightly post-process (strip) some strings
        self._validate_named_object(func)
        self._validate_feature_check(func)

        func_id = f'{func.obj.name}.{func.name}' if isinstance(func, Method) else func.name
        if func_id in self.processed_funcs:
            return

        func.returns = self._resolve_type(func.returns.raw)

        all_args: T.List[ArgBase] = []
        all_args += func.posargs
        all_args += func.optargs
        all_args += func.kwargs.values()
        all_args += [func.varargs] if func.varargs else []

        for arg in all_args:
            arg.type = self._resolve_type(arg.type.raw)

        # Handle returned_by
        for obj in func.returns.resolved:
            obj.data_type.returned_by += [func]

        # Handle kwargs inheritance
        for base_name in func.kwargs_inherit:
            base_name = base_name.strip()
            assert base_name in self.func_map, f'Unknown base function `{base_name}` for {func.name}'
            base = self.func_map[base_name]
            if base_name not in self.processed_funcs:
                self._validate_func(base)

            curr_keys = set(func.kwargs.keys())
            base_keys = set(base.kwargs.keys())

            # Calculate the missing kwargs from the current set
            missing = {k: v for k, v in base.kwargs.items() if k in base_keys - curr_keys}
            func.kwargs.update(missing)

        # Handle other args inheritance
        _T = T.TypeVar('_T', bound=T.Union[ArgBase, T.List[PosArg]])
        def resolve_inherit(name: str, curr: _T, resolver: T.Callable[[Function], _T]) -> _T:
            if name and not curr:
                name = name.strip()
                assert name in self.func_map, f'Unknown base function `{name}` for {func.name}'
                if name not in self.processed_funcs:
                    self._validate_func(self.func_map[name])
                ref_args = resolver(self.func_map[name])
                assert ref_args is not None, f'Inherited function `{name}` does not have inherited args set'
                return ref_args
            return curr

        func.posargs = resolve_inherit(func.posargs_inherit, func.posargs, lambda x: x.posargs)
        func.optargs = resolve_inherit(func.optargs_inherit, func.optargs, lambda x: x.optargs)
        func.varargs = resolve_inherit(func.varargs_inherit, func.varargs, lambda x: x.varargs)

        self.processed_funcs.add(func_id)

    def validate_and_resolve(self, manual: ReferenceManual) -> ReferenceManual:
        mlog.log('Validating loaded manual...')

        # build type map and func map for methods
        for obj in manual.objects:
            assert obj.name not in self.type_map, f'Duplicate object name {obj.name}'
            self.type_map[obj.name] = obj
            for m in obj.methods:
                mid = f'{obj.name}.{m.name}'
                assert mid not in self.type_map, f'Duplicate method {mid}'
                self.func_map[mid] = m

        # Build func map for functions
        for func in manual.functions:
            assert func.name not in [*self.func_map.keys()], f'Duplicate function {func.name}'
            self.func_map[func.name] = func

        mlog.log('Validating functions...')
        for func in manual.functions:
            mlog.log(' -- validating', mlog.bold(func.name))
            self._validate_func(func)

        mlog.log('Validating objects...')
        for obj in manual.objects:
            mlog.log(' -- validating', mlog.bold(obj.name))
            self._validate_named_object(obj)
            self._validate_feature_check(obj)
            # Resolve and validate inheritance
            if obj.extends:
                assert obj.extends in self.type_map, f'Unknown extends object {obj.extends} in {obj.name}'
                obj.extends_obj = self.type_map[obj.extends]
                obj.extends_obj.extended_by += [obj]
            # Only returned objects can be associated with module
            if obj.obj_type is not ObjectType.RETURNED:
                assert obj.defined_by_module is None
            for m in obj.methods:
                assert m.obj is obj
                self._validate_func(m)

        # Resolve inherited methods
        for obj in manual.objects:
            inherited_methods = obj.inherited_methods
            curr = obj.extends_obj
            while curr is not None:
                inherited_methods += curr.methods
                curr = curr.extends_obj
        return manual

class LoaderBase(metaclass=ABCMeta):
    def __init__(self) -> None:
        self._input_files: T.List[Path] = []

    @property
    def input_files(self) -> T.List[Path]:
        return list(self._input_files)

    def read_file(self, f: Path) -> str:
        assert f.exists()
        assert f.is_file()
        self._input_files += [f.resolve()]
        return f.read_text(encoding='utf-8')

    @abstractmethod
    def load_impl(self) -> ReferenceManual:
        pass

    def load(self) -> ReferenceManual:
        self._input_files = []  # Reset input files
        manual = self.load_impl()
        resolver = _Resolver()
        with mlog.nested():
            return resolver.validate_and_resolve(manual)
