from typing import Optional, override

from flut.flutter.rendering.custom_paint import CustomPainter
from flut.flutter.rendering.flex import FlexFit, MainAxisAlignment, MainAxisSize, CrossAxisAlignment
from flut.flutter.rendering.wrap import WrapAlignment, WrapCrossAlignment
from flut.flutter.painting.alignment import Alignment
from flut.flutter.painting.basic_types import Axis
from flut.flutter.painting.border_radius import BorderRadius
from flut.flutter.services.mouse_cursor import MouseCursor
from flut.dart.ui import Offset, Size
from .framework import Widget


class ScrollMode:
    auto = "auto"
    always = "always"
    hidden = "hidden"
    adaptive = "adaptive"


class Center(Widget):
    def __init__(self, *, key=None, child: Optional[Widget] = None):
        super().__init__("Center", key=key)
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        if self.child is not None:
            result["child"] = self.child._flut_pack()
        return result


class Expanded(Widget):
    def __init__(
        self,
        *,
        key=None,
        flex: int = 1,
        child,
    ):
        super().__init__("Expanded", key=key)
        self.flex = flex
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["flex"] = self.flex
        result["child"] = self.child._flut_pack()
        return result


class Flexible(Widget):
    def __init__(
        self,
        *,
        key=None,
        flex: int = 1,
        fit: FlexFit = FlexFit.loose,
        child,
    ):
        super().__init__("Flexible", key=key)
        self.flex = flex
        self.fit = fit
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["flex"] = self.flex
        result["fit"] = self.fit._flut_pack()
        result["child"] = self.child._flut_pack()
        return result


class SizedBox(Widget):
    def __init__(
        self,
        *,
        key=None,
        width: Optional[float] = None,
        height: Optional[float] = None,
        child: Optional[Widget] = None,
    ):
        super().__init__("SizedBox", key=key)
        self.width = width
        self.height = height
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        if self.width is not None:
            result["width"] = self.width
        if self.height is not None:
            result["height"] = self.height
        if self.child is not None:
            result["child"] = self.child._flut_pack()
        return result


class Column(Widget):
    def __init__(
        self,
        *,
        key=None,
        mainAxisAlignment: MainAxisAlignment = MainAxisAlignment.start,
        mainAxisSize: MainAxisSize = MainAxisSize.max,
        crossAxisAlignment: CrossAxisAlignment = CrossAxisAlignment.center,
        children: list[Widget] = [],
    ):
        super().__init__("Column", key=key)
        self.mainAxisAlignment = mainAxisAlignment
        self.mainAxisSize = mainAxisSize
        self.crossAxisAlignment = crossAxisAlignment
        self.children = children

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["children"] = [c._flut_pack() for c in self.children]
        result["mainAxisAlignment"] = self.mainAxisAlignment._flut_pack()
        result["mainAxisSize"] = self.mainAxisSize._flut_pack()
        result["crossAxisAlignment"] = self.crossAxisAlignment._flut_pack()
        return result


class Row(Widget):
    def __init__(
        self,
        *,
        key=None,
        mainAxisAlignment: MainAxisAlignment = MainAxisAlignment.start,
        mainAxisSize: MainAxisSize = MainAxisSize.max,
        crossAxisAlignment: CrossAxisAlignment = CrossAxisAlignment.center,
        children: list[Widget] = [],
    ):
        super().__init__("Row", key=key)
        self.mainAxisAlignment = mainAxisAlignment
        self.mainAxisSize = mainAxisSize
        self.crossAxisAlignment = crossAxisAlignment
        self.children = children

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["children"] = [c._flut_pack() for c in self.children]
        result["mainAxisAlignment"] = self.mainAxisAlignment._flut_pack()
        result["mainAxisSize"] = self.mainAxisSize._flut_pack()
        result["crossAxisAlignment"] = self.crossAxisAlignment._flut_pack()
        return result


class Stack(Widget):
    def __init__(self, *, key=None, children: list[Widget] = []):
        super().__init__("Stack", key=key)
        self.children = children

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["children"] = [c._flut_pack() for c in self.children]
        return result


class Positioned(Widget):
    def __init__(
        self,
        *,
        key=None,
        left: Optional[float] = None,
        top: Optional[float] = None,
        right: Optional[float] = None,
        bottom: Optional[float] = None,
        width: Optional[float] = None,
        height: Optional[float] = None,
        child,
    ):
        super().__init__("Positioned", key=key)
        self.left = left
        self.top = top
        self.right = right
        self.bottom = bottom
        self.width = width
        self.height = height
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        if self.left is not None:
            result["left"] = self.left
        if self.top is not None:
            result["top"] = self.top
        if self.right is not None:
            result["right"] = self.right
        if self.bottom is not None:
            result["bottom"] = self.bottom
        if self.width is not None:
            result["width"] = self.width
        if self.height is not None:
            result["height"] = self.height
        result["child"] = self.child._flut_pack()
        return result


class MouseRegion(Widget):

    def __init__(
        self,
        *,
        key=None,
        cursor: MouseCursor = MouseCursor.defer,
        onEnter=None,
        onExit=None,
        child: Optional[Widget] = None,
    ):
        super().__init__("MouseRegion", key=key)
        self.cursor = cursor
        self.onEnter = onEnter
        self.onExit = onExit
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["cursor"] = self.cursor._flut_pack()
        if self.onEnter is not None:
            result["onEnterId"] = self._register_action(self.onEnter)
        if self.onExit is not None:
            result["onExitId"] = self._register_action(self.onExit)
        if self.child is not None:
            result["child"] = self.child._flut_pack()
        return result


