use anyhow::{Result, anyhow, bail};

use crate::menu::client::MenuClient;
use crate::menu_utils::{FzfResult, FzfWrapper, Header, MenuCursor};
use crate::ui::catppuccin::{colors, format_back_icon, format_icon_colored, fzf_mocha_args};
use crate::ui::nerd_font::NerdFont;
use crate::ui::preview::PreviewBuilder;

use super::browser::*;
use super::operations::*;
use super::types::*;
use super::utils::*;

pub(super) fn interactive_pass_menu() -> Result<i32> {
    interactive_pass_quick_access()
}

pub(super) fn interactive_pass_quick_access() -> Result<i32> {
    ensure_core_dependencies()?;

    let store_dir = ensure_password_store_dir()?;
    let mut cursor = MenuCursor::new();

    loop {
        let mut entries = load_entries(&store_dir)?;
        sort_entries_by_frecency(&mut entries)?;
        let quick_access_items = build_quick_access_items(&entries);

        let mut builder = FzfWrapper::builder()
            .header(Header::fancy("Pass"))
            .prompt("Copy")
            .args(fzf_mocha_args())
            .responsive_layout();

        if let Some(index) = cursor.initial_index(&quick_access_items) {
            builder = builder.initial_index(index);
        }

        match builder.select(quick_access_items.clone())? {
            FzfResult::Selected(item) => {
                cursor.update(&item, &quick_access_items);
                match item.kind {
                    BrowserItemKind::Entry(key) => {
                        let entry = resolve_entry_by_name(&entries, &key, false)?;
                        copy_primary_entry(&entry)?;
                        record_frecency(&entry.display_name)?;
                    }
                    BrowserItemKind::Menu => {
                        interactive_pass_tree_menu()?;
                    }
                    BrowserItemKind::Close => return Ok(0),
                    BrowserItemKind::Folder(_) | BrowserItemKind::Add | BrowserItemKind::Back => {}
                }
            }
            FzfResult::Cancelled => return Ok(1),
            _ => return Ok(1),
        }
    }
}

pub(super) fn interactive_pass_menu_server() -> Result<i32> {
    interactive_pass_quick_access_server()
}

pub(super) fn interactive_pass_quick_access_server() -> Result<i32> {
    ensure_core_dependencies()?;

    let client = MenuClient::new();
    let server_client = client.clone();
    let server_ready = std::thread::spawn(move || server_client.ensure_server_running());

    server_ready
        .join()
        .map_err(|_| anyhow!("menu server thread panicked"))??;

    let store_dir = ensure_password_store_dir()?;

    loop {
        let mut entries = load_entries(&store_dir)?;
        sort_entries_by_frecency(&mut entries)?;
        let menu_items = build_quick_access_menu_items(&entries);

        let selected = client.choice("Pass".to_string(), menu_items, false)?;
        if selected.is_empty() {
            return Ok(1);
        }

        let metadata = selected[0]
            .metadata
            .as_ref()
            .ok_or_else(|| anyhow!("Selected menu item missing metadata"))?;

        match metadata.get("kind").map(String::as_str) {
            Some("entry") => {
                let key = metadata
                    .get("key")
                    .ok_or_else(|| anyhow!("Entry item missing key metadata"))?;
                let entry = resolve_entry_by_name(&entries, key, false)?;
                copy_primary_entry(&entry)?;
                record_frecency(&entry.display_name)?;
            }
            Some("menu") => {
                crate::common::terminal::launch_menu_in_terminal("pass", "Pass", &[], false)?;
                return Ok(0);
            }
            Some("close") => return Ok(0),
            Some("folder" | "add" | "edit" | "back") => {}
            other => bail!("Unknown menu item kind: {:?}", other),
        }
    }
}

pub(super) fn interactive_pass_tree_menu() -> Result<i32> {
    run_edit_browser(None)?;
    Ok(0)
}

pub(super) fn run_add_menu(current_prefix: Option<&str>) -> Result<()> {
    let items = build_add_menu_items();

    if let FzfResult::Selected(item) = FzfWrapper::builder()
        .header(Header::fancy("Pass Add"))
        .prompt("Create")
        .args(fzf_mocha_args())
        .responsive_layout()
        .select(items)?
    {
        match item.action {
            AddMenuAction::AddPassword => {
                insert_password_entry_with_prefix(None, current_prefix)?;
            }
            AddMenuAction::GeneratePassword => {
                generate_password_entry_with_prefix(None, current_prefix, DEFAULT_PASSWORD_LENGTH)?;
            }
            AddMenuAction::AddOtp => {
                ensure_otp_dependency()?;
                insert_otp_entry_with_prefix(None, current_prefix)?;
            }
            AddMenuAction::Back => {}
        }
    }

    Ok(())
}

