"""TcEx Framework Module"""
# pylint: disable=no-self-argument

# third-party
from pydantic import BaseModel, Field, validator
from semantic_version import Version

__all__ = ['JobJsonModel']


def snake_to_camel(snake_string: str) -> str:
    """Convert snake_case to camelCase"""
    components = snake_string.split('_')
    return components[0] + ''.join(x.title() for x in components[1:])


class ParamsModel(BaseModel):
    """Model definition for job.json.params"""

    default: bool | str | None
    encrypt: bool = False
    name: str
    prevent_updates: bool = False

    class Config:
        """DataModel Config"""

        alias_generator = snake_to_camel
        # without smart_union the default value as a string of "0" would be converted to a bool
        smart_union = True
        validate_assignment = True


class JobJsonCommonModel(BaseModel):
    """Model definition for common field in job.json."""

    allow_on_demand: bool = Field(
        ...,
        description='If true, the job can be run on demand.',
    )
    enable_notifications: bool = Field(
        ..., description='Enables pass/fail notification for this job.'
    )
    job_name: str
    notify_email: str = Field(
        ...,
        description='Email address to send notification to.',
    )
    notify_include_log_files: bool = Field(
        ...,
        description='If true, the job log files will be included in the notification email.',
    )
    notify_on_complete: bool = Field(
        ...,
        description='If true, a notification will be sent when the job completes.',
    )
    notify_on_failure: bool = Field(
        ...,
        description='If true, a notification will be sent when the job fails.',
    )
    notify_on_partial_failure: bool = Field(
        ...,
        description=(
            'If true, a notification will be sent when the job completes with partial success.'
        ),
    )
    params: list[ParamsModel]
    publish_auth: bool = Field(
        ...,
        description='If true, the job will publish the authentication token.',
    )
    schedule_cron_format: str
    schedule_start_date: int
    schedule_type: str

    class Config:
        """DataModel Config"""

        alias_generator = snake_to_camel
        arbitrary_types_allowed = True
        validate_assignment = True


class JobJsonModel(JobJsonCommonModel):
    """Model definition for job.json configuration file"""

    program_name: str
    program_version: str

    @validator('program_version')
    def version(cls, v):
        """Return a version object for "version" fields."""
        if v is not None:
            return Version(v)
        return v  # pragma: no cover

    class Config:
        """DataModel Config"""

        alias_generator = snake_to_camel
        arbitrary_types_allowed = True
        json_encoders = {Version: lambda v: str(v)}  # pylint: disable=unnecessary-lambda
        validate_assignment = True
