use std::{env, ffi::OsStr, fmt::Write, path::Path};

use regex::Regex;
use yazi_config::{THEME, YAZI};
use yazi_emulator::Mux;
use yazi_fs::Xdg;
use yazi_shared::timestamp_us;

use super::Actions;

impl Actions {
	pub(super) fn debug() -> Result<String, std::fmt::Error> {
		let mut s = String::new();
		writeln!(s, "\nYazi")?;
		writeln!(s, "    Version  : {}", Self::version())?;
		writeln!(s, "    Debug    : {}", cfg!(debug_assertions))?;
		writeln!(s, "    Triple   : {}", Self::triple())?;
		writeln!(s, "    Rustc    : {}", Self::rustc())?;
		writeln!(s, "    Backtrace: {:?}", env::var_os("RUST_BACKTRACE"))?;

		writeln!(s, "\nYa")?;
		writeln!(s, "    Version: {}", Self::process_output("ya", "--version"))?;

		writeln!(s, "\nConfig")?;
		writeln!(s, "    Init             : {}", Self::config_state("init.lua"))?;
		writeln!(s, "    Yazi             : {}", Self::config_state("yazi.toml"))?;
		writeln!(s, "    Keymap           : {}", Self::config_state("keymap.toml"))?;
		writeln!(s, "    Theme            : {}", Self::config_state("theme.toml"))?;
		writeln!(s, "    VFS              : {}", Self::config_state("vfs.toml"))?;
		writeln!(s, "    Package          : {}", Self::config_state("package.toml"))?;
		writeln!(s, "    Dark/light flavor: {:?} / {:?}", THEME.flavor.dark, THEME.flavor.light)?;

		writeln!(s, "\nEmulator")?;
		writeln!(s, "    TERM                : {:?}", env::var_os("TERM"))?;
		writeln!(s, "    TERM_PROGRAM        : {:?}", env::var_os("TERM_PROGRAM"))?;
		writeln!(s, "    TERM_PROGRAM_VERSION: {:?}", env::var_os("TERM_PROGRAM_VERSION"))?;
		writeln!(s, "    Brand.from_env      : {:?}", yazi_emulator::Brand::from_env())?;
		writeln!(s, "    Emulator.detect     : {:?}", &*yazi_emulator::EMULATOR)?;

		writeln!(s, "\nAdapter")?;
		writeln!(s, "    Adapter.matches    : {:?}", yazi_adapter::ADAPTOR)?;
		writeln!(s, "    Dimension.available: {:?}", yazi_emulator::Dimension::available())?;

		writeln!(s, "\nDesktop")?;
		writeln!(s, "    XDG_SESSION_TYPE           : {:?}", env::var_os("XDG_SESSION_TYPE"))?;
		writeln!(s, "    WAYLAND_DISPLAY            : {:?}", env::var_os("WAYLAND_DISPLAY"))?;
		writeln!(s, "    DISPLAY                    : {:?}", env::var_os("DISPLAY"))?;
		writeln!(s, "    SWAYSOCK                   : {:?}", env::var_os("SWAYSOCK"))?;
		#[rustfmt::skip]
		writeln!(s, "    HYPRLAND_INSTANCE_SIGNATURE: {:?}", env::var_os("HYPRLAND_INSTANCE_SIGNATURE"))?;
		writeln!(s, "    WAYFIRE_SOCKET             : {:?}", env::var_os("WAYFIRE_SOCKET"))?;

		writeln!(s, "\nSSH")?;
		writeln!(s, "    shared.in_ssh_connection: {}", yazi_shared::in_ssh_connection())?;

		writeln!(s, "\nWSL")?;
		writeln!(s, "    WSL: {:?}", yazi_adapter::WSL)?;

		writeln!(s, "\nVariables")?;
		writeln!(s, "    SHELL              : {:?}", env::var_os("SHELL"))?;
		writeln!(s, "    EDITOR             : {:?}", env::var_os("EDITOR"))?;
		writeln!(s, "    VISUAL             : {:?}", env::var_os("VISUAL"))?;
		writeln!(s, "    YAZI_FILE_ONE      : {:?}", env::var_os("YAZI_FILE_ONE"))?;
		writeln!(s, "    YAZI_CONFIG_HOME   : {:?}", env::var_os("YAZI_CONFIG_HOME"))?;
		writeln!(s, "    YAZI_ZOXIDE_OPTS   : {:?}", env::var_os("YAZI_ZOXIDE_OPTS"))?;
		writeln!(s, "    SSH_AUTH_SOCK      : {:?}", env::var_os("SSH_AUTH_SOCK"))?;
		writeln!(s, "    FZF_DEFAULT_OPTS   : {:?}", env::var_os("FZF_DEFAULT_OPTS"))?;
		writeln!(s, "    FZF_DEFAULT_COMMAND: {:?}", env::var_os("FZF_DEFAULT_COMMAND"))?;

		writeln!(s, "\nText Opener")?;
		#[rustfmt::skip]
		writeln!(
			s, "    default     : {:?}",
			YAZI.open.match_dummy(Path::new("f75a.txt"), "text/plain").and_then(|r| YAZI.opener.first(&r))
		)?;
		#[rustfmt::skip]
		writeln!(
			s, "    block-create: {:?}",
			YAZI.open.match_dummy(Path::new("bulk-create.txt"), "text/plain").and_then(|r| YAZI.opener.block(&r))
		)?;
		#[rustfmt::skip]
		writeln!(
			s, "    block-rename: {:?}",
			YAZI.open.match_dummy(Path::new("bulk-rename.txt"), "text/plain").and_then(|r| YAZI.opener.block(&r))
		)?;

		writeln!(s, "\nMultiplexers")?;
		writeln!(s, "    TMUX               : {}", yazi_emulator::TMUX)?;
		writeln!(s, "    tmux version       : {}", Self::process_output("tmux", "-V"))?;
		writeln!(s, "    tmux build flags   : enable-sixel={}", Mux::tmux_sixel_flag())?;
		writeln!(s, "    ZELLIJ_SESSION_NAME: {:?}", env::var_os("ZELLIJ_SESSION_NAME"))?;
		writeln!(s, "    Zellij version     : {}", Self::process_output("zellij", "--version"))?;

		writeln!(s, "\nDependencies")?;
		#[rustfmt::skip]
		writeln!(s, "    file          : {}", Self::process_output(env::var_os("YAZI_FILE_ONE").unwrap_or("file".into()), "--version"))?;
		writeln!(s, "    ueberzugpp    : {}", Self::process_output("ueberzugpp", "--version"))?;
		#[rustfmt::skip]
		writeln!(s, "    ffmpeg/ffprobe: {} / {}", Self::process_output("ffmpeg", "-version"), Self::process_output("ffprobe", "-version"))?;
		writeln!(s, "    pdftoppm      : {}", Self::process_output("pdftoppm", "--help"))?;
		writeln!(s, "    magick        : {}", Self::process_output("magick", "--version"))?;
		writeln!(s, "    fzf           : {}", Self::process_output("fzf", "--version"))?;
		#[rustfmt::skip]
		writeln!(s, "    fd/fdfind     : {} / {}", Self::process_output("fd", "--version"), Self::process_output("fdfind", "--version"))?;
		writeln!(s, "    rg            : {}", Self::process_output("rg", "--version"))?;
		writeln!(s, "    chafa         : {}", Self::process_output("chafa", "--version"))?;
		writeln!(s, "    zoxide        : {}", Self::process_output("zoxide", "--version"))?;
		#[rustfmt::skip]
		writeln!(s, "    7zz/7z        : {} / {}", Self::process_output("7zz", "i"), Self::process_output("7z", "i"))?;
		writeln!(s, "    resvg         : {}", Self::process_output("resvg", "--version"))?;
		writeln!(s, "    jq            : {}", Self::process_output("jq", "--version"))?;

		writeln!(s, "\nClipboard")?;
		#[rustfmt::skip]
		writeln!(s, "    wl-copy/paste: {} / {}", Self::process_output("wl-copy", "--version"), Self::process_output("wl-paste", "--version"))?;
		writeln!(s, "    xclip        : {}", Self::process_output("xclip", "-version"))?;
		writeln!(s, "    xsel         : {}", Self::process_output("xsel", "--version"))?;

		writeln!(s, "\nRoutine")?;
		writeln!(s, "    `file -bL --mime-type`: {}", Self::file1_output())?;

		writeln!(
			s,
			"\n\nSee https://yazi-rs.github.io/docs/plugins/overview#debugging on how to enable logging or debug runtime errors."
		)?;

		Ok(s)
	}

