#!/usr/bin/env python3
"""
Demo: Working Interactive Table with Buttons

This example shows a fully working interactive table where buttons are
actually rendered inside table cells and can handle click events.

This uses a hybrid approach:
1. Tables are rendered normally for structure
2. Buttons are rendered on top at calculated positions
3. Click detection maps coordinates to button callbacks
"""

from pyWebLayout.concrete.page import Page
from pyWebLayout.concrete.table import TableRenderer, TableStyle
from pyWebLayout.concrete.functional import ButtonText
from pyWebLayout.abstract.functional import Button
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.style import Font
from pyWebLayout.abstract.block import Table, TableRow, TableCell, Paragraph
from pyWebLayout.abstract.inline import Word
from PIL import Image, ImageDraw
import numpy as np


def create_interactive_table():
    """Create a table structure (buttons will be overlaid)."""
    table = Table()
    table.caption = "User Management with Interactive Buttons"

    font = Font(font_size=11)

    # Header
    header_row = TableRow()
    for i, text in enumerate(["ID", "Name", "Email", "Actions"]):
        cell = TableCell(is_header=True)
        # Set width for Actions column
        if text == "Actions":
            cell.width = "220px"  # Enough for 3 buttons
        para = Paragraph(font)
        para.add_word(Word(text, font))
        cell.add_block(para)
        header_row.add_cell(cell)
    table.add_row(header_row, section="header")

    # Body rows
    users = [
        ("U001", "Alice Johnson", "alice@example.com"),
        ("U002", "Bob Smith", "bob@example.com"),
        ("U003", "Charlie Brown", "charlie@example.com"),
    ]

    for user_id, name, email in users:
        row = TableRow()

        # ID
        cell = TableCell()
        para = Paragraph(font)
        para.add_word(Word(user_id, font))
        cell.add_block(para)
        row.add_cell(cell)

        # Name
        cell = TableCell()
        para = Paragraph(font)
        para.add_word(Word(name, font))
        cell.add_block(para)
        row.add_cell(cell)

        # Email
        cell = TableCell()
        para = Paragraph(font)
        para.add_word(Word(email, font))
        cell.add_block(para)
        row.add_cell(cell)

        # Actions - leave empty for buttons to be overlaid
        # Set width hint to ensure space for 3 buttons
        cell = TableCell()
        cell.width = "220px"  # Enough for 3 buttons (3 × 65px + padding)
        para = Paragraph(font)
        para.add_word(Word("", font))  # Empty placeholder
        cell.add_block(para)
        row.add_cell(cell)

        table.add_row(row, section="body")

    return table


def render_buttons_in_table(canvas, draw, table_origin, column_widths, row_heights, users):
    """
    Render interactive buttons inside the table cells.

    This calculates the exact position of each button based on the table
    layout and renders ButtonText objects at those positions.

    Args:
        canvas: PIL Image canvas
        draw: PIL ImageDraw object
        table_origin: (x, y) position of table top-left
        column_widths: List of column widths
        row_heights: Dict with 'header', 'body', 'footer' keys
        users: User data for button labels

    Returns:
        List of (button, bounds) for click detection
    """
    button_font = Font(font_size=10)
    buttons_with_bounds = []

    # Calculate Actions column position (column 3, index 3)
    actions_col_x = table_origin[0] + sum(column_widths[:3]) + 3 * 2  # +borders
    actions_col_width = column_widths[3]

    # Start after caption and header row
    # Caption takes 20px + 10px spacing = 30px
    caption_height = 30
    header_height = row_heights.get("header", 30)
    current_y = table_origin[1] + caption_height + header_height + 2  # +caption +header +border

    for i, (user_id, name, email) in enumerate(users):
        row_height = row_heights.get("body", 30)  # All body rows have same height

        # Position buttons horizontally in the Actions cell
        button_x = actions_col_x + 10  # Padding from cell edge
        button_y = current_y + (row_height - 30) // 2  # Center vertically

        # Create buttons for this row
        # Note: Button callbacks receive click point as first argument
        buttons = [
            ("View", lambda point, uid=user_id: print(f"View {uid}")),
            ("Edit", lambda point, uid=user_id: print(f"Edit {uid}")),
            ("Delete", lambda point, uid=user_id: print(f"Delete {uid}"))
        ]

        for label, callback in buttons:
            # Create button
            abstract_button = Button(label=label, callback=callback)
            button_text = ButtonText(
                button=abstract_button,
                font=button_font,
                draw=draw,
                padding=(6, 12, 6, 12)
            )

            # Set position
            button_text._origin = np.array([button_x, button_y])

            # Render button
            button_text.render()

            # Store bounds for click detection
            button_width = 60  # Approximate
            button_height = 25
            bounds = (button_x, button_y, button_x + button_width, button_y + button_height)
            buttons_with_bounds.append((abstract_button, bounds))

            # Move to next button position
            button_x += 65

        # Move to next row
        current_y += row_height + 1  # +border

    return buttons_with_bounds


