//! Workspace: root view composing sidebar + project boxes + status bar.
//!
//! ProjectBoxes are NOT entities — they're plain structs rendered as custom Elements.
//! This eliminates the Entity boundary and dispatch tree overhead for project cards.
//! Only Workspace is a view in the dispatch tree. Blink timer notifies Workspace directly.
//! Dispatch tree depth: 1 (just Workspace). AgentPane/TerminalView are cached child entities.

use gpui::*;

use crate::components::command_palette::CommandPalette;
use crate::components::project_box::ProjectBoxData;
use crate::components::project_box_element::ProjectBoxFullElement;
use crate::components::settings::SettingsPanel;
use crate::components::sidebar::Sidebar;
use crate::components::status_bar::StatusBar;
use crate::state::{AgentStatus, AppState, ProjectTab};
use crate::theme;
use crate::CachedView;

fn accent_color(index: usize) -> Rgba {
    const ACCENTS: [Rgba; 8] = [
        theme::BLUE, theme::MAUVE, theme::GREEN, theme::PEACH,
        theme::PINK, theme::TEAL, theme::SAPPHIRE, theme::LAVENDER,
    ];
    ACCENTS[index % ACCENTS.len()]
}

pub struct Workspace {
    #[allow(dead_code)]
    app_state: Entity<AppState>,
    sidebar: Entity<Sidebar>,
    settings_panel: Entity<SettingsPanel>,
    project_boxes: Vec<ProjectBoxData>,
    status_bar: Entity<StatusBar>,
    command_palette: Entity<CommandPalette>,
}

impl Workspace {
    pub fn new(app_state: Entity<AppState>, cx: &mut Context<Self>) -> Self {
        let sidebar = cx.new({
            let state = app_state.clone();
            |_cx| Sidebar::new(state)
        });
        let settings_panel = cx.new({
            let state = app_state.clone();
            |_cx| SettingsPanel::new(state)
        });
        let status_bar = cx.new({
            let state = app_state.clone();
            |_cx| StatusBar::new(state)
        });
        let command_palette = cx.new({
            let state = app_state.clone();
            |_cx| CommandPalette::new(state)
        });

        // Create ProjectBoxData (plain structs with entity handles for content)
        let projects: Vec<_> = app_state.read(cx).projects.clone();
        let project_boxes: Vec<ProjectBoxData> = projects
            .into_iter()
            .map(|proj| {
                let mut data = ProjectBoxData::new(&proj);

                // Create cached child entities for content
                let agent_pane = cx.new(|_cx| {
                    crate::components::agent_pane::AgentPane::with_demo_messages()
                });
                let terminal_view = cx.new(|_cx| {
                    let mut tv = crate::terminal::renderer::TerminalView::new(120, 10);
                    tv.feed_demo();
                    tv
                });
                data.agent_pane = Some(agent_pane);
                data.terminal_view = Some(terminal_view);

                // Start blink timer for Running projects (focus-gated: first only)
                let should_pulse = matches!(proj.agent.status, AgentStatus::Running)
                    && proj.accent_index == 0;
                if should_pulse {
                    let blink = crate::components::blink_state::SharedBlink::new();
                    let visible = blink.visible.clone();
                    // Notify WORKSPACE directly — it's the only view entity
                    cx.spawn(async move |workspace: WeakEntity<Self>, cx: &mut AsyncApp| {
                        loop {
                            cx.background_executor().timer(std::time::Duration::from_millis(500)).await;
                            visible.fetch_xor(true, std::sync::atomic::Ordering::Relaxed);
                            let ok = workspace.update(cx, |_, cx| cx.notify());
                            if ok.is_err() { break; }
                        }
                    }).detach();
                    data.shared_blink = Some(blink);
                }

                data
            })
            .collect();

        Self {
            app_state,
            sidebar,
            settings_panel,
            project_boxes,
            status_bar,
            command_palette,
        }
    }
}

impl Render for Workspace {
    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
        let sidebar_open = true;
        let settings_open = false;
        let palette_open = false;

        let mut root = div()
            .id("workspace-root")
            .size_full()
            .flex()
            .flex_col()
            .bg(theme::CRUST)
            .font_family("Inter");

        let mut main_row = div()
            .id("main-row")
            .flex_1()
            .w_full()
            .flex()
            .flex_row()
            .overflow_hidden();

        if sidebar_open {
            main_row = main_row.child(self.sidebar.clone());
        }
        if settings_open {
            main_row = main_row.child(self.settings_panel.clone());
        }

        // Project grid — inline custom Elements, NO entity children
        let mut grid = div()
            .id("project-grid")
            .flex_1()
            .h_full()
            .flex()
            .flex_row()
            .flex_wrap()
            .gap(px(8.0))
            .p(px(8.0))
            .bg(theme::CRUST)
            .overflow_y_scroll();

        for data in &self.project_boxes {
            let accent = accent_color(data.accent_index);
            let tab_idx = match data.active_tab {
                ProjectTab::Model => 0,
                ProjectTab::Docs => 1,
                ProjectTab::Files => 2,
            };

            // Build content div with cached child entities
            let mut content = div()
                .id(data.id_content.clone())
                .flex_1()
                .w_full()
                .overflow_hidden();

            content = match data.active_tab {
                ProjectTab::Model => {
                    let mut c = content.flex().flex_col();
                    if let Some(ref pane) = data.agent_pane {
                        c = c.child(pane.clone().into_cached_flex());
                    }
                    c = c.child(div().w_full().h(px(4.0)).bg(theme::SURFACE0));
                    if let Some(ref term) = data.terminal_view {
                        c = c.child(term.clone().into_cached_flex());
                    }
                    c
                }
                ProjectTab::Docs => content.flex().items_center().justify_center()
                    .text_size(px(14.0)).text_color(theme::OVERLAY0)
                    .child("Documentation viewer"),
                ProjectTab::Files => content.flex().flex_col().p(px(12.0)).gap(px(4.0))
                    .text_size(px(12.0)).text_color(theme::SUBTEXT0)
                    .child("src/").child("  main.rs").child("  lib.rs").child("Cargo.toml"),
            };

            grid = grid.child(ProjectBoxFullElement {
                id: data.id_project.clone().into(),
                name: data.cached_name.clone(),
                cwd: data.cached_cwd.clone(),
                accent,
                status: data.status,
                blink_visible: data.shared_blink.as_ref().map(|b| b.visible.clone()),
                active_tab: tab_idx,
                content: content.into_any_element(),
            });
        }

        main_row = main_row.child(grid);
        root = root.child(main_row);
        root = root.child(self.status_bar.clone());

        if palette_open {
            root = root.child(self.command_palette.clone());
        }

        root
    }
}
