//! View function that builds the eye-declare element tree from app state.

use eye_declare::{
    Column, Component, Elements, HStack, Line, Span, Spinner, TextBlock, VStack, WidthConstraint,
    element, impl_slot_children,
};
use ratatui_core::style::{Color, Modifier, Style};

use super::components::atuin_ai::AtuinAi;
use super::components::input_box::InputBox;
use super::components::markdown::Markdown;
use super::state::{AppMode, AppState};

mod turn;

#[derive(Default)]
struct Padding {
    top: u16,
    left: u16,
    right: u16,
    bottom: u16,
}

impl Component for Padding {
    type State = ();

    fn content_inset(&self, _state: &Self::State) -> eye_declare::Insets {
        eye_declare::Insets::ZERO
            .left(self.left)
            .right(self.right)
            .top(self.top)
            .bottom(self.bottom)
    }

    fn desired_height(&self, _width: u16, _state: &Self::State) -> u16 {
        0
    }

    fn render(
        &self,
        _area: ratatui::layout::Rect,
        _buf: &mut ratatui::buffer::Buffer,
        _state: &(),
    ) {
    }
}

impl_slot_children!(Padding);

/// Build the element tree from current state.
///
/// Layout (top to bottom):
/// - Conversation messages (user messages, agent responses, tool status)
/// - Streaming content (if actively streaming)
/// - Error display (if in error state)
/// - Spacer
/// - Input box (bordered, with contextual keybindings)
pub fn ai_view(state: &AppState) -> Elements {
    let mut turn_builder = turn::TurnBuilder::new();

    for event in &state.events {
        turn_builder.add_event(event);
    }
    let turns = turn_builder.build();

    let busy = state.mode == AppMode::Streaming || state.mode == AppMode::Generating;
    let last_index = turns.len().saturating_sub(1);

    element! {
        AtuinAi(
            mode: state.mode.clone(),
            has_command: state.has_any_command(),
            is_input_blank: state.is_input_blank,
            pending_confirmation: state.confirmation_pending,
        ) {
            #(for (index, turn) in turns.iter().enumerate() {
                #(match turn {
                    turn::UiTurn::User { events } => {
                        user_turn_view(events, index == 0)
                    }
                    turn::UiTurn::Agent { events } => {
                        agent_turn_view(events, busy && index == last_index)
                    }
                    turn::UiTurn::OutOfBand { events } => {
                        out_of_band_turn_view(events)
                    }
                })
            })

            #(if !state.is_exiting() {
                TextBlock { Line { Span(text: "") } }
                InputBox(
                    key: "input",
                    title: "Generate a command or ask a question",
                    title_right: "Atuin AI",
                    footer: state.footer_text(),
                    active: state.mode == AppMode::Input && !state.confirmation_pending,
                )

                #(if state.is_input_blank && state.has_any_command() && state.mode == AppMode::Input {
                    #(if state.confirmation_pending {
                        TextBlock { Line { Span(text: "[Enter] Confirm dangerous command  [Esc] Cancel", style: Style::default().fg(Color::Gray)) } }
                    } else {
                        TextBlock { Line { Span(text: "[Enter] Execute suggested command  [Tab] Insert Command", style: Style::default().fg(Color::Gray)) } }
                    })
                })
            })
        }
    }
}

fn user_turn_view(events: &[turn::UiEvent], first_turn: bool) -> Elements {
    let label_style = Style::default()
        .fg(Color::Cyan)
        .add_modifier(Modifier::BOLD);

    element! {
        VStack {
            TextBlock {
                #(if !first_turn {
                    Line { Span() }
                })
                Line {
                    Span(text: "You", style: label_style)
                }
            }
            #(for event in events {
                #(match event {
                    turn::UiEvent::Text { content } => {
                        element! {
                            Padding(left: 2u16) {
                                TextBlock {
                                    Line {
                                        Span(text: content, style: Style::default())
                                    }
                                }
                            }
                        }
                    },
                    _ => element!{}
                })
            })
        }
    }
}

fn agent_turn_view(events: &[turn::UiEvent], busy: bool) -> Elements {
    let label_style = Style::default()
        .fg(Color::Yellow)
        .add_modifier(Modifier::BOLD);

    element! {
        VStack {
            Spinner(
                label: "Atuin AI",
                label_style: label_style,
                done_label_style: label_style,
                hide_checkmark: true,
                label_first: true,
                done: !busy,
            )
            #(for event in events {
                #(match event {
                    turn::UiEvent::Text { content } => {
                        element! {
                            Padding(left: 2u16) {
                                Markdown(source: content)
                            }
                        }
                    },
                    turn::UiEvent::ToolSummary(summary) => {
                        tool_summary_view(summary)
                    },
                    turn::UiEvent::SuggestedCommand(details) => {
                        suggested_command_view(details)
                    },
                    _ => element!{}
                })
            })
        }
    }
}

