from __future__ import annotations
from ..function import *
import math
from enum import Enum

class Vec2D:
    x: float = 0
    y: float = 0
    def __init__(self, x=0.0, y=0.0):
        self.x = float(x)
        self.y = float(y)

    # Vec2D + Vec2D
    def __add__(self, v: Vec2D):
        return Vec2D(self.x + v.x, self.y + v.y)

    # Vec2D - Vec2D
    def __sub__(self, v: Vec2D):
        return Vec2D(self.x - v.x, self.y - v.y)

    # Vec2D * scalar
    def __mul__(self, s: float):
        if isinstance(s, (int, float)):
            return Vec2D(self.x * s, self.y * s)
        return NotImplemented
    
    # Vec2D / scalar
    def __truediv__(self, s: float):
        if isinstance(s, (int, float)):
            return Vec2D(self.x / s, self.y / s)
        return NotImplemented

    # Vec2D += Vec2D
    def __iadd__(self, v: Vec2D):
        self.x += v.x
        self.y += v.y
        return self
    
    # Vec2D -= Vec2D
    def __isub__(self, v: Vec2D):
        self.x -= v.x
        self.y -= v.y
        return self

    # Vec2D *= scalar
    def __imul__(self, s: float):
        if isinstance(s, (int, float)):
            self.x *= s
            self.y *= s
            return self
        return NotImplemented

    # Vec2D /= scalar
    def __itruediv__(self, s: float):
        if isinstance(s, (int, float)):
            self.x /= s
            self.y /= s
            return self
        return NotImplemented

    # 長さ（距離）
    def length(self):
        return math.sqrt(self.x * self.x + self.y * self.y)

    def __repr__(self):
        return f"Vec2D(x: {self.x}, y: {self.y})"

class Vec3D:
    x: float = 0
    y: float = 0
    z: float = 0
    def __init__(self, x=0.0, y=0.0, z=0.0):
        self.x = float(x)
        self.y = float(y)
        self.z = float(z)

     # Vec3D + Vec3D
    def __add__(self, v: Vec3D):
        return Vec3D(self.x + v.x, self.y + v.y, self.z + v.z)

    # Vec3D - Vec3D
    def __sub__(self, v: Vec3D):
        return Vec3D(self.x - v.x, self.y - v.y, self.z - v.z)
        
    # Vec3D * scalar
    def __mul__(self, s: float):
        if isinstance(s, (int, float)):
            return Vec3D(self.x * s, self.y * s, self.z * s)
        return NotImplemented
    
    # Vec3D / scalar
    def __truediv__(self, s: float):
        if isinstance(s, (int, float)):
            return Vec3D(self.x / s, self.y / s, self.z / s)
        return NotImplemented
        
    # Vec3D += Vec3D
    def __iadd__(self, v: Vec3D):
        self.x += v.x
        self.y += v.y
        self.z += v.z
        return self
    
    # Vec3D -= Vec3D
    def __isub__(self, v: Vec3D):
        self.x -= v.x
        self.y -= v.y
        self.z -= v.z
        return self

    # Vec3D *= scalar
    def __imul__(self, s: float):
        if isinstance(s, (int, float)):
            self.x *= s
            self.y *= s
            self.z *= s
            return self
        return NotImplemented

    # Vec3D /= scalar
    def __itruediv__(self, s: float):
        if isinstance(s, (int, float)):
            self.x /= s
            self.y /= s
            self.z /= s
            return self
        return NotImplemented

    def length(self):
        return math.sqrt(self.x**2 + self.y**2 + self.z**2)

    def normalized(self):
        l = self.length()
        if l == 0:
            return Vec3D(0,0,0)  # ゼロベクトルの場合
        return Vec3D(self.x / l,
                    self.y / l,
                    self.z / l)
    
    def __repr__(self):
        return f"Vec3D(x: {self.x}, y: {self.y}, z: {self.z})"
    
class Rect:
    def __init__(self, x=0, y=0, w=0, h=0):
        self.x = x
        self.y = y
        self.w = w
        self.h = h

class RGBA:
    def __init__(self, r=255, g=255, b=255, a=255):
        self.r = r
        self.g = g
        self.b = b
        self.a = a

class Event:
    def __init__(self):
        self._id = -1

    def pressed(self, key):
        return lib.event_pressed(self._id, key)
    
    def released(self, key):
        return lib.event_released(self._id, key)
    
    def down(self, key):
        return lib.event_down(self._id, key)
        
    def up(self, key):
        return lib.event_up(self._id, key)
    
class SurfaceType(Enum):
    TEXTURE = 1
    WINDOW = 2

class Surface:
    _id: int
    type: SurfaceType
    def __init__(self):
        pass

class Window(Surface):
    # _id: int
    def __init__(self, width, height, title):
        self._id = lib.create_window(int(width), int(height), title.encode("utf-8"), True)
        self.__width = width
        self.__height = height
        self.__title = title
        self.type = SurfaceType.WINDOW

    def closed(self):
        return lib.window_closed(self._id)
    
    def clear(self, color: RGBA):
        lib.clear_win(self._id, color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0)

    def swap(self):
        lib.swap_win(self._id)

    def get_event(self):
        event = Event()
        event._id = lib.get_event(self._id)
        return event

class Texture:
    def __init__(self, width: int=-1, height: int=-1):
        self._id = -1
        if width >= 0 and height >= 0:
            self._id = lib.create_texture(width, height)
        self.type = SurfaceType.TEXTURE

    def clear(self, color: RGBA):
        lib.clear_tex(self._id, color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0)

    @classmethod
    def from_cropped_image(cls, img: Image, rect: Rect):
        # tex = Texture()
        tex = cls(rect.w, rect.h)
        lib.crop_image_to_texture(img._id, rect.x, rect.y, rect.w, rect.h, tex._id, False)
        return tex

class Image:
    def __init__(self, width: int=-1, height: int=-1):
        self._id = -1
        if width >= 0 and height >= 0:
            self._id = lib.create_image(width, height)

class Font:
    def __init__(self):
        self._id = -1