	fn config_state(name: &str) -> String {
		let p = Xdg::config_dir().join(name);
		match std::fs::read_to_string(&p) {
			Ok(s) if s.is_empty() => format!("{} (empty)", p.display()),
			Ok(s) if s.trim().is_empty() => format!("{} (whitespaces)", p.display()),
			Ok(s) => format!("{} ({} chars)", p.display(), s.chars().count()),
			Err(e) => format!("{} ({e})", p.display()),
		}
	}

	fn process_output(name: impl AsRef<OsStr>, arg: impl AsRef<OsStr>) -> String {
		match std::process::Command::new(&name).arg(arg).output() {
			Ok(out) if out.status.success() => {
				let line =
					String::from_utf8_lossy(&if out.stdout.is_empty() { out.stderr } else { out.stdout })
						.trim()
						.lines()
						.next()
						.unwrap_or_default()
						.to_owned();
				if name.as_ref() == "ya" {
					line.trim_start_matches("Ya ").to_owned()
				} else {
					Regex::new(r"\d+\.\d+(\.\d+-\d+|\.\d+|\b)")
						.unwrap()
						.find(&line)
						.map(|m| m.as_str().to_owned())
						.unwrap_or(line)
				}
			}
			Ok(out) => format!("{:?}, {:?}", out.status, String::from_utf8_lossy(&out.stderr)),
			Err(e) => format!("{e}"),
		}
	}

	fn file1_output() -> String {
		use std::io::Write;

		let p = env::temp_dir().join(format!(".yazi-debug-{}.tmp", timestamp_us()));
		std::fs::File::create_new(&p).map(|mut f| f.write_all(b"Hello, World!")).ok();

		let program = env::var_os("YAZI_FILE_ONE").unwrap_or("file".into());
		match std::process::Command::new(program).args(["-bL", "--mime-type"]).arg(&p).output() {
			Ok(out) => {
				String::from_utf8_lossy(&out.stdout).trim().lines().next().unwrap_or_default().to_owned()
			}
			Err(e) => format!("{e}"),
		}
	}
}
