"""
AbuLang GUI Manager - Object and Draw system for graphics
Provides obj (animated objects) and draw (drawing primitives) classes
"""

import tkinter as tk
from tkinter import Canvas
import math


def rgb(r, g, b):
    """Convert RGB values (0-255) to hex color"""
    return f"#{r:02x}{g:02x}{b:02x}"


class Line:
    """Line object for creating patterns"""
    
    def __init__(self, x1, y1, x2, y2, color="black"):
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2
        self.color = color
        self.pattern_color = color
    
    def green(self):
        """Set line to green and return self for chaining"""
        self.pattern_color = "green"
        return self
    
    def red(self):
        """Set line to red and return self for chaining"""
        self.pattern_color = "red"
        return self
    
    def blue(self):
        """Set line to blue and return self for chaining"""
        self.pattern_color = "blue"
        return self
    
    def color_set(self, color):
        """Set line color and return self for chaining"""
        self.pattern_color = color
        return self


class obj:
    """
    Animated object class for GUI manager
    Can be created with obj_create(shape, top_left, bottom_right)
    Supports animation and transformations
    """
    
    def __init__(self, shape, top_left, bottom_right, canvas=None):
        """
        Initialize an object
        
        Args:
            shape: Type of shape ('rect', 'circle', 'line', 'polygon', 'text')
            top_left: Tuple (x1, y1) for top-left coordinate
            bottom_right: Tuple (x2, y2) for bottom-right coordinate
            canvas: Canvas to draw on
        """
        self.shape = shape
        self.x1, self.y1 = top_left
        self.x2, self.y2 = bottom_right
        self.canvas = canvas
        self.canvas_id = None
        self.fill_color = "white"
        self.outline_color = "black"
        self.outline_width = 1
        self.visible = True
        self.rotation = 0
        self.scale = 1.0
        self.animation_frame = 0
        self.is_animating = False
        self.animation_callback = None
        self.velocity_x = 0
        self.velocity_y = 0
        self.has_hitbox = True  # Enable hitbox by default
        self.is_solid = True  # Can collide with other objects
        
    def draw(self):
        """Draw the object on canvas"""
        if not self.canvas or not self.visible:
            return
        
        if self.shape == 'rect':
            self.canvas_id = self.canvas.create_rectangle(
                self.x1, self.y1, self.x2, self.y2,
                fill=self.fill_color,
                outline=self.outline_color,
                width=self.outline_width
            )
        elif self.shape == 'circle':
            self.canvas_id = self.canvas.create_oval(
                self.x1, self.y1, self.x2, self.y2,
                fill=self.fill_color,
                outline=self.outline_color,
                width=self.outline_width
            )
        elif self.shape == 'line':
            self.canvas_id = self.canvas.create_line(
                self.x1, self.y1, self.x2, self.y2,
                fill=self.outline_color,
                width=self.outline_width
            )
        elif self.shape == 'polygon':
            # For polygon, coordinates are passed as list
            self.canvas_id = self.canvas.create_polygon(
                self.x1, self.y1, self.x2, self.y2,
                fill=self.fill_color,
                outline=self.outline_color,
                width=self.outline_width
            )
        elif self.shape == 'text':
            self.canvas_id = self.canvas.create_text(
                (self.x1 + self.x2) // 2, (self.y1 + self.y2) // 2,
                text=str(self.x2),  # x2 holds text content
                fill=self.fill_color,
                font=("Arial", 12)
            )
    
    def move(self, dx, dy):
        """Move object by delta x, y"""
        self.x1 += dx
        self.y1 += dy
        self.x2 += dx
        self.y2 += dy
        if self.canvas_id:
            self.canvas.move(self.canvas_id, dx, dy)
    
    def set_position(self, x1, y1, x2, y2):
        """Set absolute position"""
        dx = x1 - self.x1
        dy = y1 - self.y1
        self.move(dx, dy)
        self.x2 = x2
        self.y2 = y2
    
    def set_color(self, fill=None, outline=None):
        """Set fill and outline colors"""
        if fill:
            self.fill_color = fill
        if outline:
            self.outline_color = outline
        if self.canvas_id:
            self.canvas.itemconfig(self.canvas_id, fill=self.fill_color, outline=self.outline_color)
    
    def animate(self, duration, callback=None):
        """Start animation"""
        self.is_animating = True
        self.animation_frame = 0
        self.animation_callback = callback
    
    def stop_animation(self):
        """Stop animation"""
        self.is_animating = False
        self.animation_callback = None
    
    def update_animation(self):
        """Update animation frame"""
        if self.is_animating:
            self.animation_frame += 1
            if self.animation_callback:
                self.animation_callback(self, self.animation_frame)
    
    def hide(self):
        """Hide object"""
        self.visible = False
        if self.canvas_id:
            self.canvas.itemconfig(self.canvas_id, state='hidden')
    
    def show(self):
        """Show object"""
        self.visible = True
        if self.canvas_id:
            self.canvas.itemconfig(self.canvas_id, state='normal')
    
    def delete(self):
        """Delete object from canvas"""
        if self.canvas_id:
            self.canvas.delete(self.canvas_id)
            self.canvas_id = None
    
    def velocity(self, dx, dy):
        """Set velocity for continuous movement"""
        self.velocity_x = dx
        self.velocity_y = dy
    
    def tp(self, coordinates):
        """Teleport to coordinates (x, y)"""
        x, y = coordinates
        dx = x - self.x1
        dy = y - self.y1
        self.move(dx, dy)
    
    def teleport(self, coordinates):
        """Alias for tp - teleport to coordinates"""
        self.tp(coordinates)
    
    def opposite_x(self):
        """Create a new object reflected across X axis"""
        new_obj = obj(self.shape, (self.x1, -self.y2), (self.x2, -self.y1), self.canvas)
        new_obj.fill_color = self.fill_color
        new_obj.outline_color = self.outline_color
        new_obj.outline_width = self.outline_width
        new_obj.draw()
        return new_obj
    
    def opposite_y(self):
        """Create a new object reflected across Y axis"""
        new_obj = obj(self.shape, (-self.x2, self.y1), (-self.x1, self.y2), self.canvas)
        new_obj.fill_color = self.fill_color
        new_obj.outline_color = self.outline_color
        new_obj.outline_width = self.outline_width
        new_obj.draw()
        return new_obj
    
    def get_coord(self):
        """Get object coordinates as tuple (x1, y1, x2, y2)"""
        return (self.x1, self.y1, self.x2, self.y2)
    
    def get_allcoord(self):
        """Get all object properties including coordinates"""
        return {
            'shape': self.shape,
            'x1': self.x1,
            'y1': self.y1,
            'x2': self.x2,
            'y2': self.y2,
            'fill_color': self.fill_color,
            'outline_color': self.outline_color,
            'outline_width': self.outline_width,
            'visible': self.visible,
            'velocity_x': self.velocity_x,
            'velocity_y': self.velocity_y
        }
    
    def get_hitbox(self):
        """Get hitbox as (x1, y1, x2, y2)"""
        return (self.x1, self.y1, self.x2, self.y2)
    
    def collides_with(self, other):
        """Check if this object collides with another object"""
        if not isinstance(other, obj):
            return False
        if not self.has_hitbox or not other.has_hitbox:
            return False
        
        # AABB collision detection
        return (self.x1 < other.x2 and self.x2 > other.x1 and
                self.y1 < other.y2 and self.y2 > other.y1)
    
    def set_solid(self, solid):
        """Set whether object can collide"""
        self.is_solid = solid


