use crate::ldap::ChildNode;
use crate::model::{DitNode, FlatEntry, Pane, flat_view};

use super::App;
use super::state::{Mode, PendingExpansion};

/// この件数を超えたら展開前に確認ダイアログを表示する
const EXPAND_CONFIRM_THRESHOLD: usize = 100;

// ── Tree ──────────────────────────────────────────────────────────────────────

/// DIT ツリー表示の状態（root + cursor + base_dn）。
/// flat_view 上のインデックスベースのカーソルを `usize` で公開していた旧実装を
/// 安全な API でラップする。flat_view は呼び出し時に都度 DFS で再構築する
/// （typical な DIT は <1000 ノードのため許容コスト）。
pub struct Tree {
    root: DitNode,
    cursor: usize,
    base_dn: String,
}

/// カーソル位置の表層情報（DFS 1 回で取れる軽量サマリ）
pub struct NodeInfo {
    pub dn: String,
    pub depth: usize,
    pub expanded: bool,
    pub has_children: bool,
}

/// `collapse_or_parent` の結果
pub enum CollapseResult {
    /// 何もしなかった（root で ← 等）
    NoOp,
    /// 展開済みノードを折りたたんだ
    Collapsed,
    /// 親ノードへカーソルを移動した（移動先 DN）
    MovedToParent(String),
}

impl Tree {
    /// ベース DN と取得済み子から Tree を構築（ルートは展開済みで返す）
    pub fn from_children(base_dn: String, children: Vec<ChildNode>) -> Self {
        let has_children = !children.is_empty();
        let root = DitNode {
            dn: base_dn.clone(),
            has_children,
            expanded: true,
            children: Some(children.into_iter().map(child_to_dit).collect()),
        };
        Self {
            root,
            cursor: 0,
            base_dn,
        }
    }

    /// 単一ノード（エラー表示用などの placeholder）から構築
    pub fn from_root(root: DitNode, base_dn: String) -> Self {
        Self {
            root,
            cursor: 0,
            base_dn,
        }
    }

    pub fn root(&self) -> &DitNode {
        &self.root
    }
    pub fn cursor(&self) -> usize {
        self.cursor
    }
    pub fn base_dn(&self) -> &str {
        &self.base_dn
    }

    pub fn flat(&self) -> Vec<FlatEntry<'_>> {
        flat_view(&self.root)
    }

    pub fn cursor_up(&mut self) {
        self.cursor = self.cursor.saturating_sub(1);
    }

    pub fn cursor_down(&mut self) {
        let max = self.flat().len().saturating_sub(1);
        if self.cursor < max {
            self.cursor += 1;
        }
    }

    /// flat_view 上の任意位置にカーソルを直接設定する（範囲外は末尾に丸める）。
    /// 削除後に親へ移動する用途で利用。
    pub fn set_cursor(&mut self, idx: usize) {
        let max = self.flat().len().saturating_sub(1);
        self.cursor = idx.min(max);
    }

    /// カーソル位置の親ノードの (DN, flat_view 上のインデックス) を返す。
    /// ルート (depth=0) の場合は None。
    pub fn parent_info(&self) -> Option<(String, usize)> {
        let info = self.selected_info()?;
        if info.depth == 0 {
            return None;
        }
        let flat = self.flat();
        let idx = flat[..self.cursor]
            .iter()
            .rposition(|e| e.depth < info.depth)?;
        Some((flat[idx].node.dn.clone(), idx))
    }

    pub fn selected_dn(&self) -> Option<String> {
        self.flat().get(self.cursor).map(|e| e.node.dn.clone())
    }

    pub fn selected_info(&self) -> Option<NodeInfo> {
        let flat = self.flat();
        let e = flat.get(self.cursor)?;
        Some(NodeInfo {
            dn: e.node.dn.clone(),
            depth: e.depth,
            expanded: e.node.expanded,
            has_children: e.node.has_children,
        })
    }

    /// 折りたたみ／親移動。展開済みなら子キャッシュを保ったまま collapse、
    /// 未展開かつ root 以外なら親へカーソルを移動する。
    pub fn collapse_or_parent(&mut self) -> CollapseResult {
        let info = match self.selected_info() {
            Some(i) => i,
            None => return CollapseResult::NoOp,
        };

        if info.expanded {
            if let Some(node) = self.root.find_mut(&info.dn) {
                node.collapse();
            }
            return CollapseResult::Collapsed;
        }

        if info.depth == 0 {
            return CollapseResult::NoOp;
        }

        let flat = self.flat();
        let Some(idx) = flat[..self.cursor]
            .iter()
            .rposition(|e| e.depth < info.depth)
        else {
            return CollapseResult::NoOp;
        };
        let parent_dn = flat[idx].node.dn.clone();
        self.cursor = idx;
        CollapseResult::MovedToParent(parent_dn)
    }

    /// 指定 DN のノードに子を流し込んで展開状態にする
    pub fn expand_at(&mut self, dn: &str, children: Vec<ChildNode>) {
        if let Some(node) = self.root.find_mut(dn) {
            node.set_children(children.into_iter().map(child_to_dit).collect());
        }
    }

    /// 子なしと確定させる（has_children=false かつ children=Some([])）
    pub fn mark_no_children_at(&mut self, dn: &str) {
        if let Some(node) = self.root.find_mut(dn) {
            node.mark_no_children();
        }
    }
}