fn out_of_band_turn_view(events: &[turn::UiEvent]) -> Elements {
    element! {
        VStack {
            TextBlock {
                Line { Span(text: "System", style: Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD)) }
            }
            #(for event in events {
                #(match event {
                    turn::UiEvent::OutOfBandOutput(details) => {
                        out_of_band_output_view(details)
                    }
                    _ => element!{}
                })
            })
        }
    }
}

fn out_of_band_output_view(details: &turn::OutOfBandOutputDetails) -> Elements {
    element! {
        Padding(left: 2u16) {
            #(if details.command.is_some() {
                TextBlock {
                    Line {
                        Span(text: details.command.as_ref().unwrap(), style: Style::default().fg(Color::Blue))
                    }
                }
            })
            Markdown(source: details.content.clone())
        }
    }
}

fn tool_summary_view(summary: &turn::ToolSummary) -> Elements {
    element! {
        Spinner(label: summary.summary(), done: !summary.any_pending())
    }
}

fn suggested_command_view(details: &turn::SuggestedCommandDetails) -> Elements {
    let is_dangerous = matches!(
        details.danger_level,
        turn::DangerLevel::High(_) | turn::DangerLevel::Medium(_)
    );
    let danger_notes = details.danger_level.notes();
    let danger_style = match details.danger_level {
        turn::DangerLevel::High(_) => Style::default().fg(Color::Red),
        turn::DangerLevel::Medium(_) => Style::default().fg(Color::Yellow),
        turn::DangerLevel::Low(_) => Style::default().fg(Color::Green),
        turn::DangerLevel::Unknown(_) => Style::default().fg(Color::Green),
    };
    let danger_text = match details.danger_level {
        turn::DangerLevel::High(_) => "High",
        turn::DangerLevel::Medium(_) => "Medium",
        turn::DangerLevel::Low(_) => "Low",
        turn::DangerLevel::Unknown(_) => "Unknown",
    };

    let low_confidence = matches!(
        details.confidence_level,
        turn::ConfidenceLevel::Low(_) | turn::ConfidenceLevel::Medium(_)
    );

    let confidence_level = match details.confidence_level {
        turn::ConfidenceLevel::Low(_) => "Low",
        turn::ConfidenceLevel::Medium(_) => "Medium",
        turn::ConfidenceLevel::High(_) => "High",
        turn::ConfidenceLevel::Unknown(_) => "Unknown",
    };

    let confidence_notes = details.confidence_level.notes();

    element! {
        VStack {
            TextBlock {
                #(if !details.first_event_in_turn {
                    Line { Span() }
                })
                Line {
                    Span(text: "  Suggested command:", style: Style::default().fg(Color::Cyan))
                }
            }
            HStack {
                Column(width: WidthConstraint::Fixed(2)) {
                    TextBlock {
                        Line {
                            #(if is_dangerous || low_confidence {
                                Span(text: "! ", style: Style::default().fg(Color::Yellow))
                            } else {
                                Span(text: "$ ", style: Style::default().fg(Color::Blue))
                            })
                        }
                    }
                }
                Column {
                    TextBlock {
                        Line {
                            Span(text: &details.command, style: Style::default().fg(Color::Green))
                        }
                    }
                }
            }
            #(if is_dangerous {
                Padding(left: 2u16) {
                    TextBlock {
                        Line {
                            Span(text: "Danger: ", style: danger_style)
                            Span(text: danger_text, style: danger_style.add_modifier(Modifier::BOLD))
                        }
                    }
                }
            })
            #(if is_dangerous && danger_notes.is_some() {
                Padding(left: 2u16) {
                    HStack {
                        Column(width: WidthConstraint::Fixed(2)) {
                            TextBlock {
                                Line {
                                    Span(text: "└")
                                }
                            }
                        }
                        Column(width: WidthConstraint::Fill) {
                            Markdown(source: danger_notes.unwrap())
                        }
                    }
                }
            })
            #(if low_confidence {
                Padding(left: 2u16) {
                    TextBlock {
                        Line {
                            Span(text: "Confidence: ", style: Style::default().fg(Color::Blue))
                            Span(text: confidence_level, style: Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD))
                        }
                    }
                }
            })
            #(if low_confidence && confidence_notes.is_some() {
                Padding(left: 2u16) {
                    HStack {
                        Column(width: WidthConstraint::Fixed(2)) {
                            TextBlock {
                                Line {
                                    Span(text: "└")
                                }
                            }
                        }
                        Column(width: WidthConstraint::Fill) {
                            Markdown(source: confidence_notes.unwrap())
                        }
                    }
                }
            })
        }
    }
}

// ai_view_old removed — superseded by ai_view above
