//! Hot-apply Qt/KDE colors from colors.toml for standalone apps (Dolphin, QtPass).
//!
//! Linux: Dolphin reads `[Colors:View]` in `~/.config/kdeglobals` (decimal R,G,B);
//! Stylix Base16Kvantum `GeneralColors` is refreshed for qt5ct/Kvantum chrome.
//!
//! macOS: Kvantum/qt5ct are Linux-only in nixpkgs. QtPass is wrapped with
//! `QT_STYLE_OVERRIDE=Fusion` + `-stylesheet ~/.config/qtpass/dendritic.qss`
//! (written here on every wallpaper/theme flip).

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

use crate::palette::load_palette;
use crate::state;

fn req<'a>(map: &'a HashMap<String, String>, key: &str) -> Result<&'a str, String> {
    map.get(key)
        .map(String::as_str)
        .ok_or_else(|| format!("palette missing {key}"))
}

fn hex_to_rgb(hex: &str) -> Result<String, String> {
    let h = hex.trim().trim_start_matches('#');
    if h.len() != 6 {
        return Err(format!("bad hex: {hex}"));
    }
    let r = u8::from_str_radix(&h[0..2], 16).map_err(|e| e.to_string())?;
    let g = u8::from_str_radix(&h[2..4], 16).map_err(|e| e.to_string())?;
    let b = u8::from_str_radix(&h[4..6], 16).map_err(|e| e.to_string())?;
    Ok(format!("{r},{g},{b}"))
}

fn kdeglobals_path() -> PathBuf {
    state::home_dir()
        .map(|h| h.join(".config/kdeglobals"))
        .unwrap_or_else(|| PathBuf::from("kdeglobals"))
}

fn kvantum_theme_dir() -> PathBuf {
    state::home_dir()
        .map(|h| h.join(".config/Kvantum/Base16Kvantum"))
        .unwrap_or_else(|| PathBuf::from("Base16Kvantum"))
}

fn qtpass_qss_path() -> PathBuf {
    state::home_dir()
        .map(|h| h.join(".config/qtpass/dendritic.qss"))
        .unwrap_or_else(|| PathBuf::from("dendritic.qss"))
}

fn write_replace(path: &Path, body: &str) -> Result<(), String> {
    if let Some(parent) = path.parent() {
        std::fs::create_dir_all(parent).map_err(|e| format!("mkdir {}: {e}", parent.display()))?;
    }
    let _ = std::fs::remove_file(path);
    std::fs::write(path, body).map_err(|e| format!("write {}: {e}", path.display()))?;
    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        let _ = std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o644));
    }
    Ok(())
}

/// KDE color scheme sections Dolphin / KF6 read outside Plasma.
pub fn write_kdeglobals(colors_path: &Path) -> Result<PathBuf, String> {
    let p = load_palette(colors_path)?;
    let b00 = hex_to_rgb(req(&p, "base00")?)?;
    let b01 = hex_to_rgb(req(&p, "base01")?)?;
    let b02 = hex_to_rgb(req(&p, "base02")?)?;
    let _b03 = hex_to_rgb(req(&p, "base03")?)?;
    let b04 = hex_to_rgb(req(&p, "base04")?)?;
    let b05 = hex_to_rgb(req(&p, "base05")?)?;
    let b06 = hex_to_rgb(req(&p, "base06")?)?;
    let b08 = hex_to_rgb(req(&p, "base08")?)?;
    let b09 = hex_to_rgb(req(&p, "base09")?)?;
    let b0b = hex_to_rgb(req(&p, "base0B")?)?;
    let b0d = hex_to_rgb(req(&p, "base0D")?)?;
    let b0e = hex_to_rgb(req(&p, "base0E")?)?;

    let body = format!(
        r#"# Generated by dendritic-appearance from colors.toml — do not edit.
[General]
ColorScheme=Dendritic

[Colors:View]
BackgroundNormal={b00}
BackgroundAlternate={b01}
ForegroundNormal={b05}
ForegroundInactive={b04}
ForegroundActive={b0d}
ForegroundLink={b0d}
ForegroundVisited={b0e}
ForegroundNegative={b08}
ForegroundNeutral={b09}
ForegroundPositive={b0b}
DecorationFocus={b0d}
DecorationHover={b0d}

[Colors:Window]
BackgroundNormal={b01}
BackgroundAlternate={b00}
ForegroundNormal={b05}
ForegroundInactive={b04}
ForegroundActive={b0d}
ForegroundLink={b0d}
ForegroundVisited={b0e}
ForegroundNegative={b08}
ForegroundNeutral={b09}
ForegroundPositive={b0b}
DecorationFocus={b0d}
DecorationHover={b0d}

[Colors:Button]
BackgroundNormal={b02}
BackgroundAlternate={b01}
ForegroundNormal={b05}
ForegroundInactive={b04}
ForegroundActive={b0d}
ForegroundLink={b0d}
ForegroundVisited={b0e}
ForegroundNegative={b08}
ForegroundNeutral={b09}
ForegroundPositive={b0b}
DecorationFocus={b0d}
DecorationHover={b0d}

[Colors:Selection]
BackgroundNormal={b0d}
BackgroundAlternate={b0e}
ForegroundNormal={b00}
ForegroundInactive={b01}
ForegroundActive={b06}
ForegroundLink={b00}
ForegroundVisited={b01}
ForegroundNegative={b08}
ForegroundNeutral={b09}
ForegroundPositive={b0b}
DecorationFocus={b0d}
DecorationHover={b0d}

[Colors:Tooltip]
BackgroundNormal={b00}
BackgroundAlternate={b01}
ForegroundNormal={b05}
ForegroundInactive={b04}
ForegroundActive={b0d}
ForegroundLink={b0d}
ForegroundVisited={b0e}
ForegroundNegative={b08}
ForegroundNeutral={b09}
ForegroundPositive={b0b}
DecorationFocus={b0d}
DecorationHover={b0d}

[Colors:Complementary]
BackgroundNormal={b02}
BackgroundAlternate={b01}
ForegroundNormal={b05}
ForegroundInactive={b04}
ForegroundActive={b0d}
ForegroundLink={b0d}
ForegroundVisited={b0e}
ForegroundNegative={b08}
ForegroundNeutral={b09}
ForegroundPositive={b0b}
DecorationFocus={b0d}
DecorationHover={b0d}

[Colors:Header]
BackgroundNormal={b01}
BackgroundAlternate={b00}
ForegroundNormal={b05}
ForegroundInactive={b04}
ForegroundActive={b0d}
ForegroundLink={b0d}
ForegroundVisited={b0e}
ForegroundNegative={b08}
ForegroundNeutral={b09}
ForegroundPositive={b0b}
DecorationFocus={b0d}
DecorationHover={b0d}

[WM]
activeBackground={b01}
activeForeground={b05}
inactiveBackground={b00}
inactiveForeground={b04}
"#
    );

    let dest = kdeglobals_path();
    write_replace(&dest, &body)?;
    Ok(dest)
}

