from __future__ import annotations

from typing import TYPE_CHECKING

from narwhals._duckdb.utils import F, col, concat_str, lit
from narwhals._sql.expr_str import SQLExprStringNamespace
from narwhals._utils import not_implemented, requires

if TYPE_CHECKING:
    from duckdb import Expression

    from narwhals._duckdb.expr import DuckDBExpr


class DuckDBExprStringNamespace(SQLExprStringNamespace["DuckDBExpr"]):
    def strip_chars_start(self, characters: str) -> DuckDBExpr:
        return self.compliant._with_elementwise(
            lambda expr: F("ltrim", expr, lit(characters))
        )

    def strip_chars_end(self, characters: str) -> DuckDBExpr:
        return self.compliant._with_elementwise(
            lambda expr: F("rtrim", expr, lit(characters))
        )

    def to_datetime(self, format: str | None) -> DuckDBExpr:
        if format is None:
            msg = "Cannot infer format with DuckDB backend, please specify `format` explicitly."
            raise NotImplementedError(msg)

        return self.compliant._with_elementwise(
            lambda expr: F("strptime", expr, lit(format))
        )

    def to_date(self, format: str | None) -> DuckDBExpr:
        if format is not None:
            return self.to_datetime(format=format).dt.date()

        compliant_expr = self.compliant
        return compliant_expr.cast(compliant_expr._version.dtypes.Date())

    def to_time(self, format: str | None) -> DuckDBExpr:
        time_dtype = self.compliant._version.dtypes.Time()
        if format is None:
            return self.compliant.cast(time_dtype)

        return self.compliant._with_elementwise(
            lambda expr: F("strptime", expr, lit(format))
        ).cast(time_dtype)

    @requires.backend_version((1, 2))
    def to_titlecase(self) -> DuckDBExpr:
        from narwhals._duckdb.utils import lambda_expr

        def _to_titlecase(expr: Expression) -> Expression:
            extract_expr = F(
                "regexp_extract_all", F("lower", expr), lit(r"[a-z]*[^a-z]*")
            )
            elem = col("_")
            capitalize = lambda_expr(
                elem,
                concat_str(
                    F("upper", F("array_extract", elem, lit(1))),
                    F("substring", elem, lit(2)),
                ),
            )
            capitalized_expr = F("list_transform", extract_expr, capitalize)
            return F("list_aggregate", capitalized_expr, lit("string_agg"), lit(""))

        return self.compliant._with_elementwise(_to_titlecase)

    replace = not_implemented()