fn child_to_dit(c: ChildNode) -> DitNode {
    DitNode::unloaded(c.dn, c.has_children)
}

// ── App: tree 操作の薄いラッパ ────────────────────────────────────────────────

impl App {
    pub(super) fn toggle_pane(&mut self) {
        self.active_pane = match self.active_pane {
            Pane::Tree => Pane::Detail,
            Pane::Detail => Pane::Tree,
        };
    }

    pub(super) fn tree_up(&mut self) {
        if let Some(t) = &mut self.browse {
            t.cursor_up();
        }
    }

    pub(super) fn tree_down(&mut self) {
        if let Some(t) = &mut self.browse {
            t.cursor_down();
        }
    }

    pub(super) fn selected_tree_dn(&self) -> Option<String> {
        self.browse.as_ref().and_then(|t| t.selected_dn())
    }

    /// → キー: 常に LDAP から再フェッチして展開
    pub(super) async fn expand_selected(&mut self) {
        let info = match self.browse.as_ref().and_then(|t| t.selected_info()) {
            Some(i) => i,
            None => return,
        };
        if !info.has_children || info.expanded {
            return;
        }

        let Some(result) = self.ldap_children(&info.dn).await else {
            return;
        };

        match result {
            Ok(children) if children.len() > EXPAND_CONFIRM_THRESHOLD => {
                self.status = format!(
                    "{} 件見つかりました。全件表示しますか？ [y/N]",
                    children.len()
                );
                self.mode = Mode::ConfirmExpand(PendingExpansion {
                    dn: info.dn,
                    children,
                });
            }
            Ok(children) if !children.is_empty() => {
                if let Some(t) = &mut self.browse {
                    t.expand_at(&info.dn, children);
                }
            }
            Ok(_) => {
                if let Some(t) = &mut self.browse {
                    t.mark_no_children_at(&info.dn);
                }
            }
            Err(e) => {
                self.status = format!("Expand error: {e}");
            }
        }
    }

    /// ConfirmExpand から確定された展開を Tree に反映する
    pub(super) fn apply_expansion(&mut self, dn: &str, children: Vec<ChildNode>) {
        if let Some(t) = &mut self.browse {
            t.expand_at(dn, children);
        }
    }

    /// ← キー: 展開済みなら折りたたみ、未展開なら親へ移動
    pub(super) fn collapse_or_parent(&mut self) {
        let result = match &mut self.browse {
            Some(t) => t.collapse_or_parent(),
            None => return,
        };
        if let CollapseResult::MovedToParent(parent_dn) = result {
            // 親が現在のエントリと異なれば詳細をクリア
            if self.current_entry.as_ref().map(|e| e.dn.as_str()) != Some(parent_dn.as_str()) {
                self.current_entry = None;
            }
        }
    }
}
