use super::*;
use crate::core_tui::session::inline_list::{InlineListRow, selection_padding};
use crate::core_tui::session::list_panel::{
    ListPanelLayout, SharedListPanelSections, SharedListPanelStyles, SharedSearchField,
    StaticRowsListPanelModel, fixed_section_rows, fixed_section_rows_with_divider,
    render_shared_list_panel, rows_to_u16,
};
use ratatui::widgets::{Clear, Paragraph, Wrap};

#[derive(Clone)]
struct AgentPaletteRenderRow {
    text: String,
    subtitle: Option<String>,
    style: Style,
    selectable: bool,
    selected: bool,
}

#[derive(Clone)]
struct FilePaletteRenderRow {
    text: String,
    style: Style,
    selectable: bool,
    selected: bool,
}

pub(crate) fn agent_palette_panel_layout(session: &Session) -> Option<ListPanelLayout> {
    if !session.agent_palette_visible() || !session.inline_lists_visible() {
        return None;
    }

    let palette = session.agent_palette.as_ref()?;
    let info_rows = if palette.has_agents() {
        agent_palette_instructions(session, palette).len()
    } else {
        1
    };
    let fixed_rows = fixed_section_rows(1, info_rows, palette.has_agents());
    let list_rows = if palette.has_agents() {
        let mut rows = palette.current_page_items().len().max(1);
        if palette.has_more_items() {
            rows += 1;
        }
        rows.min(ui::INLINE_LIST_MAX_ROWS)
    } else {
        1
    };

    Some(ListPanelLayout::new(fixed_rows, rows_to_u16(list_rows)))
}

pub fn split_inline_agent_palette_area(session: &mut Session, area: Rect) -> (Rect, Option<Rect>) {
    if area.height == 0 || area.width == 0 {
        return (area, None);
    }

    let Some(layout) = agent_palette_panel_layout(session) else {
        return (area, None);
    };

    layout.split(area)
}

pub fn render_agent_palette(session: &mut Session, frame: &mut Frame<'_>, area: Rect) {
    if !session.inline_lists_visible()
        || area.height == 0
        || area.width == 0
        || !session.agent_palette_visible()
    {
        return;
    }

    let Some(palette) = session.agent_palette.as_ref() else {
        return;
    };

    frame.render_widget(Clear, area);

    if !palette.has_agents() {
        let loading = Paragraph::new(Line::from(Span::styled(
            "Loading subagents...".to_owned(),
            default_style(session).add_modifier(Modifier::DIM),
        )))
        .wrap(Wrap { trim: true });
        frame.render_widget(loading, area);
        return;
    }

    let instructions = agent_palette_instructions(session, palette);
    let rows = build_agent_palette_rows(session, palette);
    if rows.is_empty() {
        return;
    }

    let default_style = default_style(session);
    let highlight_style = modal_list_highlight_style(session);
    let unselected_prefix = selection_padding();

    let selected = rows.iter().position(|row| row.selectable && row.selected);
    let rendered_rows = rows
        .into_iter()
        .map(|row| {
            let mut spans = vec![
                Span::styled(unselected_prefix.clone(), default_style),
                Span::styled(row.text, row.style),
            ];
            if let Some(subtitle) = row.subtitle {
                spans.push(Span::styled(
                    format!("  {}", subtitle),
                    default_style.add_modifier(Modifier::DIM),
                ));
            }

            (
                InlineListRow::single(
                    Line::from(spans),
                    if row.selectable {
                        default_style
                    } else {
                        default_style.add_modifier(Modifier::DIM)
                    },
                ),
                1_u16,
            )
        })
        .collect::<Vec<_>>();

    let sections = SharedListPanelSections {
        header: vec![Line::from(Span::styled("Agents".to_owned(), default_style))],
        info: instructions,
        search: Some(SharedSearchField {
            label: "Search agents".to_owned(),
            placeholder: Some("name or description".to_owned()),
            query: palette.filter_query().to_owned(),
        }),
    };
    let mut model = StaticRowsListPanelModel {
        rows: rendered_rows,
        selected,
        offset: 0,
        visible_rows: 0,
    };

    render_shared_list_panel(
        frame,
        area,
        sections,
        SharedListPanelStyles {
            base_style: default_style,
            selected_style: Some(highlight_style),
            text_style: default_style,
            divider_style: None,
        },
        &mut model,
    );
}

