//! agor-gpui: GPU-accelerated Agent Orchestrator UI prototype.
//!
//! Uses Zed's GPUI framework for native GPU rendering.
//! This is a decision-making prototype comparing against the existing Tauri+Svelte app.
//!
//! # Architecture
//!
//! ```text
//! main.rs → Application::new().run()
//!   └─ Workspace (root view)
//!        ├─ Sidebar (icon rail)
//!        ├─ SettingsPanel (drawer, optional)
//!        ├─ ProjectGrid
//!        │   ├─ ProjectBox[0]
//!        │   │   ├─ AgentPane (message list + prompt)
//!        │   │   └─ TerminalView (GPU-rendered via alacritty_terminal)
//!        │   └─ ProjectBox[1]
//!        │       ├─ AgentPane
//!        │       └─ TerminalView
//!        ├─ StatusBar (bottom)
//!        └─ CommandPalette (overlay, optional)
//! ```
//!
//! # Backend Integration
//!
//! `backend.rs` bridges to `agor-core` (PtyManager, SidecarManager) via an
//! `EventSink` that queues events into an mpsc channel. The GPUI main loop
//! drains this channel to update entity state reactively.
//!
//! # Key Differentiator: GPU Terminal
//!
//! `terminal/renderer.rs` uses `alacritty_terminal::Term` for VT100 parsing
//! and renders each cell directly via GPUI's text pipeline — no DOM, no
//! Canvas 2D context, just GPU-accelerated glyph rendering.

mod backend;
mod components;
mod state;
mod theme;
mod terminal;
mod workspace;

/// Extension trait to create cached AnyView from Entity.
/// Cached views skip re-render when their entity is not dirty —
/// GPUI replays previous frame's GPU scene commands via memcpy.
///
/// IMPORTANT: The StyleRefinement must specify size/flex for the cached wrapper
/// node. Without it, the wrapper collapses to zero size on first render.
pub trait CachedView {
    /// Cache with flex-1 + full size (for content areas)
    fn into_cached_flex(self) -> gpui::AnyView;
    /// Cache with natural size (for sidebar, status bar)
    fn into_cached_natural(self) -> gpui::AnyView;
}

impl<V: 'static + gpui::Render> CachedView for gpui::Entity<V> {
    fn into_cached_flex(self) -> gpui::AnyView {
        let mut style = gpui::StyleRefinement::default();
        style.flex_grow = Some(1.0);
        style.size.width = Some(gpui::Length::Definite(gpui::DefiniteLength::Fraction(1.0)).into());
        style.size.height = Some(gpui::Length::Definite(gpui::DefiniteLength::Fraction(1.0)).into());
        gpui::AnyView::from(self).cached(style)
    }

    fn into_cached_natural(self) -> gpui::AnyView {
        let mut style = gpui::StyleRefinement::default();
        // Natural size — don't set width/height, let content determine size
        // But set min_size to prevent collapse
        style.min_size.width = Some(gpui::Length::Definite(gpui::DefiniteLength::Absolute(gpui::AbsoluteLength::Pixels(gpui::px(1.0)))).into());
        style.min_size.height = Some(gpui::Length::Definite(gpui::DefiniteLength::Absolute(gpui::AbsoluteLength::Pixels(gpui::px(1.0)))).into());
        gpui::AnyView::from(self).cached(style)
    }
}

use gpui::*;

use state::AppState;
use workspace::Workspace;

fn main() {
    // Initialize the GPUI application
    Application::new().run(|cx: &mut App| {
        // Create shared application state with demo data
        let app_state: Entity<AppState> = cx.new(|_cx| AppState::new_demo());

        // Configure window
        let window_options = WindowOptions {
            // Use default window bounds (the OS will position/size it)
            focus: true,
            show: true,
            ..Default::default()
        };

        // Open the main window with Workspace as the root view
        let _window = cx
            .open_window(window_options, |window, cx| {
                // Set window title
                window.set_window_title("Agent Orchestrator — GPUI Prototype");

                // Create the workspace root view
                cx.new(|cx| Workspace::new(app_state.clone(), cx))
            })
            .expect("Failed to open window");

        // TODO: Set up keyboard bindings for Ctrl+K (palette), Ctrl+B (sidebar), Ctrl+, (settings)
        // GPUI uses an action dispatch system:
        //   1. Define action structs with #[derive(Action)]
        //   2. Register key bindings via cx.bind_keys()
        //   3. Handle actions via window.on_action() or element .on_action()
        //
        // Example (requires gpui::actions! macro):
        //   actions!(agor, [TogglePalette, ToggleSidebar, OpenSettings]);
        //   cx.bind_keys([
        //       KeyBinding::new("ctrl-k", TogglePalette, None),
        //       KeyBinding::new("ctrl-b", ToggleSidebar, None),
        //       KeyBinding::new("ctrl-,", OpenSettings, None),
        //   ]);

        // TODO: Start backend event polling loop
        // In a full implementation, we'd spawn a timer or use cx.spawn() to
        // periodically drain backend events and update the app state:
        //
        //   let backend = Backend::new();
        //   cx.spawn(|cx| async move {
        //       loop {
        //           Timer::after(Duration::from_millis(16)).await; // ~60fps
        //           let events = backend.drain_events();
        //           for ev in events {
        //               // Route to appropriate entity updates
        //           }
        //       }
        //   }).detach();
    });
}
