use eframe::egui::{self, Rect, Rounding, Stroke, Vec2};
use xkbcommon::xkb;

#[derive(Debug, Clone)]
pub struct XkbKey {
    pub x: f32, pub y: f32, pub w: f32, pub h: f32,
    pub labels: Vec<String>,
}

#[derive(Debug)]
pub struct XkbLayout {
    pub keys: Vec<XkbKey>,
    pub width: f32, pub height: f32,
}

/// Boş bir klavye düzeni (layout derlenemediğinde gösterilir).
pub fn empty_layout() -> XkbLayout {
    XkbLayout { keys: vec![], width: 1.0, height: 1.0 }
}

/// ISO‑105 tuşlu klavye için XKB adı → (x, y, w, h) birim cinsinden.
/// x,y ondalıklı olabilir (geniş tuşlar için).
fn key_position(name: &str) -> Option<(f32, f32, f32, f32)> {
    // Satır y offset'leri (birim)
    let r = |row| row as f32;

    // Standart ISO‑105 düzeni. x değerleri kümülatif.
    match name {
        // ── (function row tamamen kaldırıldı) ──


        // ── Number row ─────────────────
        "TLDE" => Some((0.0,  r(1), 1.0, 1.0)),
        "AE01" => Some((1.0,  r(1), 1.0, 1.0)),
        "AE02" => Some((2.0,  r(1), 1.0, 1.0)),
        "AE03" => Some((3.0,  r(1), 1.0, 1.0)),
        "AE04" => Some((4.0,  r(1), 1.0, 1.0)),
        "AE05" => Some((5.0,  r(1), 1.0, 1.0)),
        "AE06" => Some((6.0,  r(1), 1.0, 1.0)),
        "AE07" => Some((7.0,  r(1), 1.0, 1.0)),
        "AE08" => Some((8.0,  r(1), 1.0, 1.0)),
        "AE09" => Some((9.0,  r(1), 1.0, 1.0)),
        "AE10" => Some((10.0, r(1), 1.0, 1.0)),
        "AE11" => Some((11.0, r(1), 1.0, 1.0)),
        "AE12" => Some((12.0, r(1), 1.0, 1.0)),
        "BKSP" => Some((13.0, r(1), 2.0, 1.0)),

        // ── Top alpha row (Q–P) ────────
        "TAB"  => Some((0.0,  r(2), 1.5, 1.0)),
        "AD01" => Some((1.5,  r(2), 1.0, 1.0)),
        "AD02" => Some((2.5,  r(2), 1.0, 1.0)),
        "AD03" => Some((3.5,  r(2), 1.0, 1.0)),
        "AD04" => Some((4.5,  r(2), 1.0, 1.0)),
        "AD05" => Some((5.5,  r(2), 1.0, 1.0)),
        "AD06" => Some((6.5,  r(2), 1.0, 1.0)),
        "AD07" => Some((7.5,  r(2), 1.0, 1.0)),
        "AD08" => Some((8.5,  r(2), 1.0, 1.0)),
        "AD09" => Some((9.5,  r(2), 1.0, 1.0)),
        "AD10" => Some((10.5, r(2), 1.0, 1.0)),
        "AD11" => Some((11.5, r(2), 1.0, 1.0)),
        "AD12" => Some((12.5, r(2), 1.0, 1.0)),
        "BKSL" => Some((13.5, r(2), 1.0, 1.0)), // ISO: solundaki tuş (\|)
        "RTRN" => Some((14.5, r(2), 1.25, 2.0)), // ISO Enter (2 satır)

        // ── Home row (A–L) ────────────
        "CAPS" => Some((0.0,  r(3), 1.75, 1.0)),
        "AC01" => Some((1.75, r(3), 1.0, 1.0)),
        "AC02" => Some((2.75, r(3), 1.0, 1.0)),
        "AC03" => Some((3.75, r(3), 1.0, 1.0)),
        "AC04" => Some((4.75, r(3), 1.0, 1.0)),
        "AC05" => Some((5.75, r(3), 1.0, 1.0)),
        "AC06" => Some((6.75, r(3), 1.0, 1.0)),
        "AC07" => Some((7.75, r(3), 1.0, 1.0)),
        "AC08" => Some((8.75, r(3), 1.0, 1.0)),
        "AC09" => Some((9.75, r(3), 1.0, 1.0)),
        "AC10" => Some((10.75,r(3), 1.0, 1.0)),
        "AC11" => Some((11.75,r(3), 1.0, 1.0)),
        "AC12" => Some((12.75,r(3), 1.0, 1.0)),

        // ── Bottom row (Z–M) ──────────
        "LFSH" => Some((0.0,  r(4), 1.25, 1.0)),
        "LSGT" => Some((1.25, r(4), 1.0, 1.0)), // ISO extra (< > |)
        "AB01" => Some((2.25, r(4), 1.0, 1.0)),
        "AB02" => Some((3.25, r(4), 1.0, 1.0)),
        "AB03" => Some((4.25, r(4), 1.0, 1.0)),
        "AB04" => Some((5.25, r(4), 1.0, 1.0)),
        "AB05" => Some((6.25, r(4), 1.0, 1.0)),
        "AB06" => Some((7.25, r(4), 1.0, 1.0)),
        "AB07" => Some((8.25, r(4), 1.0, 1.0)),
        "AB08" => Some((9.25, r(4), 1.0, 1.0)),
        "AB09" => Some((10.25,r(4), 1.0, 1.0)),
        "AB10" => Some((11.25,r(4), 1.0, 1.0)),
        "RTSH" => Some((12.25,r(4), 3.75, 1.0)),

        // ── Space bar row ─────────────
        "LCTL" => Some((0.0,  r(5), 1.25, 1.0)),
        "LWIN" => Some((1.25, r(5), 1.25, 1.0)),
        "LALT" => Some((2.5,  r(5), 1.5, 1.0)),
        "SPCE" => Some((4.0,  r(5), 6.25, 1.0)),
        "RALT" | "LVL3" => Some((10.25,r(5), 1.5, 1.0)),
        "COMP" => Some((11.75,r(5), 1.25, 1.0)),
        "RCTL" => Some((13.0, r(5), 1.25, 1.0)),

        // ── (nav cluster tamamen kaldırıldı) ──

        _ => None,
    }
}