/// Refresh Stylix Base16Kvantum GeneralColors from the live wallpaper palette.
pub fn write_kvantum_colors(colors_path: &Path) -> Result<(), String> {
    let dir = kvantum_theme_dir();
    let dest = dir.join("Base16Kvantum.kvconfig");
    if !dest.exists() && !dest.is_symlink() {
        // Stylix Qt target not installed — skip quietly.
        return Ok(());
    }

    let p = load_palette(colors_path)?;
    let b00 = req(&p, "base00")?;
    let b01 = req(&p, "base01")?;
    let b02 = req(&p, "base02")?;
    let b03 = req(&p, "base03")?;
    let b04 = req(&p, "base04")?;
    let b05 = req(&p, "base05")?;
    let b0d = req(&p, "base0D")?;
    let b0e = req(&p, "base0E")?;

    let general_colors = format!(
        r#"[GeneralColors]
window.color={b01}
base.color={b00}
alt.base.color={b01}
button.color={b02}
light.color={b03}
mid.light.color={b03}
dark.color={b00}
mid.color={b00}
highlight.color={b0e}
inactive.highlight.color={b03}
tooltip.base.color={b00}
text.color={b05}
window.text.color={b05}
button.text.color={b05}
disabled.text.color={b04}
tooltip.text.color={b05}
highlight.text.color={b00}
link.color={b0d}
link.visited.color={b0e}
"#
    );

    // Materialize a writable copy if HM left a store symlink.
    let raw = std::fs::read_to_string(&dest).map_err(|e| format!("read {}: {e}", dest.display()))?;
    let updated = replace_ini_section(&raw, "GeneralColors", &general_colors);
    write_replace(&dest, &updated)?;

    // Ensure theme selection points at Base16Kvantum.
    let kvantum_cfg = state::home_dir()
        .map(|h| h.join(".config/Kvantum/kvantum.kvconfig"))
        .unwrap_or_else(|| PathBuf::from("kvantum.kvconfig"));
    if kvantum_cfg.exists() || kvantum_cfg.is_symlink() {
        let body = "[General]\ntheme=Base16Kvantum\n";
        let _ = write_replace(&kvantum_cfg, body);
    }

    Ok(())
}

fn replace_ini_section(src: &str, section: &str, replacement: &str) -> String {
    let header = format!("[{section}]");
    let mut out = String::new();
    let mut lines = src.lines().peekable();
    let mut replaced = false;
    while let Some(line) = lines.next() {
        if line.trim() == header {
            if !replaced {
                out.push_str(replacement.trim_end());
                out.push('\n');
                if !out.ends_with("\n\n") {
                    out.push('\n');
                }
                replaced = true;
            }
            // Skip old section body until next [Section] or EOF.
            while let Some(next) = lines.peek() {
                let t = next.trim();
                if t.starts_with('[') && t.ends_with(']') {
                    break;
                }
                lines.next();
            }
            continue;
        }
        out.push_str(line);
        out.push('\n');
    }
    if !replaced {
        if !out.ends_with('\n') && !out.is_empty() {
            out.push('\n');
        }
        out.push_str(replacement.trim_end());
        out.push('\n');
    }
    out
}

