# Reflecting the TOML configuration file in data structures.
#
# Author: Malte J. Ziebarth (malte.ziebarth@tum.de)
#
# Copyright (C) 2025-2026 Technische Universität München
#
# Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
# the European Commission - subsequent versions of the EUPL (the "Licence");
# You may not use this work except in compliance with the Licence.
# You may obtain a copy of the Licence at:
#
# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the Licence is distributed on an "AS IS" basis,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the Licence for the specific language governing permissions and
# limitations under the Licence.
#
# SPDX-FileCopyrightText: 2025-2026 Technical University of Munich
# SPDX-License-Identifier: EUPL-1.2
# SPDX-FileContributor: Malte J. Ziebarth <malte.ziebarth@tum.de>


from itertools import islice
from .repository import Repository, RelativePath
from .paths import wrapper_header_path


class MesonTarget:
    """
    Wrapping Meson targets in custom types.
    """
    name: str

    def __init__(self, name: str):
        # Assert validity:
        redux = name.replace('_','')
        if not redux.isalnum():
            raise RuntimeError(
                f"Meson target '{name}' is not alpha-numeric."
            )
        self.name = name

    def __str__(self) -> str:
        return self.name

    def __repr__(self) -> str:
        return f"<MesonTarget '{self.name}'>"


class TOMLLibrary:
    """
    Data structure reflecting one of the extension module entries
    of the `funktionsklempner.toml` configuration file.
    """
    module: tuple[str, ...]
    header: RelativePath
    sources: list[RelativePath]
    wrapper_header: RelativePath | None
    wrapper_source: RelativePath | None
    link_with: list[MesonTarget] | None
    dependencies: list[MesonTarget] | None
    include_root: RelativePath
    repository: Repository
    fk_namespace: str

    # More metadata:
    license_boilerplate: str | None
    accept_any_email: bool
    extended_author_syntax: bool

    def __init__(self,
            repository: Repository,
            module: tuple[str, ...],
            header: RelativePath,
            sources: list[RelativePath],
            link_with: list[MesonTarget] | None,
            dependencies: list[MesonTarget] | None,
            wrapper_source: RelativePath | None,
            include_root: RelativePath | None,
            fk_namespace: str | None
        ):
        assert isinstance(header, RelativePath)
        assert isinstance(module, tuple)
        assert all(isinstance(m,str) for m in module)
        assert isinstance(sources, list)
        assert all(isinstance(s, RelativePath) for s in sources)
        if link_with is not None:
            assert isinstance(link_with, list)
            assert all(isinstance(s, MesonTarget) for s in link_with)
            if len(link_with) == 0:
                link_with = None
        if dependencies is not None:
            assert isinstance(dependencies, list)
            assert all(isinstance(s, MesonTarget) for s in dependencies)
            if len(dependencies) == 0:
                dependencies = None
        assert isinstance(wrapper_source, RelativePath) or wrapper_source is None
        assert isinstance(include_root, RelativePath) or include_root is None
        if include_root is None:
            include_root = header.parent

        assert isinstance(repository, Repository)
        self.module = module
        self.header = header
        self.sources = sources
        self.wrapper_header = None
        self.wrapper_source = None
        self.accept_any_email = False
        self.license_boilerplate = None
        self.extended_author_syntax = True
        self.link_with = link_with
        self.dependencies = dependencies
        self.wrapper_source = wrapper_source
        self.include_root = include_root
        self.repository = repository
        if fk_namespace is None:
            self.fk_namespace = "funktionsklempner"
        else:
            self.fk_namespace = fk_namespace


    def __repr__(self) -> str:
        res = f"Library({self.module}, header={self.header}, " \
            f"sources={self.sources}"
        if self.link_with is not None:
            res += (
                f", link_with=[{",".join(l.name for l in self.link_with)}]"
            )
        if self.dependencies is not None:
            res += (
                f", dependencies=[{",".join(d.name for d in self.dependencies)}]"
            )
        res += ")"
        return res


    def include_root_path(self) -> RelativePath:
        # If no 'include_root' was specified, we default to the
        # location of the header:
        return self.include_root


    def module_path(self) -> RelativePath:
        path = self.repository.python_package_root / \
            islice(self.module, 1, len(self.module)-1)
        path /= self.module[-1] + ".py"
        return path

    def wrapper_header_path(self) -> RelativePath:
        if self.wrapper_header is None:
            #header_name = self.header.split('/')[-1]
            #header_name = wrapper_header_path(wrapped, self.root)
            #return wrapped.parent / header_name
            wrapper_header = wrapper_header_path(
                self.header, self.include_root
            )
            return wrapper_header
            #return RelativePath.from_paths(self.repository.root, wrapper_header)
        raise NotImplementedError("Given header configuration not implemented.")


    def wrapper_source_path(self) -> RelativePath:
        if self.wrapper_source is None:
            whp = self.wrapper_header_path()
            return whp.parent / (whp.stem + ".cpp")
        return self.wrapper_source


    def header_path(self) -> RelativePath:
        return self.header