use crate::mosaic::WidgetContext;
use nightshade::prelude::serde::{Deserialize, Serialize};
use nightshade::prelude::*;

use crate::app_context::AppContext;
use crate::messages::EditorMessage;

#[derive(Clone, Copy, PartialEq, Eq)]
enum ChatStatus {
    Idle,
    Streaming,
    ToolUse,
}

impl Default for ChatStatus {
    fn default() -> Self {
        Self::Idle
    }
}

#[derive(Clone)]
enum ChatMessageRole {
    User,
    Assistant,
}

#[derive(Clone)]
struct ChatMessage {
    role: ChatMessageRole,
    text: String,
    thinking: Option<String>,
    tool_uses: Vec<String>,
}

#[derive(Clone)]
struct ToolUseState {
    tool_name: String,
    finished: bool,
}

#[derive(Clone, Serialize, Deserialize)]
#[serde(crate = "nightshade::prelude::serde")]
pub struct ChatWidget {
    #[serde(skip)]
    messages: Vec<ChatMessage>,
    #[serde(skip)]
    input_text: String,
    #[serde(skip)]
    streaming_text: String,
    #[serde(skip)]
    thinking_text: String,
    #[serde(skip)]
    active_tools: Vec<ToolUseState>,
    #[serde(skip)]
    status: ChatStatus,
    #[serde(skip)]
    session_id: Option<String>,
    #[serde(skip)]
    initialized: bool,
    #[serde(skip)]
    scroll_to_bottom: bool,
    #[serde(skip)]
    error_message: Option<String>,
}

impl Default for ChatWidget {
    fn default() -> Self {
        Self {
            messages: Vec::new(),
            input_text: String::new(),
            streaming_text: String::new(),
            thinking_text: String::new(),
            active_tools: Vec::new(),
            status: ChatStatus::Idle,
            session_id: None,
            initialized: false,
            scroll_to_bottom: false,
            error_message: None,
        }
    }
}

impl ChatWidget {
    fn ensure_initialized(&mut self, context: &mut WidgetContext<AppContext, EditorMessage>) {
        if self.initialized {
            return;
        }
        self.initialized = true;

        if context.app.claude_command_sender.is_some() {
            return;
        }

        let (command_sender, command_receiver, event_sender, event_receiver) =
            nightshade::claude::create_cli_channels();

        let config = nightshade::claude::ClaudeConfig {
            system_prompt: Some(
                "You are an assistant embedded in the Nightshade game engine editor. \
                 You can use MCP tools to manipulate the 3D scene."
                    .to_string(),
            ),
            mcp_config: nightshade::claude::McpConfig::Auto,
            ..Default::default()
        };

        nightshade::claude::spawn_cli_worker(command_receiver, event_sender, config);

        context.app.claude_command_sender = Some(command_sender);
        context.app.claude_event_receiver = Some(event_receiver);
    }

    fn drain_events(&mut self, context: &mut WidgetContext<AppContext, EditorMessage>) {
        let Some(receiver) = context.app.claude_event_receiver.as_ref() else {
            return;
        };

        while let Ok(event) = receiver.try_recv() {
            match event {
                nightshade::claude::CliEvent::SessionStarted { session_id } => {
                    self.session_id = Some(session_id);
                }
                nightshade::claude::CliEvent::TextDelta { text } => {
                    self.streaming_text.push_str(&text);
                    self.scroll_to_bottom = true;
                }
                nightshade::claude::CliEvent::ThinkingDelta { text } => {
                    self.thinking_text.push_str(&text);
                    self.scroll_to_bottom = true;
                }
                nightshade::claude::CliEvent::ToolUseStarted { tool_name, .. } => {
                    self.active_tools.push(ToolUseState {
                        tool_name,
                        finished: false,
                    });
                    self.status = ChatStatus::ToolUse;
                    self.scroll_to_bottom = true;
                }
                nightshade::claude::CliEvent::ToolUseInputDelta { .. } => {}
                nightshade::claude::CliEvent::ToolUseFinished { .. } => {
                    if let Some(tool) = self.active_tools.last_mut() {
                        tool.finished = true;
                    }
                    self.status = ChatStatus::Streaming;
                }
                nightshade::claude::CliEvent::TurnComplete { .. } => {
                    self.finalize_assistant_message();
                    self.status = ChatStatus::Idle;
                }
                nightshade::claude::CliEvent::Complete { .. } => {
                    self.finalize_assistant_message();
                    self.status = ChatStatus::Idle;
                }
                nightshade::claude::CliEvent::Error { message } => {
                    self.error_message = Some(message);
                    self.status = ChatStatus::Idle;
                }
            }
        }
    }

