//! Togglable folder tree sidebar — gPhoto-inspired.
//!
//! Slides in from the left when activated (default key: Tab). Shows a
//! vertical list of image-containing folders sibling to the current one.
//! Click a folder to switch the navigator to it.
//!
//! The sidebar is intentionally simple: it shows folders (not a full file
//! tree), and only folders that contain at least one supported image.
//! This keeps the UI focused on browsing photos, not on file management.

use std::path::{Path, PathBuf};

use iced::widget::{button, column, container, row, scrollable, text};
use iced::{Element, Length};

use super::theme;
use crate::codec::FormatRegistry;

const SIDEBAR_WIDTH: f32 = 240.0;

#[derive(Debug, Clone)]
pub enum SidebarMessage {
    /// User clicked a folder entry.
    FolderSelected(PathBuf),
    /// User requested the sidebar toggle (Tab key or button).
    Toggle,
}

#[derive(Debug, Clone, Default)]
pub struct Sidebar {
    pub visible: bool,
    /// The root directory whose children we're listing.
    /// Typically the parent of the currently-open folder.
    pub root: Option<PathBuf>,
    /// List of (path, name, image_count) for each sibling folder.
    pub entries: Vec<SidebarEntry>,
    /// Currently-selected folder path.
    pub current: Option<PathBuf>,
}

#[derive(Debug, Clone)]
pub struct SidebarEntry {
    pub path: PathBuf,
    pub name: String,
    pub image_count: usize,
}

impl Sidebar {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn toggle(&mut self) {
        self.visible = !self.visible;
    }

    /// Rebuild the sidebar entries from the current folder's parent.
    /// Called when a new folder is opened.
    pub fn refresh(&mut self, current_folder: &Path, registry: &FormatRegistry) {
        let parent = match current_folder.parent() {
            Some(p) => p.to_path_buf(),
            None => {
                self.root = None;
                self.entries.clear();
                self.current = Some(current_folder.to_path_buf());
                return;
            }
        };

        self.root = Some(parent.clone());
        self.current = Some(current_folder.to_path_buf());

        self.entries = std::fs::read_dir(&parent)
            .into_iter()
            .flatten()
            .flatten()
            .map(|entry| entry.path())
            .filter(|p| p.is_dir())
            .filter_map(|path| {
                let name = path
                    .file_name()
                    .and_then(|n| n.to_str())
                    .unwrap_or("?")
                    .to_string();
                // Skip hidden directories.
                if name.starts_with('.') {
                    return None;
                }
                let count = count_images(&path, registry);
                if count == 0 {
                    return None;
                }
                Some(SidebarEntry {
                    path,
                    name,
                    image_count: count,
                })
            })
            .collect();

        self.entries.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
    }

    pub fn view(&self) -> Element<'_, SidebarMessage> {
        let title = text("Folders")
            .color(theme::TEXT_SECONDARY)
            .size(11);

        let mut children: Vec<Element<'_, SidebarMessage>> = vec![title.into()];

        if self.entries.is_empty() {
            children.push(
                text("No folders with images")
                    .color(theme::TEXT_DIM)
                    .size(11)
                    .into(),
            );
        } else {
            for entry in &self.entries {
                let is_current = self.current.as_deref() == Some(entry.path.as_path());

                let name_text = text(entry.name.clone())
                    .color(if is_current {
                        theme::TEXT_PRIMARY
                    } else {
                        theme::TEXT_SECONDARY
                    })
                    .size(12);

                let count_text = text(format!("{}", entry.image_count))
                    .color(theme::TEXT_DIM)
                    .size(10);

                let entry_row = row![
                    name_text,
                    text("").width(Length::Fill),
                    count_text,
                ]
                .align_y(iced::Alignment::Center)
                .spacing(4.0);

                let btn = button(entry_row)
                    .on_press(SidebarMessage::FolderSelected(entry.path.clone()))
                    .width(Length::Fill)
                    .padding(iced::Padding {
                        top: 5.0,
                        right: 10.0,
                        bottom: 5.0,
                        left: 10.0,
                    })
                    .style(move |_theme, status| {
                        let bg = match (status, is_current) {
                            (button::Status::Hovered, _) => Some(theme::BG_CHROME_HOVER),
                            (button::Status::Pressed, _) => Some(theme::ACCENT_DIM),
                            (_, true) => Some(theme::ACCENT_DIM),
                            _ => None,
                        };
                        button::Style {
                            background: bg.map(iced::Background::Color),
                            border: iced::Border {
                                radius: 3.0.into(),
                                ..Default::default()
                            },
                            ..Default::default()
                        }
                    });

                children.push(btn.into());
            }
        }

        let content = column(children)
            .padding(iced::Padding {
                top: 8.0,
                right: 6.0,
                bottom: 8.0,
                left: 8.0,
            })
            .spacing(2.0);

        let scrollable_content = scrollable(content)
            .direction(scrollable::Direction::Vertical(
                scrollable::Scrollbar::new().width(4).scroller_width(4),
            ))
            .width(Length::Fill)
            .height(Length::Fill);

        container(scrollable_content)
            .width(Length::Fixed(SIDEBAR_WIDTH))
            .height(Length::Fill)
            .style(|_| container::Style {
                background: Some(theme::BG_CHROME.into()),
                border: iced::Border {
                    color: theme::BG_CHROME_BORDER,
                    width: 0.0,
                    radius: 0.0.into(),
                },
                ..Default::default()
            })
            .into()
    }

    pub fn width(&self) -> f32 {
        if self.visible {
            SIDEBAR_WIDTH
        } else {
            0.0
        }
    }
}

/// Count supported images in a directory (non-recursive).
fn count_images(dir: &Path, registry: &FormatRegistry) -> usize {
    std::fs::read_dir(dir)
        .into_iter()
        .flatten()
        .flatten()
        .map(|e| e.path())
        .filter(|p| p.is_file())
        .filter(|p| !p
            .file_name()
            .and_then(|n| n.to_str())
            .map(|n| n.starts_with('.'))
            .unwrap_or(true))
        .filter(|p| registry.check_anti_list(p).is_none())
        .filter(|p| registry.is_supported(p))
        .count()
}