pub(super) fn run_edit_browser(initial_prefix: Option<&str>) -> Result<()> {
    let store_dir = ensure_password_store_dir()?;
    let mut path = initial_prefix.map(path_segments).unwrap_or_default();
    let mut cursor = MenuCursor::new();

    loop {
        let mut entries = load_entries(&store_dir)?;
        sort_entries_by_frecency(&mut entries)?;
        let browser_items = build_browser_menu_items(&entries, &path)?;

        let title = if path.is_empty() {
            "Edit Passwords".to_string()
        } else {
            format!("Edit Passwords / {}", path.join("/"))
        };

        let mut builder = FzfWrapper::builder()
            .header(Header::fancy(&title))
            .prompt("Select")
            .args(fzf_mocha_args())
            .responsive_layout();

        if let Some(index) = cursor.initial_index(&browser_items) {
            builder = builder.initial_index(index);
        }

        match builder.select(browser_items.clone())? {
            FzfResult::Selected(item) => {
                cursor.update(&item, &browser_items);
                match item.kind {
                    BrowserItemKind::Folder(folder) => path = path_segments(&folder),
                    BrowserItemKind::Entry(key) => {
                        let entry = resolve_entry_by_name(&entries, &key, false)?;
                        run_edit_action_menu(&entry)?;
                    }
                    BrowserItemKind::Back => {
                        if path.is_empty() {
                            return Ok(());
                        }
                        path.pop();
                    }
                    BrowserItemKind::Close => return Ok(()),
                    BrowserItemKind::Add => run_add_menu(path_prefix(&path).as_deref())?,
                    BrowserItemKind::Menu => {}
                }
            }
            FzfResult::Cancelled => {
                if path.is_empty() {
                    return Ok(());
                }
                path.pop();
            }
            _ => return Ok(()),
        }
    }
}

pub(super) fn run_edit_action_menu(entry: &PassEntry) -> Result<()> {
    let mut cursor = MenuCursor::new();

    loop {
        let refreshed_entries = load_entries(&ensure_password_store_dir()?)?;
        let current_entry = resolve_entry_by_name(&refreshed_entries, &entry.display_name, false);

        let current_entry = match current_entry {
            Ok(entry) => entry,
            Err(_) => return Ok(()),
        };

        let items = build_edit_action_items(&current_entry);
        let mut builder = FzfWrapper::builder()
            .header(Header::fancy(&format!(
                "Edit: {}",
                current_entry.display_name
            )))
            .prompt("Action")
            .args(fzf_mocha_args())
            .responsive_layout();

        if let Some(index) = cursor.initial_index(&items) {
            builder = builder.initial_index(index);
        }

        match builder.select(items.clone())? {
            FzfResult::Selected(item) => {
                cursor.update(&item, &items);
                match item.action {
                    EditAction::CopyPassword => {
                        copy_password_entry(&current_entry)?;
                        record_frecency(&current_entry.display_name)?;
                    }
                    EditAction::CopyOtp => {
                        copy_otp_entry(&current_entry)?;
                        record_frecency(&current_entry.display_name)?;
                    }
                    EditAction::Export => {
                        export_entry_flow(Some(current_entry.display_name.clone()), None)?;
                    }
                    EditAction::Rename => {
                        rename_entry_interactive(&current_entry)?;
                    }
                    EditAction::EditPassword => {
                        edit_password_entry(&current_entry)?;
                    }
                    EditAction::GeneratePassword => {
                        let key = current_entry
                            .secret_key
                            .clone()
                            .unwrap_or(current_entry.display_name.clone());
                        generate_password_entry(Some(key), DEFAULT_PASSWORD_LENGTH)?;
                    }
                    EditAction::EditOtp => {
                        ensure_otp_dependency()?;
                        upsert_otp_entry_interactive(&current_entry)?;
                    }
                    EditAction::Delete => {
                        delete_entry_flow(Some(current_entry.display_name.clone()))?;
                        return Ok(());
                    }
                    EditAction::Back => return Ok(()),
                }
            }
            FzfResult::Cancelled => return Ok(()),
            _ => return Ok(()),
        }
    }
}