class draw:
    """
    Drawing class for GUI manager
    Drawn on top of obj items
    """
    
    def __init__(self, canvas=None):
        """
        Initialize draw object
        
        Args:
            canvas: Canvas to draw on
        """
        self.canvas = canvas
        self.items = []
        self.fill_color = "black"
        self.outline_color = "black"
        self.outline_width = 1
    
    def set_color(self, fill=None, outline=None):
        """Set drawing colors"""
        if fill:
            self.fill_color = fill
        if outline:
            self.outline_color = outline
    
    def line(self, x1, y1, x2, y2, color=None, width=None):
        """Draw a line"""
        if not self.canvas:
            return None
        c = color or self.outline_color
        w = width or self.outline_width
        item_id = self.canvas.create_line(x1, y1, x2, y2, fill=c, width=w)
        self.items.append(item_id)
        return item_id
    
    def rect(self, x1, y1, x2, y2, fill=None, outline=None, width=None):
        """Draw a rectangle"""
        if not self.canvas:
            return None
        f = fill or self.fill_color
        o = outline or self.outline_color
        w = width or self.outline_width
        item_id = self.canvas.create_rectangle(x1, y1, x2, y2, fill=f, outline=o, width=w)
        self.items.append(item_id)
        return item_id
    
    def circle(self, x1, y1, x2, y2, fill=None, outline=None, width=None):
        """Draw a circle/oval"""
        if not self.canvas:
            return None
        f = fill or self.fill_color
        o = outline or self.outline_color
        w = width or self.outline_width
        item_id = self.canvas.create_oval(x1, y1, x2, y2, fill=f, outline=o, width=w)
        self.items.append(item_id)
        return item_id
    
    def text(self, x, y, text, color=None, font_size=12):
        """Draw text"""
        if not self.canvas:
            return None
        c = color or self.fill_color
        item_id = self.canvas.create_text(x, y, text=str(text), fill=c, font=("Arial", font_size))
        self.items.append(item_id)
        return item_id
    
    def polygon(self, coords, fill=None, outline=None, width=None):
        """Draw a polygon"""
        if not self.canvas:
            return None
        f = fill or self.fill_color
        o = outline or self.outline_color
        w = width or self.outline_width
        item_id = self.canvas.create_polygon(*coords, fill=f, outline=o, width=w)
        self.items.append(item_id)
        return item_id
    
    def clear(self):
        """Clear all drawn items"""
        for item_id in self.items:
            if self.canvas:
                self.canvas.delete(item_id)
        self.items = []
    
    def opposite_x(self):
        """Create a new draw reflected across X axis"""
        new_draw = draw(self.canvas)
        new_draw.fill_color = self.fill_color
        new_draw.outline_color = self.outline_color
        new_draw.outline_width = self.outline_width
        return new_draw
    
    def opposite_y(self):
        """Create a new draw reflected across Y axis"""
        new_draw = draw(self.canvas)
        new_draw.fill_color = self.fill_color
        new_draw.outline_color = self.outline_color
        new_draw.outline_width = self.outline_width
        return new_draw


