import json
import hashlib

def rgba_to_hex(rgba):
    """
    Convert an RGBA dict into a #RRGGBB hex string (ignoring alpha in this demo).
    """
    r = int(rgba["r"] * 255)
    g = int(rgba["g"] * 255)
    b = int(rgba["b"] * 255)
    return f"#{r:02x}{g:02x}{b:02x}"

def style_hash(style_data):
    """
    Create a hash from style data to use as a unique identifier.
    """
    style_str = json.dumps(style_data, sort_keys=True)
    return hashlib.md5(style_str.encode()).hexdigest()

def figma_align_to_flex(figma_val):
    """
    Convert Figma alignment values to CSS flex values.
    """
    align_map = {
        "MIN": "flex-start",
        "CENTER": "center",
        "MAX": "flex-end",
        "SPACE_BETWEEN": "space-between"
    }
    return align_map.get(figma_val, "flex-start")

def get_fill_style_id(fills, styles):
    """
    Process fill styles and add them to the styles dictionary.
    """
    if not fills or len(fills) == 0 or fills[0].get("visible", True) == False:
        return None
    
    fill = fills[0]
    
    if fill["type"] == "SOLID":
        color = fill["color"]
        opacity = fill.get("opacity", 1)
        
        # Create a style object
        style_data = {
            "backgroundColor": rgba_to_hex(color),
            "opacity": opacity
        }
        
        # Generate a unique ID for this style
        style_id = style_hash(style_data)
        
        # Add to styles dictionary if not already present
        if style_id not in styles:
            styles[style_id] = style_data
        
        return style_id
    
    return None

def get_layout_style_id(raw_node, styles):
    """
    Process layout styles and add them to the styles dictionary.
    """
    layout_style = {}
    
    # Extract layout properties
    if "layoutMode" in raw_node:
        layout_mode = raw_node["layoutMode"]
        
        if layout_mode == "HORIZONTAL":
            layout_style["display"] = "flex"
            layout_style["flexDirection"] = "row"
        elif layout_mode == "VERTICAL":
            layout_style["display"] = "flex"
            layout_style["flexDirection"] = "column"
        
        # Process padding
        if "paddingLeft" in raw_node:
            layout_style["paddingLeft"] = f"{raw_node['paddingLeft']}px"
        if "paddingRight" in raw_node:
            layout_style["paddingRight"] = f"{raw_node['paddingRight']}px"
        if "paddingTop" in raw_node:
            layout_style["paddingTop"] = f"{raw_node['paddingTop']}px"
        if "paddingBottom" in raw_node:
            layout_style["paddingBottom"] = f"{raw_node['paddingBottom']}px"
        
        # Process spacing
        if "itemSpacing" in raw_node:
            layout_style["gap"] = f"{raw_node['itemSpacing']}px"
        
        # Process alignment
        if "primaryAxisAlignItems" in raw_node:
            primary_align = raw_node["primaryAxisAlignItems"]
            counter_align = raw_node.get("counterAxisAlignItems", "MIN")
            
            def align_map_primary(val):
                if layout_mode == "HORIZONTAL":
                    return figma_align_to_flex(val)
                return figma_align_to_flex(val)
            
            def align_map_counter(val):
                if layout_mode == "HORIZONTAL":
                    return figma_align_to_flex(val)
                return figma_align_to_flex(val)
            
            layout_style["justifyContent"] = align_map_primary(primary_align)
            layout_style["alignItems"] = align_map_counter(counter_align)
    
    # Process size constraints
    if "absoluteBoundingBox" in raw_node:
        bbox = raw_node["absoluteBoundingBox"]
        layout_style["width"] = f"{bbox['width']}px"
        layout_style["height"] = f"{bbox['height']}px"
    
    # Process border radius
    border_radius = get_border_radius(raw_node)
    if border_radius:
        layout_style["borderRadius"] = border_radius
    
    # Process corner smoothing
    corner_smoothing = get_corner_smoothing(raw_node)
    if corner_smoothing:
        layout_style["borderRadius"] = corner_smoothing
    
    # Generate a unique ID for this style if it's not empty
    if layout_style:
        style_id = style_hash(layout_style)
        
        # Add to styles dictionary if not already present
        if style_id not in styles:
            styles[style_id] = layout_style
        
        return style_id
    
    return None

def get_border_radius(raw_node):
    """
    Extract border radius from a node.
    """
    if "cornerRadius" in raw_node:
        return f"{raw_node['cornerRadius']}px"
    return None