def handle_click(click_pos, buttons_with_bounds):
    """
    Handle a click event by checking if it's inside any button bounds.

    Args:
        click_pos: (x, y) tuple of click position
        buttons_with_bounds: List of (button, bounds) tuples

    Returns:
        True if a button was clicked, False otherwise
    """
    click_x, click_y = click_pos

    for button, (x1, y1, x2, y2) in buttons_with_bounds:
        if x1 <= click_x <= x2 and y1 <= click_y <= y2:
            # Click is inside this button!
            button.execute(click_pos)
            return True

    return False


def main():
    # Create page
    page_size = (900, 500)  # Increased height to fit instructions
    page_style = PageStyle(
        border_width=1,
        padding=(20, 20, 20, 20),
        background_color=(255, 255, 255)
    )
    page = Page(size=page_size, style=page_style)
    canvas = page._create_canvas()
    page._canvas = canvas
    page._draw = ImageDraw.Draw(canvas)

    # Table style
    table_style = TableStyle(
        border_width=1,
        border_color=(100, 100, 100),
        cell_padding=(8, 10, 8, 10),
        header_bg_color=(220, 230, 240),
        cell_bg_color=(255, 255, 255),
        alternate_row_color=(248, 248, 248)
    )

    # User data
    users = [
        ("U001", "Alice Johnson", "alice@example.com"),
        ("U002", "Bob Smith", "bob@example.com"),
        ("U003", "Charlie Brown", "charlie@example.com"),
    ]

    # Create and render table
    table = create_interactive_table()
    table_origin = (20, 30)
    renderer = TableRenderer(
        table,
        origin=table_origin,
        available_width=860,
        draw=page._draw,
        style=table_style,
        canvas=canvas
    )
    renderer.render()

    # Get table dimensions for button positioning
    column_widths = renderer._column_widths
    row_heights = renderer._row_heights

    # Render interactive buttons on top of table
    buttons_with_bounds = render_buttons_in_table(
        canvas, page._draw, table_origin,
        column_widths, row_heights, users
    )

    # Add instructions (position below the table)
    # Calculate actual table height based on rows
    header_height = row_heights.get("header", 30)
    body_height = row_heights.get("body", 30) * len(users)
    actual_table_height = header_height + body_height + (len(users) + 2) * 2  # +borders

    inst_font = Font(font_size=12)
    y_offset = table_origin[1] + actual_table_height + 50
    page._draw.text(
        (20, y_offset),
        "Interactive Table Demo:",
        fill=(50, 50, 50),
        font=inst_font.font
    )

    note_font = Font(font_size=10)
    page._draw.text(
        (20, y_offset + 25),
        "• Buttons are rendered at calculated positions within table cells",
        fill=(80, 80, 80),
        font=note_font.font
    )
    page._draw.text(
        (20, y_offset + 45),
        "• Click detection maps coordinates to button callbacks",
        fill=(80, 80, 80),
        font=note_font.font
    )
    page._draw.text(
        (20, y_offset + 65),
        "• Try simulated clicks below:",
        fill=(80, 80, 80),
        font=note_font.font
    )

    # Save
    output_path = "docs/images/example_14_interactive_table.png"
    canvas.save(output_path)

    print(f"✓ Working interactive table demo created!")
    print(f"  Output: {output_path}")
    print(f"  Image size: {canvas.size}")
    print(f"\nDemonstrating button click detection:")

    # Simulate some clicks to demonstrate functionality
    actions_col_x = table_origin[0] + sum(column_widths[:3]) + 6
    caption_height = 30
    header_height = row_heights.get("header", 30)
    body_row_height = row_heights.get("body", 30)

    # Calculate first body row position (after caption + header + border)
    first_row_y = table_origin[1] + caption_height + header_height + 2

    test_clicks = [
        (100, 100, "Click outside table"),
        (actions_col_x + 10, first_row_y + 15, "View button - Alice"),
        (actions_col_x + 75, first_row_y + 15, "Edit button - Alice"),
        (actions_col_x + 140, first_row_y + 15, "Delete button - Alice"),
        (actions_col_x + 10, first_row_y + body_row_height + 17, "View button - Bob"),
    ]

    for x, y, desc in test_clicks:
        print(f"\n  Click at ({x}, {y}) - {desc}:")
        clicked = handle_click((x, y), buttons_with_bounds)
        if not clicked:
            print(f"    No button at this position")


if __name__ == "__main__":
    main()