fn keysym_to_label(sym: xkb::Keysym) -> String {
    let utf = xkb::keysym_to_utf8(sym);
    if utf.chars().any(|c| !c.is_control()) {
        let trimmed = utf.trim();
        if !trimmed.is_empty() {
            return trimmed.to_string();
        }
    }

    let name = xkb::keysym_get_name(sym);
    if name == "VoidSymbol" || name == "NoSymbol" {
        return String::new();
    }

    // Yaygın XKB sembol adlarını kısa etiketlere çevir
    match name.as_str() {
        "BackSpace" => "Bksp".into(),
        "Tab" => "Tab".into(),
        "Return" => "Enter".into(),
        "Caps_Lock" => "Caps".into(),
        "Shift_L" => "Shift".into(),
        "Shift_R" => "Shift".into(),
        "Control_L" => "Ctrl".into(),
        "Control_R" => "Ctrl".into(),
        "Alt_L" => "Alt".into(),
        "Alt_R" => "AltGr".into(),
        "ISO_Level3_Shift" => "AltGr".into(),
        "Super_L" => "Win".into(),
        "Super_R" => "Win".into(),
        "Menu" => "Menü".into(),
        "Escape" => "Esc".into(),
        "Delete" => "Del".into(),
        "Insert" => "Ins".into(),
        "Prior" => "PgUp".into(),
        "Next" => "PgDn".into(),
        "space" => "".into(),
        "Multi_key" => "Compose".into(),
        _ if name.starts_with("XF86") => String::new(),
        _ => name,
    }
}

