"""Browser chrome (GTK UI)."""

import gi
from typing import Optional
import logging

gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, Gdk, GdkPixbuf
from functools import partial

import skia


class Chrome:
    def __init__(self, browser):
        self.logger = logging.getLogger("bowser.chrome")
        self.browser = browser
        self.window: Optional[Gtk.ApplicationWindow] = None
        self.address_bar: Optional[Gtk.Entry] = None
        self.back_btn: Optional[Gtk.Button] = None
        self.forward_btn: Optional[Gtk.Button] = None
        self.reload_btn: Optional[Gtk.Button] = None
        self.go_btn: Optional[Gtk.Button] = None
        self.drawing_area: Optional[Gtk.DrawingArea] = None
        self.tabs_box: Optional[Gtk.Box] = None
        self.skia_surface: Optional[skia.Surface] = None

    def create_window(self):
        """Initialize the GTK application window."""
        self.window = Gtk.ApplicationWindow(application=self.browser.app)
        self.window.set_default_size(1024, 768)
        self.window.set_title("Bowser")

        # Main vertical box
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
        self.window.set_child(vbox)

        # Top bar: address bar + buttons
        top_bar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        top_bar.set_margin_top(5)
        top_bar.set_margin_bottom(5)
        top_bar.set_margin_start(5)
        top_bar.set_margin_end(5)

        self.back_btn = Gtk.Button(label="◀")
        self.forward_btn = Gtk.Button(label="▶")
        self.reload_btn = Gtk.Button(label="⟳")

        self.address_bar = Gtk.Entry()
        self.address_bar.set_text("https://example.com")
        self.address_bar.set_hexpand(True)

        self.go_btn = Gtk.Button(label="Go")

        top_bar.append(self.back_btn)
        top_bar.append(self.forward_btn)
        top_bar.append(self.reload_btn)
        top_bar.append(self.address_bar)
        top_bar.append(self.go_btn)

        vbox.append(top_bar)

        # Tabs bar: contains tab buttons and a new-tab button
        self.tabs_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=4)
        self.tabs_box.set_margin_start(5)
        self.tabs_box.set_margin_end(5)
        self.tabs_box.set_margin_bottom(4)
        vbox.append(self.tabs_box)

        # Drawing area for content
        self.drawing_area = Gtk.DrawingArea()
        self.drawing_area.set_vexpand(True)
        self.drawing_area.set_hexpand(True)
        self.drawing_area.set_draw_func(self.on_draw)
        vbox.append(self.drawing_area)

        # Status bar
        status_bar = Gtk.Label(label="Ready")
        status_bar.set_xalign(0)
        status_bar.set_margin_start(5)
        vbox.append(status_bar)

        self.window.present()
        # Build initial tab bar now that window exists
        self.rebuild_tab_bar()

        # Wire handlers
        if self.address_bar:
            self.address_bar.connect("activate", self._on_addressbar_activate)
        if self.go_btn:
            self.go_btn.connect("clicked", self._on_go_clicked)
        if self.back_btn:
            self.back_btn.connect("clicked", lambda _b: self.browser.go_back())
        if self.forward_btn:
            self.forward_btn.connect("clicked", lambda _b: self.browser.go_forward())
        if self.reload_btn:
            self.reload_btn.connect("clicked", lambda _b: self.browser.reload())

    def _clear_children(self, box: Gtk.Box):
        child = box.get_first_child()
        while child is not None:
            nxt = child.get_next_sibling()
            box.remove(child)
            child = nxt

    def rebuild_tab_bar(self):
        """Recreate tab buttons to reflect current tabs and active tab."""
        if not self.tabs_box:
            return
        self._clear_children(self.tabs_box)

        # Add a button per tab with a close '×' control
        for i, tab in enumerate(self.browser.tabs):
            # Composite tab widget: label button + inline close button in one container
            tab_container = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
            tab_container.add_css_class("linked")  # visual integration

            label = f"{i+1}: {tab.title}"
            tab_btn = Gtk.Button(label=label)
            tab_btn.set_hexpand(False)
            if tab is self.browser.active_tab:
                tab_btn.add_css_class("suggested-action")
            tab_btn.connect("clicked", partial(self.browser.set_active_tab, tab))

            close_btn = Gtk.Button(label="×")
            close_btn.add_css_class("flat")
            close_btn.connect("clicked", partial(self.browser.close_tab, tab))

            tab_container.append(tab_btn)
            tab_container.append(close_btn)
            self.tabs_box.append(tab_container)

        # New tab '+' button at the end
        plus_btn = Gtk.Button(label="+")
        plus_btn.connect("clicked", lambda _b: self.browser.new_tab("https://example.com"))
        self.tabs_box.append(plus_btn)

    def update_address_bar(self):
        if not self.address_bar:
            return
        url = None
        if self.browser.active_tab and self.browser.active_tab.current_url:
            url = str(self.browser.active_tab.current_url)
        self.address_bar.set_text(url or "")

    # Handlers
    def _on_addressbar_activate(self, entry: Gtk.Entry):
        self.browser.navigate_to(entry.get_text())

    def _on_go_clicked(self, _btn: Gtk.Button):
        if self.address_bar:
            self.browser.navigate_to(self.address_bar.get_text())

    def on_draw(self, drawing_area, context, width, height):
        """Callback for drawing the content area using Skia."""
        self.logger.debug(f"on_draw start {width}x{height}")
        # Create Skia surface for this frame
        self.skia_surface = skia.Surface(width, height)
        canvas = self.skia_surface.getCanvas()

        # White background
        canvas.clear(skia.ColorWHITE)

        # Get content to render
        content_text = self._get_content_text()
        
        if content_text:
            # Render actual page content with text wrapping
            self._render_text_content(canvas, content_text, width, height)
        else:
            # Show placeholder
            paint = skia.Paint()
            paint.setAntiAlias(True)
            paint.setColor(skia.ColorBLACK)
            font = skia.Font(skia.Typeface.MakeDefault(), 20)
            canvas.drawString("Bowser — Enter a URL to browse", 20, 50, font, paint)

        # Convert Skia surface to GTK Pixbuf and blit to Cairo context
        image = self.skia_surface.makeImageSnapshot()
        png_data = image.encodeToData().bytes()

        # Load PNG data into a Pixbuf
        from io import BytesIO

        loader = GdkPixbuf.PixbufLoader.new_with_type("png")
        loader.write(png_data)
        loader.close()
        pixbuf = loader.get_pixbuf()

        # Render pixbuf to Cairo context
        Gdk.cairo_set_source_pixbuf(context, pixbuf, 0, 0)
        context.paint()
        self.logger.debug("on_draw end")
    
    def _get_content_text(self) -> str:
        """Extract text content from active tab's document."""
        if not self.browser.active_tab:
            return ""
        
        frame = self.browser.active_tab.main_frame
        if not frame.document:
            return ""
        
        # Extract text from document tree
        return self._extract_text(frame.document)
    
    def _extract_text(self, node) -> str:
        """Recursively extract text from HTML tree."""
        from ..parser.html import Text, Element
        
        if isinstance(node, Text):
            return node.text
        elif isinstance(node, Element):
            texts = []
            for child in node.children:
                texts.append(self._extract_text(child))
            return " ".join(texts)
        return ""
    
    def _render_text_content(self, canvas, text: str, width: int, height: int):
        """Render text content with basic word wrapping."""
        paint = skia.Paint()
        paint.setAntiAlias(True)
        paint.setColor(skia.ColorBLACK)
        
        font_size = 14
        font = skia.Font(skia.Typeface.MakeDefault(), font_size)
        
        # Simple word wrapping
        words = text.split()
        lines = []
        current_line = []
        current_width = 0
        max_width = width - 40  # 20px margin on each side
        
        for word in words:
            word_width = font.measureText(word + " ")
            
            if current_width + word_width > max_width and current_line:
                lines.append(" ".join(current_line))
                current_line = [word]
                current_width = word_width
            else:
                current_line.append(word)
                current_width += word_width
        
        if current_line:
            lines.append(" ".join(current_line))
        
        # Draw lines
        y = 30
        line_height = font_size * 1.4
        
        for line in lines:
            if y > height - 20:  # Don't draw past bottom
                break
            canvas.drawString(line, 20, y, font, paint)
            y += line_height

    def paint(self):
        """Trigger redraw of the drawing area."""
        if self.drawing_area:
            self.drawing_area.queue_draw()
