from __future__ import annotations

import logging

from pydantic import BaseModel, Field
from typing_extensions import Self

logger = logging.getLogger(__name__)


class AppiumData(BaseModel):
    type: str
    value: str | None = None
    name: str | None = None
    label: str | None = None
    resource_id: str | None = None
    text: str | None = None
    bounds: str | None = None
    x: int
    y: int
    width: int
    height: int

    @classmethod
    def factory(cls, xml_element) -> Self:
        return cls(
            type=xml_element.attrib.get("appium_type")
            or xml_element.attrib.get("type"),
            value=xml_element.attrib.get("value"),
            name=(
                xml_element.attrib["appium_name"]
                if "appium_name" in xml_element.attrib
                else xml_element.attrib.get("name")
            ),
            label=(
                xml_element.attrib["appium_label"]
                if "appium_label" in xml_element.attrib
                else xml_element.attrib.get("label")
            ),
            resource_id=xml_element.attrib.get("appium_resource-id"),
            text=xml_element.attrib.get("appium_text"),
            bounds=xml_element.attrib.get("appium_bounds"),
            x=(
                int(xml_element.attrib["appium_x"])
                if "appium_x" in xml_element.attrib
                else int(xml_element.attrib.get("x"))
            ),
            y=(
                int(xml_element.attrib["appium_y"])
                if "appium_y" in xml_element.attrib
                else int(xml_element.attrib.get("y"))
            ),
            width=int(xml_element.attrib.get("width")),
            height=int(xml_element.attrib.get("height")),
        )


class ActiveElement(BaseModel):
    source: str
    appium_data: AppiumData | None = None

    type: str
    id: str | None = None

    x: int
    y: int
    width: int
    height: int

    scrollable: str | None = None

    @classmethod
    def factory(cls, xml_element) -> Self:
        source_data = AppiumData.factory(xml_element)

        return cls(
            source=xml_element.attrib.get("source") or "appium",
            appium_data=source_data,
            type=xml_element.attrib.get("type"),
            id=xml_element.attrib.get("id"),
            x=int(xml_element.attrib.get("x")),
            y=int(xml_element.attrib.get("y")),
            width=int(xml_element.attrib.get("width")),
            height=int(xml_element.attrib.get("height")),
            scrollable=xml_element.attrib.get("scrollable"),
        )

    @property
    def center_x(self) -> int:
        return self.x + self.width // 2

    @property
    def center_y(self) -> int:
        return self.y + self.height // 2

    @property
    def value(self) -> str | None:
        return self.appium_data.value if self.appium_data else None

    @property
    def name(self) -> str | None:
        return self.appium_data.name if self.appium_data else None

    @property
    def label(self) -> str | None:
        return self.appium_data.label if self.appium_data else None

    @property
    def string_description(self) -> str:
        coordinates = f"(x:{self.center_x}, y:{self.center_y})"

        parts = []
        if self.type != "Element":
            parts.append(f"type='{self.type}'")
        if self.label:
            parts.append(f"label='{self.label}'")
        if self.id:
            parts.append(f"id='{self.id}'")
        parts.append(f"coordinates={coordinates}")
        return " ".join(parts)


class Screen(BaseModel):
    elements_tree: str | None = Field(default=None)
    screenshot_url: str | None = Field(
        default=None
    )  # Public URL for screenshot retrieval