/// XKB keymap'inden klavye düzenini oluşturur.
pub fn compile_layout(layout: &str, variant: &str) -> Option<XkbLayout> {
    let mut context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
    context.set_log_level(xkb::LogLevel::Critical);
    let model = if std::path::Path::new("/usr/share/X11/xkb/symbols/").exists() {
        "pc105"
    } else {
        "pc105"
    };

    let keymap = xkb::Keymap::new_from_names::<str>(
        &context,
        "",                                              // rules
        model,                                           // model
        layout,                                          // layout
        if variant.is_empty() { "" } else { variant },   // variant
        None::<String>,                                  // options
        xkb::COMPILE_NO_FLAGS,
    )?;

    let min = keymap.min_keycode();
    let max = keymap.max_keycode();
    let mut keys = Vec::new();
    let mut min_x = f32::MAX;
    let mut min_y = f32::MAX;
    let mut max_x = f32::MIN;
    let mut max_y = f32::MIN;
    let mut moved_comma = false;

    for code_u32 in (min.raw() as u32)..=(max.raw() as u32) {
        let code = xkb::Keycode::new(code_u32);
        let Some(name) = keymap.key_get_name(code) else { continue };
        let Some((x, y, w, h)) = key_position(name) else { continue };

        // Sembolleri al (base, shift, altgr, shift+altgr), boş olanları atla
        let mut raw_labels = Vec::new();
        for level in 0..4 {
            let syms = keymap.key_get_syms_by_level(code, 0, level);
            let label = syms.iter()
                .map(|&s| keysym_to_label(s))
                .collect::<Vec<_>>()
                .join("");
            if !label.is_empty() && !raw_labels.contains(&label) {
                raw_labels.push(label);
            }
        }

        // Her tuşta sadece 1 karakter göster (büyük harf tercihli)
        let mut labels: Vec<String> = {
            let single: Vec<_> = raw_labels.iter().filter(|l| l.chars().count() == 1).collect();
            if single.is_empty() {
                // Hiç tek karakter yoksa ilk label'ı göster (F1, Esc, …)
                raw_labels.into_iter().take(1).collect()
            } else {
                // Büyük harf varsa onu göster, yoksa ilk tek karakteri
                let uc = single.iter().find(|l| l.chars().next().map_or(false, |c| c.is_uppercase()));
                vec![if let Some(s) = uc { (*s).clone() } else { (*single[0]).clone() }]
            }
        };

        // , tuşu BKSL'deyse AC12'ye taşı (Türkçe Q düzeni için)
        if name == "BKSL" && labels.contains(&",".to_string()) {
            moved_comma = true;
            continue;
        }
        if name == "AC12" {
            labels = vec![",".to_string()];
        }

        keys.push(XkbKey { x, y, w, h, labels });

        if x < min_x { min_x = x; }
        if y < min_y { min_y = y; }
        if x + w > max_x { max_x = x + w; }
        if y + h > max_y { max_y = y + h; }
    }

    // AC12 keymap'te yoksa manuel ekle
    if moved_comma && !keys.iter().any(|k| (k.x - 12.75).abs() < 0.1 && (k.y - 3.0).abs() < 0.1) {
        keys.push(XkbKey { x: 12.75, y: 3.0, w: 1.0, h: 1.0, labels: vec![",".to_string()] });
    }

    // normalize x,y — tüm tuşlar (0,0) bazlı olsun
    for key in &mut keys {
        key.x -= min_x;
        key.y -= min_y;
    }

    Some(XkbLayout {
        keys,
        width: max_x - min_x,
        height: max_y - min_y,
    })
}

/// Klavyeyi egui ile çizer.
pub fn draw_layout(ui: &mut egui::Ui, layout: &XkbLayout, max_size: Vec2) {
    let margin = 6.0;
    let spacing = 0.08;
    let corner = 3.0;

    let uw = (max_size.x - margin * 2.0) / layout.width;
    let uh = (max_size.y - margin * 2.0) / layout.height;
    let unit = uw.min(uh).max(12.0);

    let draw_w = layout.width * unit;
    let draw_h = layout.height * unit;

    let (_id, resp) = ui.allocate_exact_size(Vec2::new(draw_w + margin * 2.0, draw_h + margin * 2.0), egui::Sense::hover());
    let painter = ui.painter_at(resp.rect);
    let origin = resp.rect.min;

    let visuals = ui.visuals();
    let key_fill = visuals.widgets.inactive.bg_fill;
    let key_stroke = visuals.widgets.noninteractive.bg_stroke;
    let text_color = egui::Color32::BLACK;
    let bg = visuals.window_fill();

    painter.rect_filled(resp.rect, Rounding::same(6.0), bg);

    let font_size = (unit * 0.28).max(6.0);
    let small_size = (unit * 0.22).max(5.0);

    let sp = unit * spacing;

    for key in &layout.keys {
        let kx = origin.x + margin + key.x * unit + sp;
        let ky = origin.y + margin + key.y * unit + sp;
        let kw = key.w * unit - sp * 2.0;
        let kh = key.h * unit - sp * 2.0;

        if kw <= 0.0 || kh <= 0.0 { continue; }

        let key_rect = Rect::from_min_size(egui::pos2(kx, ky), Vec2::new(kw, kh));
        painter.rect(key_rect, Rounding::same(corner), key_fill, Stroke::new(key_stroke.width.max(0.5), key_stroke.color));

        for (i, label) in key.labels.iter().enumerate() {
            let lbl = label.trim();
            if lbl.is_empty() { continue; }
            let (lx, ly, sz) = match i {
                0 => (kx + kw * 0.5, ky + kh * 0.5, font_size),
                1 => (kx + kw * 0.5, ky + kh * 0.75, small_size),
                _ => (kx + kw * 0.5, ky + kh * 0.9, small_size),
            };
            painter.text(
                egui::pos2(lx, ly), egui::Align2::CENTER_CENTER,
                lbl, egui::FontId::proportional(sz), text_color,
            );
        }
    }
}