/// Fusion QSS for macOS QtPass (and a Linux fallback if Kvantum is absent).
pub fn write_qtpass_qss(colors_path: &Path) -> Result<PathBuf, String> {
    let p = load_palette(colors_path)?;
    let b00 = req(&p, "base00")?;
    let b01 = req(&p, "base01")?;
    let b02 = req(&p, "base02")?;
    let b03 = req(&p, "base03")?;
    let b04 = req(&p, "base04")?;
    let b05 = req(&p, "base05")?;
    let b0d = req(&p, "base0D")?;
    let b0e = req(&p, "base0E")?;

    let body = format!(
        r#"/* Generated by dendritic-appearance from colors.toml — do not edit. */
QWidget {{
  background-color: {b00};
  color: {b05};
  selection-background-color: {b02};
  selection-color: {b05};
}}
QMainWindow, QDialog, QMenuBar, QMenu, QToolBar, QStatusBar, QDockWidget {{
  background-color: {b00};
  color: {b05};
  border: none;
}}
QToolBar {{
  background-color: {b01};
  spacing: 4px;
  padding: 2px;
}}
QStatusBar {{
  background-color: {b01};
}}
QLineEdit, QTextEdit, QPlainTextEdit, QSpinBox, QComboBox, QAbstractSpinBox {{
  background-color: {b01};
  color: {b05};
  border: 1px solid {b03};
  border-radius: 3px;
  padding: 3px 6px;
  selection-background-color: {b02};
}}
QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus, QComboBox:focus {{
  border: 1px solid {b0d};
}}
QTreeView, QListView, QTableView, QAbstractItemView {{
  background-color: {b00};
  alternate-background-color: {b01};
  color: {b05};
  border: 1px solid {b02};
  outline: 0;
}}
QTreeView::item:selected, QListView::item:selected, QTableView::item:selected {{
  background-color: {b02};
  color: {b05};
}}
QTreeView::item:hover, QListView::item:hover {{
  background-color: {b01};
}}
QHeaderView::section {{
  background-color: {b01};
  color: {b05};
  border: 1px solid {b02};
  padding: 4px 6px;
}}
QPushButton, QToolButton {{
  background-color: {b02};
  color: {b05};
  border: 1px solid {b03};
  border-radius: 3px;
  padding: 4px 10px;
}}
QPushButton:hover, QToolButton:hover {{
  background-color: {b03};
  border: 1px solid {b0d};
}}
QPushButton:pressed, QToolButton:pressed {{
  background-color: {b0d};
  color: {b00};
}}
QPushButton:disabled, QToolButton:disabled {{
  color: {b04};
  background-color: {b01};
}}
QCheckBox, QRadioButton, QLabel {{
  color: {b05};
  background-color: transparent;
}}
QGroupBox {{
  border: 1px solid {b02};
  margin-top: 8px;
  padding-top: 8px;
  color: {b05};
}}
QGroupBox::title {{
  subcontrol-origin: margin;
  left: 8px;
  padding: 0 4px;
  color: {b05};
}}
QScrollBar:vertical {{
  background: {b00};
  width: 10px;
  margin: 0;
}}
QScrollBar::handle:vertical {{
  background: {b03};
  min-height: 24px;
  border-radius: 4px;
}}
QScrollBar:horizontal {{
  background: {b00};
  height: 10px;
  margin: 0;
}}
QScrollBar::handle:horizontal {{
  background: {b03};
  min-width: 24px;
  border-radius: 4px;
}}
QScrollBar::add-line, QScrollBar::sub-line {{
  width: 0;
  height: 0;
}}
QTabWidget::pane {{
  border: 1px solid {b02};
  background: {b00};
}}
QTabBar::tab {{
  background: {b01};
  color: {b04};
  padding: 6px 12px;
  border: 1px solid {b02};
}}
QTabBar::tab:selected {{
  background: {b00};
  color: {b05};
  border-bottom: 2px solid {b0d};
}}
QProgressBar {{
  background: {b01};
  border: 1px solid {b02};
  text-align: center;
  color: {b05};
}}
QProgressBar::chunk {{
  background: {b0d};
}}
QToolTip {{
  background-color: {b01};
  color: {b05};
  border: 1px solid {b0e};
}}
QSplitter::handle {{
  background: {b02};
}}
"#
    );

    let dest = qtpass_qss_path();
    write_replace(&dest, &body)?;
    eprintln!("dendritic-appearance: wrote {}", dest.display());
    Ok(dest)
}

pub fn apply_from_colors(colors_path: &Path) -> Result<(), String> {
    write_kdeglobals(colors_path)?;
    let _ = write_kvantum_colors(colors_path);
    write_qtpass_qss(colors_path)?;
    Ok(())
}
