from __future__ import annotations

from typing import TYPE_CHECKING, Any, Optional

from ._input_handler import TextInputHandler

from .element import CursorOffset, Element

if TYPE_CHECKING:
    from pydantic import TypeAdapter

    from .styles.base import BaseStyle


class Input(TextInputHandler, Element):
    label: Optional[str] = None

    def __init__(
        self,
        label: Optional[str] = None,
        placeholder: Optional[str] = None,
        default: Optional[str] = None,
        default_as_placeholder: bool = True,
        required: bool = False,
        required_message: Optional[str] = None,
        password: bool = False,
        inline: bool = False,
        name: Optional[str] = None,
        style: Optional[BaseStyle] = None,
        validator: Optional[TypeAdapter] = None,
        **metadata: Any,
    ):
        self.name = name
        self.label = label
        self._placeholder = placeholder
        self.default = default
        self.default_as_placeholder = default_as_placeholder
        self.required = required
        self.password = password
        self.inline = inline

        self.text = ""
        self.valid = None
        self.required_message = required_message
        self._validation_message: Optional[str] = None
        self._validator: Optional[TypeAdapter] = validator

        Element.__init__(self, style=style, metadata=metadata)
        super().__init__()

    @property
    def placeholder(self) -> str:
        if self.default_as_placeholder and self.default:
            return self.default

        return self._placeholder or ""

    @property
    def validation_message(self) -> Optional[str]:
        if self._validation_message:
            return self._validation_message

        assert self.valid

        return None

    @property
    def cursor_offset(self) -> CursorOffset:
        top = 1 if self.inline else 2

        left_offset = 0

        if self.inline and self.label:
            left_offset = len(self.label) + 1

        return CursorOffset(top=top, left=self.cursor_left + left_offset)

    @property
    def should_show_cursor(self) -> bool:
        return True

    def on_blur(self):
        self.on_validate()

    def on_validate(self):
        value = self.value.strip()

        if not value and self.required:
            self.valid = False
            self._validation_message = self.required_message or "This field is required"

            return

        if self._validator:
            from pydantic import ValidationError

            try:
                self._validator.validate_python(value)
            except ValidationError as e:
                self.valid = False

                self._validation_message = e.errors()[0]["ctx"]["reason"]

                return

        self._validation_message = None
        self.valid = True

    @property
    def value(self) -> str:
        return self.text or self.default or ""

    def ask(self) -> str:
        from .container import Container

        container = Container(style=self.style)

        container.elements = [self]

        container.run()

        return self.value