fn build_add_menu_items() -> Vec<AddMenuItem> {
    vec![
        AddMenuItem {
            key: "add-password",
            display: format!(
                "{} Add Password",
                format_icon_colored(NerdFont::Plus, colors::GREEN)
            ),
            preview: PreviewBuilder::new()
                .header(NerdFont::Plus, "Add Password")
                .text("Create a password entry in the pass store.")
                .blank()
                .bullet("Prompts for a name")
                .bullet("Prompts for password + confirmation")
                .build(),
            action: AddMenuAction::AddPassword,
        },
        AddMenuItem {
            key: "generate-password",
            display: format!(
                "{} Generate Password",
                format_icon_colored(NerdFont::Refresh, colors::TEAL)
            ),
            preview: PreviewBuilder::new()
                .header(NerdFont::Refresh, "Generate Password")
                .text("Generate a 20-character password into a pass entry.")
                .blank()
                .bullet("Prompts for a name")
                .bullet("Uses `pass generate -f`")
                .build(),
            action: AddMenuAction::GeneratePassword,
        },
        AddMenuItem {
            key: "add-otp",
            display: format!(
                "{} Add OTP",
                format_icon_colored(NerdFont::Clock, colors::SAPPHIRE)
            ),
            preview: PreviewBuilder::new()
                .header(NerdFont::Clock, "Add OTP")
                .text("Create a standalone OTP entry using pass-otp.")
                .blank()
                .bullet("Prompts for a name")
                .bullet("Accepts only `otpauth://` URIs")
                .build(),
            action: AddMenuAction::AddOtp,
        },
        AddMenuItem {
            key: "back",
            display: format!("{} Back", format_back_icon()),
            preview: PreviewBuilder::new()
                .header(NerdFont::ArrowLeft, "Back")
                .text("Return to the pass browser.")
                .build(),
            action: AddMenuAction::Back,
        },
    ]
}

fn build_edit_action_items(entry: &PassEntry) -> Vec<EditActionItem> {
    let mut items = Vec::new();

    if entry.has_secret() {
        items.push(EditActionItem {
            key: "copy-password",
            display: format!(
                "{} Copy Password",
                format_icon_colored(NerdFont::Clipboard, colors::GREEN)
            ),
            preview: PreviewBuilder::new()
                .header(NerdFont::Clipboard, "Copy Password")
                .text("Copy the first line of the pass entry to the clipboard.")
                .build(),
            action: EditAction::CopyPassword,
        });
    }

    if entry.has_otp() {
        items.push(EditActionItem {
            key: "copy-otp",
            display: format!(
                "{} Copy OTP",
                format_icon_colored(NerdFont::Clock, colors::TEAL)
            ),
            preview: PreviewBuilder::new()
                .header(NerdFont::Clock, "Copy OTP")
                .text("Generate the current OTP code and copy it to the clipboard.")
                .build(),
            action: EditAction::CopyOtp,
        });
    }

    items.push(EditActionItem {
        key: "export",
        display: format!(
            "{} Export",
            format_icon_colored(NerdFont::Upload, colors::LAVENDER)
        ),
        preview: PreviewBuilder::new()
            .header(NerdFont::Upload, "Export Entry")
            .text("Write the decrypted entry content to a file.")
            .build(),
        action: EditAction::Export,
    });

    items.push(EditActionItem {
        key: "rename",
        display: format!(
            "{} Rename",
            format_icon_colored(NerdFont::Edit, colors::BLUE)
        ),
        preview: PreviewBuilder::new()
            .header(NerdFont::Edit, "Rename Entry")
            .text("Rename the selected pass entry.")
            .build(),
        action: EditAction::Rename,
    });

    if entry.has_secret() {
        items.push(EditActionItem {
            key: "edit-password",
            display: format!(
                "{} Edit Password",
                format_icon_colored(NerdFont::Key, colors::PEACH)
            ),
            preview: PreviewBuilder::new()
                .header(NerdFont::Key, "Edit Password")
                .text("Open the entry in `pass edit` using `nvim --clean`.")
                .build(),
            action: EditAction::EditPassword,
        });

        items.push(EditActionItem {
            key: "generate-password",
            display: format!(
                "{} Generate Password",
                format_icon_colored(NerdFont::Refresh, colors::SAPPHIRE)
            ),
            preview: PreviewBuilder::new()
                .header(NerdFont::Refresh, "Generate Password")
                .text("Generate a fresh password into this entry.")
                .build(),
            action: EditAction::GeneratePassword,
        });
    }

    if entry.has_otp() {
        items.push(EditActionItem {
            key: "edit-otp",
            display: format!(
                "{} Edit OTP",
                format_icon_colored(NerdFont::Clock, colors::TEAL)
            ),
            preview: PreviewBuilder::new()
                .header(NerdFont::Clock, "Edit OTP")
                .text("Replace the stored OTP URI for this entry.")
                .build(),
            action: EditAction::EditOtp,
        });
    }

    items.push(EditActionItem {
        key: "delete",
        display: format!(
            "{} Delete",
            format_icon_colored(NerdFont::Trash, colors::RED)
        ),
        preview: PreviewBuilder::new()
            .header(NerdFont::Trash, "Delete Entry")
            .text("Remove the selected pass entry with confirmation.")
            .build(),
        action: EditAction::Delete,
    });

    items.push(EditActionItem {
        key: "back",
        display: format!("{} Back", format_back_icon()),
        preview: PreviewBuilder::new()
            .header(NerdFont::ArrowLeft, "Back")
            .text("Return to the edit browser.")
            .build(),
        action: EditAction::Back,
    });

    items
}