    fn finalize_assistant_message(&mut self) {
        let text = std::mem::take(&mut self.streaming_text);
        let thinking = if self.thinking_text.is_empty() {
            None
        } else {
            Some(std::mem::take(&mut self.thinking_text))
        };
        let tool_uses: Vec<String> = self
            .active_tools
            .drain(..)
            .map(|tool| tool.tool_name)
            .collect();

        if !text.is_empty() || thinking.is_some() || !tool_uses.is_empty() {
            self.messages.push(ChatMessage {
                role: ChatMessageRole::Assistant,
                text,
                thinking,
                tool_uses,
            });
            self.scroll_to_bottom = true;
        }
    }

    fn send_message(&mut self, context: &mut WidgetContext<AppContext, EditorMessage>) {
        let prompt = self.input_text.trim().to_string();
        if prompt.is_empty() {
            return;
        }

        self.messages.push(ChatMessage {
            role: ChatMessageRole::User,
            text: prompt.clone(),
            thinking: None,
            tool_uses: Vec::new(),
        });

        if let Some(sender) = context.app.claude_command_sender.as_ref() {
            let _ = sender.send(nightshade::claude::CliCommand::StartQuery {
                prompt,
                session_id: self.session_id.clone(),
                model: None,
            });
            self.status = ChatStatus::Streaming;
        }

        self.input_text.clear();
        self.scroll_to_bottom = true;
    }

    pub(crate) fn render(
        &mut self,
        ui: &mut egui::Ui,
        context: &mut WidgetContext<AppContext, EditorMessage>,
    ) {
        self.ensure_initialized(context);
        self.drain_events(context);

        let available = ui.available_rect_before_wrap();
        ui.painter()
            .rect_filled(available, 0.0, ui.style().visuals.panel_fill);

        let input_height = 60.0;
        let status_height = 20.0;
        let messages_rect = egui::Rect::from_min_max(
            available.min,
            egui::pos2(
                available.max.x,
                available.max.y - input_height - status_height,
            ),
        );
        let status_rect = egui::Rect::from_min_max(
            egui::pos2(available.min.x, messages_rect.max.y),
            egui::pos2(available.max.x, messages_rect.max.y + status_height),
        );
        let input_rect = egui::Rect::from_min_max(
            egui::pos2(available.min.x, status_rect.max.y),
            available.max,
        );

        self.render_status(ui, status_rect);
        self.render_messages(ui, messages_rect);
        self.render_input(ui, input_rect, context);
    }

    fn render_status(&self, ui: &mut egui::Ui, rect: egui::Rect) {
        let mut child = ui.new_child(
            egui::UiBuilder::new()
                .max_rect(rect)
                .layout(egui::Layout::left_to_right(egui::Align::Center)),
        );

        child.add_space(8.0);

        match self.status {
            ChatStatus::Idle => {
                child.colored_label(egui::Color32::from_rgb(120, 120, 120), "Ready");
            }
            ChatStatus::Streaming => {
                child.spinner();
                child.add_space(4.0);
                child.colored_label(egui::Color32::from_rgb(100, 180, 255), "Responding...");
            }
            ChatStatus::ToolUse => {
                child.spinner();
                child.add_space(4.0);
                let tool_name = self
                    .active_tools
                    .last()
                    .map(|tool| tool.tool_name.as_str())
                    .unwrap_or("unknown");
                child.colored_label(
                    egui::Color32::from_rgb(255, 180, 50),
                    format!("Using tool: {}", tool_name),
                );
            }
        }

        if let Some(ref error) = self.error_message {
            child.add_space(8.0);
            child.colored_label(egui::Color32::from_rgb(255, 80, 80), error);
        }
    }

