
""" 
DataClass UI: Model 
-------------------

The backend components that make up the dataclass UI.
These are used as inputs to the controllers to define 
the meta-data and the type of the dataclass fields, 
so that the controller can find the fitting widgets and provide 
the user with additional information.
"""
from __future__ import annotations

import logging
from collections.abc import Callable
from dataclasses import MISSING, Field, dataclass, field
from pathlib import Path
from typing import Any

LOGGER = logging.getLogger(__name__)

@dataclass(slots=True)
class MetaData:
    """ Metadata for a dataclass-field. """
    label: str | None = None
    comment: str | None = None
    validate: Callable | None = None  # needs to return a truthy value if valid, else falsy or raise

    def __getitem__(self, key):
        return getattr(self, key)

    def get(self, key, default=None):
        return getattr(self, key, default)

    
def metafield(
    label: str, 
    comment: str, 
    default=MISSING, 
    validate: Callable | None = None, 
    ) -> Field:
    """ Convenience function to create a dataclass-field with metadata. """
    return field(
        default=default, 
        metadata=MetaData(label=label, comment=comment, validate=validate)
    )


def choices_validator(*choices: Any) -> Callable:
    """ Return a validator that checks if a given value is in the choices. """
    def validator(value):
        if value not in choices:
            raise ValueError(f"Value {value} is not in {choices}.")
        return True
    return validator


class FilePath(type(Path())):
    """ Convenience Class to indicate that the Path should lead to a file. 
    For the inheritance: https://stackoverflow.com/questions/29850801/subclass-pathlib-path-fails
    """
    pass


class DirectoryPath(type(Path())):
    """ Convenience Class to indicate that the Path should lead to a directory. 
    For the inheritance: https://stackoverflow.com/questions/29850801/subclass-pathlib-path-fails
    """
    pass


@dataclass(slots=True)
class FieldUIDef:
    """ Definition of an FieldUI to be generated by 
    :class:`omc3_gui.utils.dataclass_ui.controller.DataClassUI`.
    This defines how the label and edit-field widgets should look like
    for a field in the dataclass to be UI'ed.
    Missing information is parsed in from the dataclass 
    isetlf if possible, but values given here take precedence. 
    """
    name: str                        # name of the field in the dataclass
    label: str | None = None         # label of the field
    pytype: type | None = None       # type of the field's data, needs to be instanciable
    comment: str | None = None       # comment for the field, e.g. used for tooltips
    editable: bool | None = True     # sets field to be editable