pub(crate) fn file_palette_panel_layout(session: &Session) -> Option<ListPanelLayout> {
    if !session.file_palette_visible() || !session.inline_lists_visible() {
        return None;
    }

    let palette = session.file_palette.as_ref()?;
    let info_rows = if palette.has_files() {
        file_palette_instructions(session, palette).len()
    } else {
        1
    };
    let fixed_rows = fixed_section_rows_with_divider(1, info_rows, palette.has_files(), true);
    let list_rows = if palette.has_files() {
        let mut rows = palette.current_page_items().len().max(1);
        if palette.has_more_items() {
            rows += 1;
        }
        rows.min(ui::INLINE_LIST_MAX_ROWS)
    } else {
        1
    };

    Some(ListPanelLayout::new(fixed_rows, rows_to_u16(list_rows)))
}

pub fn split_inline_file_palette_area(session: &mut Session, area: Rect) -> (Rect, Option<Rect>) {
    if area.height == 0 || area.width == 0 {
        return (area, None);
    }

    let Some(layout) = file_palette_panel_layout(session) else {
        return (area, None);
    };

    layout.split(area)
}

pub fn render_file_palette(session: &mut Session, frame: &mut Frame<'_>, area: Rect) {
    if !session.inline_lists_visible()
        || area.height == 0
        || area.width == 0
        || !session.file_palette_visible()
    {
        return;
    }

    let Some(palette) = session.file_palette.as_ref() else {
        return;
    };

    frame.render_widget(Clear, area);

    if !palette.has_files() {
        let loading = Paragraph::new(Line::from(Span::styled(
            "Loading workspace files...".to_owned(),
            default_style(session).add_modifier(Modifier::DIM),
        )))
        .wrap(Wrap { trim: true });
        frame.render_widget(loading, area);
        return;
    }

    let instructions = file_palette_instructions(session, palette);
    let rows = build_file_palette_rows(session, palette);
    if rows.is_empty() {
        return;
    }

    let default_style = default_style(session);
    let highlight_style = modal_list_highlight_style(session);
    let unselected_prefix = selection_padding();

    let selected = rows.iter().position(|row| row.selectable && row.selected);
    let rendered_rows = rows
        .into_iter()
        .map(|row| {
            (
                InlineListRow::single(
                    Line::from(vec![
                        Span::styled(unselected_prefix.clone(), default_style),
                        Span::styled(row.text, row.style),
                    ]),
                    if row.selectable {
                        default_style
                    } else {
                        default_style.add_modifier(Modifier::DIM)
                    },
                ),
                1_u16,
            )
        })
        .collect::<Vec<_>>();

    let sections = SharedListPanelSections {
        header: vec![Line::from(Span::styled(
            "Files".to_owned(),
            session.core.section_title_style(),
        ))],
        info: instructions,
        search: Some(SharedSearchField {
            label: "Search files".to_owned(),
            placeholder: Some("filename or path".to_owned()),
            query: palette.filter_query().to_owned(),
        }),
    };
    let mut model = StaticRowsListPanelModel {
        rows: rendered_rows,
        selected,
        offset: 0,
        visible_rows: 0,
    };

    render_shared_list_panel(
        frame,
        area,
        sections,
        SharedListPanelStyles {
            base_style: default_style,
            selected_style: Some(highlight_style),
            text_style: default_style,
            divider_style: Some(session.core.styles.border_style()),
        },
        &mut model,
    );
}