class Padding(Widget):
    def __init__(self, *, key=None, padding, child: Optional[Widget] = None):
        super().__init__("Padding", key=key)
        self.padding = padding
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["padding"] = self.padding._flut_pack()
        if self.child is not None:
            result["child"] = self.child._flut_pack()
        return result


class Align(Widget):
    def __init__(self, *, key=None, alignment: Alignment = Alignment.center, child: Optional[Widget] = None):
        super().__init__("Align", key=key)
        self.alignment = alignment
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["alignment"] = self.alignment._flut_pack()
        if self.child is not None:
            result["child"] = self.child._flut_pack()
        return result


class Opacity(Widget):
    def __init__(
        self,
        *,
        key=None,
        opacity: float,
        child: Optional[Widget] = None,
    ):
        super().__init__("Opacity", key=key)
        self.opacity = opacity
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["opacity"] = self.opacity
        if self.child is not None:
            result["child"] = self.child._flut_pack()
        return result


class ClipRRect(Widget):
    def __init__(self, *, key=None, borderRadius: BorderRadius = BorderRadius.circular(0), child: Optional[Widget] = None):
        super().__init__("ClipRRect", key=key)
        self.borderRadius = borderRadius
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["borderRadius"] = self.borderRadius._flut_pack()
        if self.child is not None:
            result["child"] = self.child._flut_pack()
        return result


class Spacer(Widget):
    def __init__(self, *, key=None, flex: int = 1):
        super().__init__("Spacer", key=key)
        self.flex = flex

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["flex"] = self.flex
        return result


class CustomPaint(Widget):
    def __init__(
        self,
        *,
        key=None,
        painter: Optional[CustomPainter] = None,
        size: Size = Size(0, 0),
        child: Optional[Widget] = None,
    ):
        super().__init__("CustomPaint", key=key)
        self.painter = painter
        self.size = size
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["size"] = self.size._flut_pack()
        if self.painter is not None:
            result["painter"] = self.painter._flut_pack()
        if self.child is not None:
            result["child"] = self.child._flut_pack()
        return result


class Wrap(Widget):
    def __init__(
        self,
        *,
        key=None,
        direction: Axis = Axis.horizontal,
        alignment: WrapAlignment = WrapAlignment.start,
        spacing: float = 0.0,
        runAlignment: WrapAlignment = WrapAlignment.start,
        runSpacing: float = 0.0,
        crossAxisAlignment: WrapCrossAlignment = WrapCrossAlignment.start,
        children: list[Widget] = [],
    ):
        super().__init__("Wrap", key=key)
        self.direction = direction
        self.alignment = alignment
        self.spacing = spacing
        self.runAlignment = runAlignment
        self.runSpacing = runSpacing
        self.crossAxisAlignment = crossAxisAlignment
        self.children = children

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["direction"] = self.direction._flut_pack()
        result["alignment"] = self.alignment._flut_pack()
        result["spacing"] = self.spacing
        result["runAlignment"] = self.runAlignment._flut_pack()
        result["runSpacing"] = self.runSpacing
        result["crossAxisAlignment"] = self.crossAxisAlignment._flut_pack()
        result["children"] = [c._flut_pack() for c in self.children]
        return result


class _TransformRotate(Widget):
    def __init__(
        self,
        *,
        key=None,
        angle: float,
        origin=None,
        alignment=None,
        transformHitTests: bool = True,
        child: Optional[Widget] = None,
    ):
        super().__init__("Transform.rotate", key=key)
        self.angle = angle
        self.origin = origin
        self.alignment = alignment
        self.transformHitTests = transformHitTests
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["angle"] = self.angle
        result["transformHitTests"] = self.transformHitTests
        if self.origin is not None:
            result["origin"] = self.origin._flut_pack()
        if self.alignment is not None:
            result["alignment"] = self.alignment._flut_pack()
        if self.child is not None:
            result["child"] = self.child._flut_pack()
        return result


class _TransformScale(Widget):
    def __init__(
        self,
        *,
        key=None,
        scale: Optional[float] = None,
        scaleX: Optional[float] = None,
        scaleY: Optional[float] = None,
        origin=None,
        alignment=None,
        transformHitTests: bool = True,
        child: Optional[Widget] = None,
    ):
        super().__init__("Transform.scale", key=key)
        self.scale = scale
        self.scaleX = scaleX
        self.scaleY = scaleY
        self.origin = origin
        self.alignment = alignment
        self.transformHitTests = transformHitTests
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["transformHitTests"] = self.transformHitTests
        if self.scale is not None:
            result["scale"] = self.scale
        if self.scaleX is not None:
            result["scaleX"] = self.scaleX
        if self.scaleY is not None:
            result["scaleY"] = self.scaleY
        if self.origin is not None:
            result["origin"] = self.origin._flut_pack()
        if self.alignment is not None:
            result["alignment"] = self.alignment._flut_pack()
        if self.child is not None:
            result["child"] = self.child._flut_pack()
        return result


class _TransformTranslate(Widget):
    def __init__(
        self,
        *,
        key=None,
        offset: Offset,
        transformHitTests: bool = True,
        child: Optional[Widget] = None,
    ):
        super().__init__("Transform.translate", key=key)
        self.offset = offset
        self.transformHitTests = transformHitTests
        self.child = child

    @override
    def _flut_pack(self) -> dict:
        result = self._flut_base_props()
        result["offset"] = self.offset._flut_pack()
        result["transformHitTests"] = self.transformHitTests
        if self.child is not None:
            result["child"] = self.child._flut_pack()
        return result


class Transform:
    rotate = _TransformRotate
    scale = _TransformScale
    translate = _TransformTranslate