class GUIManager:
    """
    Main GUI Manager for AbuLang
    Manages canvas, objects, and drawing
    """
    
    def __init__(self, width=800, height=600, title="AbuLang GUI"):
        """Initialize GUI Manager"""
        self.width = width
        self.height = height
        self.title = title
        self.root = tk.Tk()
        self.root.title(title)
        self.root.geometry(f"{width}x{height}")
        self.root.withdraw()  # Hide window initially
        
        self.canvas = Canvas(self.root, width=width, height=height, bg="white")
        self.canvas.pack()
        
        self.objects = []
        self.draw_layer = draw(self.canvas)
        self.running = False
        self.animation_speed = 30  # ms per frame
    
    def obj_create(self, shape, top_left, bottom_right):
        """Create an object"""
        new_obj = obj(shape, top_left, bottom_right, self.canvas)
        new_obj.draw()
        self.objects.append(new_obj)
        return new_obj
    
    def get_draw(self):
        """Get draw layer"""
        return self.draw_layer
    
    def update(self):
        """Update animation frames"""
        for o in self.objects:
            o.update_animation()
        self.canvas.after(self.animation_speed, self.update)
    
    def run(self):
        """Start GUI loop"""
        self.running = True
        self.root.deiconify()  # Show window
        self.update()
        self.root.mainloop()
    
    def stop(self):
        """Stop GUI"""
        self.running = False
        self.root.quit()
    
    def clear(self):
        """Clear all objects"""
        for o in self.objects:
            o.delete()
        self.objects = []
        self.draw_layer.clear()
    
    def redraw(self):
        """Redraw canvas"""
        self.canvas.delete("all")
        for o in self.objects:
            o.draw()
    
    def create_surface(self, color="green"):
        """Create a surface (background fill)"""
        surface = obj('rect', (0, 0), (self.width, self.height), self.canvas)
        surface.set_color(fill=color, outline=color)
        surface.draw()
        self.objects.insert(0, surface)  # Add to back
        return surface
    
    def fill_halfmany(self, line_obj):
        """
        Fill with cross-hatch pattern using line object
        Creates diagonal lines across the canvas
        """
        if not isinstance(line_obj, Line):
            raise TypeError("fill_halfmany requires a Line object")
        
        spacing = 20
        color = line_obj.pattern_color
        
        # Diagonal lines from top-left to bottom-right
        for i in range(-self.height, self.width, spacing):
            self.draw_layer.line(i, 0, i + self.height, self.height, color=color, width=1)
        
        # Diagonal lines from top-right to bottom-left
        for i in range(0, self.width + self.height, spacing):
            self.draw_layer.line(i, 0, i - self.height, self.height, color=color, width=1)
    
    def coordinate_map(self, obj_list):
        """Map coordinates of multiple objects"""
        coord_map = {}
        for i, o in enumerate(obj_list):
            coord_map[f"obj_{i}"] = o.get_coord()
        return coord_map