def get_corner_smoothing(raw_node):
    """
    Extract corner smoothing from a node.
    """
    if "cornerSmoothing" in raw_node and raw_node["cornerSmoothing"] > 0:
        return f"{raw_node['cornerSmoothing']}px"
    return None

def get_text_style_id(raw_node, styles):
    """
    Process text styles and add them to the styles dictionary.
    """
    if raw_node["type"] != "TEXT" or "style" not in raw_node:
        return None
    
    text_style = {}
    node_style = raw_node["style"]
    
    # Extract text properties
    if "fontFamily" in node_style:
        text_style["fontFamily"] = node_style["fontFamily"]
    if "fontWeight" in node_style:
        text_style["fontWeight"] = node_style["fontWeight"]
    if "fontSize" in node_style:
        text_style["fontSize"] = f"{node_style['fontSize']}px"
    if "lineHeightPx" in node_style:
        text_style["lineHeight"] = f"{node_style['lineHeightPx']}px"
    if "letterSpacing" in node_style:
        text_style["letterSpacing"] = f"{node_style['letterSpacing']}px"
    if "textAlignHorizontal" in node_style:
        align_map = {"LEFT": "left", "CENTER": "center", "RIGHT": "right", "JUSTIFIED": "justify"}
        text_style["textAlign"] = align_map.get(node_style["textAlignHorizontal"], "left")
    
    # Process fill color for text
    if "fills" in raw_node and raw_node["fills"]:
        fill = raw_node["fills"][0]
        if fill["type"] == "SOLID":
            text_style["color"] = rgba_to_hex(fill["color"])
    
    # Generate a unique ID for this style if it's not empty
    if text_style:
        style_id = style_hash(text_style)
        
        # Add to styles dictionary if not already present
        if style_id not in styles:
            styles[style_id] = text_style
        
        return style_id
    
    return None

def transform_node(raw_node, styles):
    """
    Transform a Figma node into a simplified structure.
    """
    node_type = raw_node["type"]
    
    # Basic node properties
    node = {
        "id": raw_node["id"],
        "name": raw_node["name"],
        "type": node_type,
        "visible": raw_node.get("visible", True)
    }
    
    # Process styles
    fill_style_id = get_fill_style_id(raw_node.get("fills", []), styles)
    if fill_style_id:
        node["fillStyleId"] = fill_style_id
    
    layout_style_id = get_layout_style_id(raw_node, styles)
    if layout_style_id:
        node["layoutStyleId"] = layout_style_id
    
    text_style_id = get_text_style_id(raw_node, styles)
    if text_style_id:
        node["textStyleId"] = text_style_id
    
    # Process text content
    if node_type == "TEXT" and "characters" in raw_node:
        node["characters"] = raw_node["characters"]
    
    # Process image content
    if node_type == "RECTANGLE" and "fills" in raw_node:
        for fill in raw_node.get("fills", []):
            if fill["type"] == "IMAGE" and "imageRef" in fill:
                node["imageRef"] = fill["imageRef"]
    
    # Process children
    if "children" in raw_node:
        node["children"] = []
        for child in raw_node["children"]:
            # Skip invisible nodes
            if child.get("visible", True) == False:
                continue
            
            transformed_child = transform_node(child, styles)
            node["children"].append(transformed_child)
    
    # Process component properties
    if "componentPropertyReferences" in raw_node:
        node["componentPropertyReferences"] = raw_node["componentPropertyReferences"]
    
    # Process component properties
    if "componentProperties" in raw_node:
        node["componentProperties"] = raw_node["componentProperties"]
    
    # Process component property definitions
    if "componentPropertyDefinitions" in raw_node:
        node["componentPropertyDefinitions"] = raw_node["componentPropertyDefinitions"]
    
    # Process variants
    if "variantProperties" in raw_node:
        node["variantProperties"] = raw_node["variantProperties"]
    
    # Process component set
    if "componentSetId" in raw_node:
        node["componentSetId"] = raw_node["componentSetId"]
    
    # Process component
    if "componentId" in raw_node:
        node["componentId"] = raw_node["componentId"]
    
    return node

def transform_figma_json(raw_data):
    """
    Transform Figma JSON data into a simplified structure.
    """
    # Initialize styles dictionary
    styles = {}
    
    # Transform the document
    if isinstance(raw_data, dict) and "document" in raw_data:
        document = transform_node(raw_data["document"], styles)
    else:
        document = transform_node(raw_data, styles)
    
    # Return the transformed data
    return {
        "document": document,
        "styles": styles
    } 