from typing import Callable

from pydantic import BeforeValidator, GetCoreSchemaHandler
from pydantic_core import core_schema
from sqlalchemy.orm import DeclarativeBase


class DelimitedList:
    """Converts delimited strings to list[str]

    Usage in Pydantic models:
        nationality: Annotated[list[str], DelimitedList(",")]
        role_last: Annotated[list[str], DelimitedList(";")]
    """

    def __init__(self, delimiter: str = ",", validation: Callable | None = None):
        self.delimiter = delimiter
        self.validation = validation

    def __get_pydantic_core_schema__(
        self, _source_type, _handler: GetCoreSchemaHandler
    ) -> core_schema.CoreSchema:
        delimiter = self.delimiter
        validation = self.validation

        def validate(v):
            if isinstance(v, str):
                items = [item.strip() for item in v.split(delimiter)]
                # Convert each item to the target type
                if validation is not None:
                    items = [validation(item) for item in items]
                return [item for item in items]
            if isinstance(v, list):
                # Handle list input - apply validation if needed
                if validation is not None:
                    return [validation(item) for item in v]
                return v
            raise TypeError(f"Expected str or list, got {type(v)}")

        return core_schema.no_info_after_validator_function(
            validate,
            core_schema.union_schema(
                [
                    core_schema.str_schema(),
                    core_schema.list_schema(core_schema.str_schema()),
                ]
            ),
        )


def empty_str_to_none(v):
    if v == "" or v is None:
        return None
    return v


Nullable = BeforeValidator(empty_str_to_none)
"""
For value that could be emptystring but not considered as None.
On non str values, this leads to pydantic validation error. 

### Usage: 
    Birthdate: Annotated[date | None, Nullable] = None
"""


class Base(DeclarativeBase):
    pass