fn build_agent_palette_rows(
    session: &Session,
    palette: &AgentPalette,
) -> Vec<AgentPaletteRenderRow> {
    let mut rows = Vec::new();
    let default = default_style(session);

    for (_global_idx, entry, selected) in palette.current_page_items() {
        rows.push(AgentPaletteRenderRow {
            text: entry.display_name.clone(),
            subtitle: entry.description.clone(),
            style: default.add_modifier(Modifier::BOLD),
            selectable: true,
            selected,
        });
    }

    if rows.is_empty() {
        rows.push(AgentPaletteRenderRow {
            text: "No matching agents".to_owned(),
            subtitle: None,
            style: default.add_modifier(Modifier::DIM),
            selectable: false,
            selected: false,
        });
    }

    if palette.has_more_items() {
        let remaining = palette
            .total_items()
            .saturating_sub(palette.current_page_number() * 20);
        rows.push(AgentPaletteRenderRow {
            text: format!("... ({} more items)", remaining),
            subtitle: None,
            style: default.add_modifier(Modifier::DIM | Modifier::ITALIC),
            selectable: false,
            selected: false,
        });
    }

    rows
}

fn build_file_palette_rows(session: &Session, palette: &FilePalette) -> Vec<FilePaletteRenderRow> {
    let mut rows = Vec::new();
    let default = default_style(session);

    for (_global_idx, entry, selected) in palette.current_page_items() {
        let mut style = default;
        let prefix = if entry.is_dir {
            style = style.add_modifier(Modifier::BOLD);
            "↳  "
        } else {
            "  · "
        };

        rows.push(FilePaletteRenderRow {
            text: format!("{}{}", prefix, entry.display_name),
            style,
            selectable: true,
            selected,
        });
    }

    if rows.is_empty() {
        rows.push(FilePaletteRenderRow {
            text: "No matching files".to_owned(),
            style: default.add_modifier(Modifier::DIM),
            selectable: false,
            selected: false,
        });
    }

    if palette.has_more_items() {
        let remaining = palette
            .total_items()
            .saturating_sub(palette.current_page_number() * 20);
        rows.push(FilePaletteRenderRow {
            text: format!("  ... ({} more items)", remaining),
            style: default.add_modifier(Modifier::DIM | Modifier::ITALIC),
            selectable: false,
            selected: false,
        });
    }

    rows
}

fn agent_palette_instructions(session: &Session, palette: &AgentPalette) -> Vec<Line<'static>> {
    let mut lines = vec![];

    if palette.is_empty() {
        lines.push(Line::from(Span::styled(
            "No agents found matching filter".to_owned(),
            default_style(session).add_modifier(Modifier::DIM),
        )));
    } else {
        let total = palette.total_items();
        let count_text = if total == 1 {
            "1 agent".to_owned()
        } else {
            format!("{} agents", total)
        };

        lines.push(Line::from(Span::styled(
            "↑↓ Navigate · PgUp/PgDn Page · Tab/Enter Select · Esc Close".to_owned(),
            default_style(session),
        )));

        lines.push(Line::from(vec![
            Span::styled(
                format!("Showing {}", count_text),
                default_style(session).add_modifier(Modifier::DIM),
            ),
            Span::styled(
                if !palette.filter_query().is_empty() {
                    format!(" matching '{}'", palette.filter_query())
                } else {
                    String::new()
                },
                accent_style(session),
            ),
        ]));
    }

    lines
}

fn file_palette_instructions(session: &Session, palette: &FilePalette) -> Vec<Line<'static>> {
    let mut lines = vec![];

    if palette.is_empty() {
        lines.push(Line::from(Span::styled(
            "No files found matching filter".to_owned(),
            default_style(session).add_modifier(Modifier::DIM),
        )));
    } else {
        let total = palette.total_items();
        let count_text = if total == 1 {
            "1 file".to_owned()
        } else {
            format!("{} files", total)
        };

        lines.push(Line::from(vec![Span::styled(
            "↑↓ Navigate · PgUp/PgDn Page · Tab/Enter Select · Esc Close".to_owned(),
            default_style(session),
        )]));

        lines.push(Line::from(vec![
            Span::styled(
                format!("Showing {}", count_text),
                default_style(session).add_modifier(Modifier::DIM),
            ),
            Span::styled(
                if !palette.filter_query().is_empty() {
                    format!(" matching '{}'", palette.filter_query())
                } else {
                    String::new()
                },
                accent_style(session),
            ),
        ]));
    }

    lines
}
