"""
point module
"""
from typing import Union
from typing import Any


class Point:
    """ Represent a two-dimensional point

    x - horizontal position
    y - vertical position
    """
    x:float
    y:float

    def __init__(self, x: Union[float, int], y: Union[float, int]) -> None:
        """ Initialize a new point with non-negative floats

        @param self Point: The current object
        @param x int|float: the 'x' unit to the right
        @param y int|float: the 'y' unit above the origin
        @rtype: None
        """
        self.x, self.y = float(x), float(y)

    def distance(self, other: 'Point') -> float:
        """ Return the distance from the origin of this point

        @param self Point: this point object
        @param other Point: Another Point object
        @rtype: float

        >>> Point(3, 4).distance(Point(0,0))
        5.0
        """
        return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** (1/2)

    def find_midpoint(self, other:'Point')->'Point':
        """ Return the midpoint between two points

        @param self Point: this point object
        @param other Point: Another Point object
        @rtype: Point

        >>> print(Point(4, 4).find_midpoint(Point(0,0)))
        (2.0, 2.0)
        """
        return Point((self.x+other.x)/2, (self.y+other.y)/2)

    def __eq__(self, other: Any) -> bool:
        """
        Return whether this point is equivalent to other.

        @param self Point: this point object
        @param other Point|Any: Another object of any class
        @rtype: bool

        >>> p1 = Point(3, 4)
        >>> p2 = Point(4, 3)
        >>> p3 = Point(3.0, 4.0)
        >>> p1 == p2
        False
        >>> p1 == p3
        True
        """
        return type(other) == type(self) and \
               (self.x == other.x) and (self.y == other.y)

    def __str__(self) -> str:
        """
        Return a user-friendly string representation of
        Point self.

        @param self Point: this point object
        @rtype: str

        >>> p = Point(3, 4)
        >>> print(p)
        (3.0, 4.0)
        """
        return "({}, {})".format(self.x, self.y)

    def __add__(self, other: 'Point') -> 'Point':
        """
        Adds two Points and return the result as a Point

        @param self Point: this point object
        @param other Point: Another Point object
        @rtype: Point

        >>> p1 = Point(3, 4)
        >>> p2 = Point(4, 4)
        >>> print(p1 + p2)
        (7.0, 8.0)
        """
        return Point(self.x + other.x, self.y + other.y)


if __name__ == "__main__":
    from doctest import testmod

    testmod()

    p1 = Point(3,4)
    p2 = Point(4,4)

    print (p1.distance(p2))
    print (p1.find_midpoint(p2))

    print(p1 == p2)
    print(p1 + p2)

    print(p1)
    print(str(p2))