    fn render_messages(&mut self, ui: &mut egui::Ui, rect: egui::Rect) {
        let mut child = ui.new_child(
            egui::UiBuilder::new()
                .max_rect(rect)
                .layout(egui::Layout::top_down(egui::Align::LEFT)),
        );

        egui::ScrollArea::vertical()
            .auto_shrink([false, false])
            .stick_to_bottom(true)
            .show(&mut child, |ui| {
                ui.add_space(8.0);

                if self.messages.is_empty() && self.streaming_text.is_empty() {
                    ui.centered_and_justified(|ui| {
                        ui.colored_label(
                            egui::Color32::from_rgb(120, 120, 120),
                            "Send a message to start a conversation with Claude.",
                        );
                    });
                    return;
                }

                for message in &self.messages {
                    self.render_single_message(ui, message);
                    ui.add_space(8.0);
                }

                if !self.thinking_text.is_empty() || !self.streaming_text.is_empty() {
                    let in_progress_message = ChatMessage {
                        role: ChatMessageRole::Assistant,
                        text: self.streaming_text.clone(),
                        thinking: if self.thinking_text.is_empty() {
                            None
                        } else {
                            Some(self.thinking_text.clone())
                        },
                        tool_uses: self
                            .active_tools
                            .iter()
                            .map(|tool| tool.tool_name.clone())
                            .collect(),
                    };
                    self.render_single_message(ui, &in_progress_message);
                }

                if self.scroll_to_bottom {
                    ui.scroll_to_cursor(Some(egui::Align::BOTTOM));
                    self.scroll_to_bottom = false;
                }
            });
    }

    fn render_single_message(&self, ui: &mut egui::Ui, message: &ChatMessage) {
        let (label_text, label_color) = match message.role {
            ChatMessageRole::User => ("You", egui::Color32::from_rgb(100, 180, 255)),
            ChatMessageRole::Assistant => ("Claude", egui::Color32::from_rgb(255, 160, 50)),
        };

        ui.horizontal(|ui| {
            ui.colored_label(label_color, egui::RichText::new(label_text).strong());
        });

        if let Some(ref thinking) = message.thinking {
            egui::CollapsingHeader::new(
                egui::RichText::new("Thinking...")
                    .italics()
                    .color(egui::Color32::from_rgb(150, 150, 150)),
            )
            .id_salt(ui.next_auto_id())
            .show(ui, |ui| {
                ui.colored_label(egui::Color32::from_rgb(150, 150, 150), thinking);
            });
        }

        for tool_name in &message.tool_uses {
            ui.horizontal(|ui| {
                ui.colored_label(
                    egui::Color32::from_rgb(255, 180, 50),
                    format!("  [tool: {}]", tool_name),
                );
            });
        }

        if !message.text.is_empty() {
            ui.label(&message.text);
        }
    }

    fn render_input(
        &mut self,
        ui: &mut egui::Ui,
        rect: egui::Rect,
        context: &mut WidgetContext<AppContext, EditorMessage>,
    ) {
        let mut child = ui.new_child(
            egui::UiBuilder::new()
                .max_rect(rect)
                .layout(egui::Layout::left_to_right(egui::Align::Center)),
        );

        child.add_space(4.0);

        let text_edit_width = rect.width() - 70.0;
        let response = child.add(
            egui::TextEdit::multiline(&mut self.input_text)
                .desired_width(text_edit_width)
                .desired_rows(2)
                .hint_text("Message Claude...")
                .return_key(egui::KeyboardShortcut::new(
                    egui::Modifiers::SHIFT,
                    egui::Key::Enter,
                )),
        );

        let enter_pressed = response.has_focus()
            && child.input(|input| input.key_pressed(egui::Key::Enter) && !input.modifiers.shift);

        let is_busy = self.status != ChatStatus::Idle;

        child.add_space(4.0);
        let send_enabled = !self.input_text.trim().is_empty() && !is_busy;
        if child
            .add_enabled(send_enabled, egui::Button::new("Send"))
            .clicked()
            || (enter_pressed && send_enabled)
        {
            self.send_message(context);
        }
    }
}
