//! Disk bölümleme adımı — Otomatik ve Manuel mod destekli.

use eframe::egui;
use rust_i18n::t;
use crate::ui::theme;
use crate::funct::form_label;
// sysinfo::Disks mount point başına bir kayıt döndürür (partition'lar),
// ham disk listesi için lsblk kullanıyoruz.

// ─────────────────────────────────────────────
// Mevcut disk bölümlerini oku
// ─────────────────────────────────────────────

/// Verilen diskin (`/dev/sda`, `/dev/nvme0n1` vb.) mevcut bölümlerini
/// `lsblk` aracılığıyla okur ve `CustomPartition` listesi olarak döndürür.
///
/// Hem SATA/virtio tipi (`sda` → `sda1`, `sda2`) hem de NVMe tipi
/// (`nvme0n1` → `nvme0n1p1`, `nvme0n1p2`) aygıtları desteklenir.
/// Manuel bölümleme modunda disk seçildiğinde çağrılır; böylece kullanıcı
/// diskin mevcut bölüm düzenini görebilir.
fn read_existing_partitions(disk_path: &str) -> Vec<crate::installer::CustomPartition> {
    use crate::installer::{CustomPartition, FsType};

    let dev_name = disk_path.trim_start_matches("/dev/");

    let out = std::process::Command::new("lsblk")
        .args([
            "-o", "NAME,SIZE,FSTYPE,MOUNTPOINT",
            "-b", "--noheadings", "-l",
            disk_path,
        ])
        .output();

    let mut parts = Vec::new();

    if let Ok(o) = out {
        if o.status.success() {
            let text = String::from_utf8_lossy(&o.stdout);
            for line in text.lines() {
                let mut tokens = line.split_whitespace();

                let name = match tokens.next() { Some(n) => n, None => continue };

                // Diskin kendisini (örn. "sda") atla — yalnızca bölümleri al
                if name == dev_name { continue; }

                // Bu diske ait olmayan girişleri atla
                // SATA: sda1, sda2 …   NVMe: nvme0n1p1, nvme0n1p2 …
                if !name.starts_with(dev_name) { continue; }

                let size_bytes: u64 = tokens.next().unwrap_or("0").parse().unwrap_or(0);
                let size_mb = size_bytes / (1024 * 1024);

                let fstype_str = tokens.next().unwrap_or("");
                let fstype = match fstype_str {
                    "ext4"  => FsType::Ext4,
                    "ext3"  => FsType::Ext3,
                    "btrfs" => FsType::Btrfs,
                    "xfs"   => FsType::Xfs,
                    "vfat"  => FsType::Fat32,
                    "ntfs"  => FsType::Ntfs,
                    "swap"  => FsType::Swap,
                    _       => FsType::Ext4, // bilinmeyen → varsayılan
                };

                // lsblk mount point alanı boşsa sonraki token gelmez; unwrap_or ile güvenli al
                let mountpoint = tokens.next().unwrap_or("").to_string();

                parts.push(CustomPartition {
                    device:     format!("/dev/{}", name),
                    size_mb,
                    fstype,
                    mountpoint,
                    encrypt: false,
                    luks_password: String::new(),
                    luks_name: String::new(),
                    skip_format: true,
                });
            }
        }
    }

    parts
}

/// `/sys/block` altındaki gerçek blok aygıtlarını (partition değil) listeler.
/// Aygıt adına (`sda`, `nvme0n1`) bakarak türünü belirler.
fn detect_drive_type(name: &str) -> String {
    if name.starts_with("nvme") {
        return "NVMe SSD".into();
    }
    if name.starts_with("mmcblk") {
        return "MMC/SD".into();
    }
    // removable ortam (USB flash bellek)
    let removable_path = format!("/sys/block/{}/removable", name);
    if let Ok(val) = std::fs::read_to_string(&removable_path) {
        if val.trim() == "1" {
            return "USB".into();
        }
    }
    // döner disk mi? (rotational=1 → HDD, 0 → SSD)
    let rotational_path = format!("/sys/block/{}/queue/rotational", name);
    if let Ok(val) = std::fs::read_to_string(&rotational_path) {
        if val.trim() == "0" {
            return "SSD".into();
        }
    }
    "HDD".into()
}

/// lsblk'dan gelen çıktı akıllıca ayrıştırılır; başarısız olursa /sys/block fallback devreye girer.
pub fn list_block_devices() -> Vec<crate::installer::DiskInfo> {
    // Önce -P (key=value pairs) ile dene, boşluklu MODEL/VENDOR güvenli
    let out = std::process::Command::new("lsblk")
        .args(["-d", "-o", "NAME,SIZE,MODEL,VENDOR", "-b", "--noheadings", "-P"])
        .output();

    let mut disks = Vec::new();

    if let Ok(o) = out {
        if o.status.success() {
            let text = String::from_utf8_lossy(&o.stdout);
            for line in text.lines() {
                // NAME="sda" SIZE="42949672960" MODEL="VBOX HARDDISK" VENDOR="ATA"
                let mut name_raw = String::new();
                let mut vendor  = String::new();
                let mut model   = String::new();
                let mut size    = 0u64;

                for pair in line.split_ascii_whitespace() {
                    let mut parts = pair.splitn(2, '=');
                    let key = parts.next().unwrap_or("");
                    let val = parts.next().unwrap_or("").trim_matches('"');
                    match key {
                        "NAME"  => name_raw = val.to_string(),
                        "SIZE"  => size = val.parse().unwrap_or(0),
                        "VENDOR"=> vendor = val.to_string(),
                        "MODEL" => model = val.to_string(),
                        _ => {}
                    }
                }

                if name_raw.is_empty() || size == 0 { continue; }

                if name_raw.starts_with("loop")
                    || name_raw.starts_with("ram")
                    || name_raw.starts_with("sr")
                    || name_raw.starts_with("zram")
                { continue; }

                disks.push(crate::installer::DiskInfo {
                    name:       format!("/dev/{}", name_raw),
                    vendor,
                    model,
                    drive_type: detect_drive_type(&name_raw),
                    size_gb:    size / 1_073_741_824,
                    size_bytes: size,
                });
            }
        }
    }

    // lsblk başarısız olduysa /sys/block fallback
    if disks.is_empty() {
        if let Ok(rd) = std::fs::read_dir("/sys/block") {
            for entry in rd.flatten() {
                let name = entry.file_name().to_string_lossy().to_string();
                
                if name.starts_with("loop") 
                    || name.starts_with("ram")
                    || name.starts_with("sr")
                    || name.starts_with("zram")
                { continue; }

                let size_path = format!("/sys/block/{}/size", name);
                let size_sectors: u64 = std::fs::read_to_string(&size_path)
                    .unwrap_or_default().trim().parse().unwrap_or(0);
                let size_bytes = size_sectors * 512;
                if size_bytes == 0 { continue; }

                let vendor_path = format!("/sys/block/{}/device/vendor", name);
                let vendor = std::fs::read_to_string(&vendor_path)
                    .unwrap_or_default().trim().to_string();

                let model_path = format!("/sys/block/{}/device/model", name);
                let model = std::fs::read_to_string(&model_path)
                    .unwrap_or_default().trim().to_string();

                disks.push(crate::installer::DiskInfo {
                    name: format!("/dev/{}", name),
                    vendor,
                    model,
                    drive_type: detect_drive_type(&name),
                    size_gb: size_bytes / 1_073_741_824,
                    size_bytes,
                });
            }
        }
    }

    disks
}

use crate::installer::{
    CustomPartition, DiskInfo, FsType, GlobalState, InstallerStep,
    PartitionPlan, PartitionTableType, VolumeGroup,
};

const MIN_DISK_GB: u64 = 10;
const EFI_MB: u64     = 300;
const SWAP_MB_MIN: u64 = 512;
const SWAP_MB_MAX: u64 = 8 * 1024;

const COMMON_MOUNTPOINTS: &[&str] = &["/", "/boot", "/boot/efi", "/home", "/var", "/tmp", "swap"];

// ─────────────────────────────────────────────
// Manuel bölümleme için yerel durum
// ─────────────────────────────────────────────

#[derive(Default)]
struct ManualState {
    /// "Bölüm Ekle" diyaloğu açık mı?
    adding: bool,
    /// "Bölüm Düzenle" diyaloğı açık mı?
    editing: bool,
    /// Düzenlenecek bölüm indeksi
    edit_idx: Option<usize>,
    /// Seçili satır indeksi
    selected_idx: Option<usize>,
    /// Diyalog: seçili dosya sistemi
    add_fstype: usize,   // FsType listesindeki indeks
    /// Diyalog: boyut alanı (MB, metin girişi)
    add_size_str: String,
    /// Diyalog: bağlama noktası
    add_mountpoint: String,
    /// Diyalog: LUKS şifrele
    add_encrypt: bool,
    /// Diyalog: LUKS parola
    add_luks_password: String,
    /// Silinmek istenen bölüm indeksi (onay isteği)
    delete_idx: Option<usize>,
    /// Genel hata mesajı
    error: Option<String>,
    /// Biçimlendirme atlansın mı?
    add_skip_format: bool,
    /// Yeni VG adı (LVM)
    add_vg_name: String,

    // ── LVM Logical Volume Ekleme State'leri ───────────────────
    adding_lv: bool,
    add_lv_name: String,
    add_lv_vg_idx: usize,
    add_lv_size_str: String,
    add_lv_fstype: usize,
    add_lv_mountpoint: String,
}

const FS_OPTIONS: &[(&str, FsType)] = &[
    ("ext4",        FsType::Ext4),
    ("ext3",        FsType::Ext3),
    ("btrfs",       FsType::Btrfs),
    ("xfs",         FsType::Xfs),
    ("FAT32 (EFI)", FsType::Fat32),
    ("NTFS",        FsType::Ntfs),
    ("swap",        FsType::Swap),
    ("LVM PV",      FsType::Lvm),
];

// ─────────────────────────────────────────────
// PartitionStep
// ─────────────────────────────────────────────

pub struct PartitionStep {
    scanned: bool,
    is_uefi: bool,
    manual: ManualState,
    show_luks_password: bool,
    selected_disk_size_mb: Option<u64>,
}

impl Default for PartitionStep {
    fn default() -> Self {
        Self {
            scanned: false,
            is_uefi: std::path::Path::new("/sys/firmware/efi").exists(),
            manual: ManualState::default(),
            show_luks_password: false,
            selected_disk_size_mb: None,
        }
    }
}

/// RAM miktarına göre önerilen swap alanı (MB).
fn recommended_swap_mb() -> u64 {
    use sysinfo::System;
    let mut sys = System::new();
    sys.refresh_memory();
    let ram_mb = sys.total_memory() / 1_048_576;
    let swap = if ram_mb <= 2048 {
        ram_mb
    } else if ram_mb <= 8192 {
        ram_mb / 2
    } else {
        4096
    };
    swap.clamp(SWAP_MB_MIN, SWAP_MB_MAX)
}

/// Seçili disk için otomatik bölümleme planı hesapla.
fn make_plan(disk: &DiskInfo, is_uefi: bool) -> Option<PartitionPlan> {
    if disk.size_gb < MIN_DISK_GB {
        return None;
    }
    let total_mb = disk.size_bytes / 1_048_576;
    let efi_mb   = if is_uefi { EFI_MB } else { 0 };
    let swap_mb  = recommended_swap_mb();
    let overhead = efi_mb + swap_mb + 512;
    let root_mb  = total_mb.saturating_sub(overhead);
    if root_mb < 6144 { return None; }
    Some(PartitionPlan {
        disk: disk.name.clone(),
        table_type: if is_uefi { PartitionTableType::Gpt } else { PartitionTableType::Mbr },
        efi_mb,
        swap_mb,
        root_mb,
        encrypt_root: false,
        luks_password: String::new(),
    })
}

/// Manuel listedeki bölümlerin geçerliliğini kontrol eder.
fn validate_manual(
    parts: &[CustomPartition],
    lvs: &[crate::installer::LogicalVolume],
    is_uefi: bool,
) -> Option<String> {
    let has_root = parts.iter().any(|p| p.mountpoint == "/")
        || lvs.iter().any(|lv| lv.mountpoint == "/");
    let has_efi  = parts.iter().any(|p| p.mountpoint == "/boot/efi" || p.fstype == FsType::Fat32);

    if !has_root {
        return Some(t!("mp_no_root").to_string());
    }
    if is_uefi && !has_efi {
        return Some(t!("mp_no_efi").to_string());
    }
    None
}

impl InstallerStep for PartitionStep {
    fn name(&self) -> String { t!("partition").to_string() }

    fn on_enter(&mut self, state: &mut GlobalState) {
        if !self.scanned {
            state.available_disks = list_block_devices();
            state.available_disks.retain(|d| d.size_gb >= 4);
            self.scanned = true;
        }
    }

    fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
        ui.heading(t!("partition_title"));
        ui.label(t!("partition_description"));
        ui.add_space(10.0);

        if state.available_disks.is_empty() {
            ui.colored_label(egui::Color32::RED, t!("no_disks_found"));
            if ui.button(t!("rescan_disks")).clicked() {
                self.scanned = false;
                self.on_enter(state);
            }
            return;
        }

        // ── Mod seçimi ─────────────────────────────────────────
        ui.horizontal(|ui| {
            if state.erase_disk {
                let _ = theme::primary_button(ui, &t!("erase_disk_label"));
                if theme::secondary_button(ui, &t!("manual_partition_label")).clicked() {
                    state.erase_disk = false;
                }
            } else {
                if theme::secondary_button(ui, &t!("erase_disk_label")).clicked() {
                    state.erase_disk = true;
                }
                let _ = theme::primary_button(ui, &t!("manual_partition_label"));
            }
        });
        ui.add_space(10.0);

        if state.erase_disk {
            self.show_auto_mode(ui, state);
        } else {
            self.show_manual_mode(ui, state);
        }
    }

    fn is_complete(&self, state: &GlobalState) -> bool {
        if state.erase_disk {
            state.partition_plan.is_some()
        } else {
            !state.custom_partitions.is_empty()
                && validate_manual(&state.custom_partitions, &state.logical_volumes, self.is_uefi).is_none()
        }
    }
}

// ─────────────────────────────────────────────
// Otomatik mod
// ─────────────────────────────────────────────

impl PartitionStep {
    fn show_auto_mode(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
        ui.group(|ui| {
            ui.label(t!("select_disk_label"));
            ui.add_space(8.0);
            let disks = state.available_disks.clone();
            let kart_genislik = 180.0;
            let kart_yukseklik = 160.0;

            egui::Grid::new("disk_grid")
                .min_col_width(kart_genislik + 12.0)
                .spacing([12.0, 12.0])
                .show(ui, |ui| {
                    for (i, disk) in disks.iter().enumerate() {
                        let too_small = disk.size_gb < MIN_DISK_GB;
                        let selected = state.selected_disk.as_deref() == Some(&disk.name);

                        let (rect, response) = ui.allocate_exact_size(
                            egui::vec2(kart_genislik, kart_yukseklik),
                            egui::Sense::click(),
                        );
                        let child_ui = &mut ui.child_ui(rect, egui::Layout::top_down(egui::Align::Center));

                        // arka plan
                        egui::Frame::none()
                            .fill(if selected {
                                egui::Color32::from_rgba_unmultiplied(237, 237, 224, 1)
                            } else if response.hovered() {
                                egui::Color32::from_rgba_unmultiplied(60, 60, 80, 180)
                            } else {
                                egui::Color32::from_rgba_unmultiplied(237, 237, 224, 1)
                            })
                            .stroke(egui::Stroke::new(
                                if selected { 2.0_f32 } else { 1.0_f32 },
                                if selected { crate::ui::theme::c_accent() } else { crate::ui::theme::c_border() },
                            ))
                            .rounding(egui::Rounding::same(8.0))
                            .inner_margin(egui::Margin::same(8.0))
                            .show(child_ui, |ui| {
                                ui.set_min_size(egui::vec2(kart_genislik - 16.0, kart_yukseklik - 16.0));
                                ui.add_space(8.0);
                                ui.add(
                                    egui::Image::new(egui::include_image!("../../assets/disk.png"))
                                        .max_width(64.0)
                                        .max_height(64.0)
                                        .rounding(egui::Rounding::same(6.0))
                                        .tint(if too_small {
                                            egui::Color32::from_gray(80)
                                        } else {
                                            egui::Color32::WHITE
                                        }),
                                );
                                ui.add_space(6.0);
                                let marka = if disk.vendor.is_empty() {
                                    &disk.model
                                } else {
                                    &disk.vendor
                                };
                                ui.label(
                                    egui::RichText::new(format!("{} GB", disk.size_gb))
                                        .size(14.0)
                                        .strong()
                                        .color(crate::ui::theme::c_text()),
                                );
                                ui.label(
                                    egui::RichText::new(marka)
                                        .size(11.0)
                                        .color(crate::ui::theme::c_text_dim()),
                                );
                                if too_small {
                                    ui.colored_label(
                                        crate::ui::theme::c_error(),
                                        t!("disk_too_small"),
                                    );
                                }
                            });

                        if response.clicked() && !too_small {
                            state.selected_disk = Some(disk.name.clone());
                            self.selected_disk_size_mb = Some(disk.size_bytes / 1_048_576);
                            eprintln!("DEBUG AUTO DISK SELECT: disk={} size_bytes={} size_mb={}", disk.name, disk.size_bytes, disk.size_bytes / 1_048_576);
                            state.partition_plan = make_plan(disk, self.is_uefi);
                        }

                        if (i + 1) % 3 == 0 {
                            ui.end_row();
                        }
                    }
                });
        });

        if let Some(ref plan) = state.partition_plan {
            ui.add_space(12.0);
            ui.separator();
            ui.add_space(8.0);
            ui.label(egui::RichText::new(t!("partition_plan_title")).strong().color(crate::ui::theme::c_text()));
            ui.add_space(6.0);
            partition_bar(ui, plan);
            ui.add_space(8.0);

            // Bootstrap 5 tarzı çizgili tablo
            let col_widths = [0.40, 0.25, 0.35];
            let header_color = egui::Color32::from_rgb(33, 37, 41);
            let header_text = egui::Color32::WHITE;
            let baslik_yukseklik = 36.0;
            let satir_yukseklik = 34.0;
            let headers = [t!("plan_col_part"), t!("plan_col_fs"), t!("plan_col_size")];

            struct Satir {
                part: String,
                fs: &'static str,
                size: String,
            }
            let mut satirlar = Vec::new();
            if plan.efi_mb > 0 {
                satirlar.push(Satir {
                    part: format!("{}1  (EFI)", plan.disk),
                    fs: "FAT32",
                    size: format!("{} MB", plan.efi_mb),
                });
            }
            let swap_part = if plan.efi_mb > 0 { 2 } else { 1 };
            satirlar.push(Satir {
                part: format!("{}{}  (swap)", plan.disk, swap_part),
                fs: "swap",
                size: format!("{} MB", plan.swap_mb),
            });
            let root_part = swap_part + 1;
            satirlar.push(Satir {
                part: format!("{}{}{}", plan.disk, root_part, t!("plan_root_suffix")),
                fs: "ext4",
                size: format!("{:.1} GB", plan.root_mb as f64 / 1024.0),
            });

            egui::Frame::none()
                .stroke(egui::Stroke::new(1.0_f32, crate::ui::theme::c_border()))
                .rounding(egui::Rounding::same(6.0))
                .show(ui, |ui| {
                    let tam = ui.available_width();

                    ui.horizontal(|ui| {
                        ui.set_height(baslik_yukseklik);
                        ui.spacing_mut().item_spacing.x = 0.0;
                        for (j, h) in headers.iter().enumerate() {
                            let w = tam * col_widths[j];
                            let (rect, _) = ui.allocate_exact_size(
                                egui::vec2(w, baslik_yukseklik),
                                egui::Sense::hover(),
                            );
                            let mut cell_ui = ui.child_ui(rect, egui::Layout::top_down(egui::Align::Center));
                            egui::Frame::none()
                                .fill(header_color)
                                .inner_margin(egui::Margin::symmetric(10.0, 6.0))
                                .show(&mut cell_ui, |ui| {
                                    ui.vertical_centered(|ui| {
                                        ui.label(egui::RichText::new(h.as_ref()).strong().color(header_text).size(14.0));
                                    });
                                });
                        }
                    });

                    for (row_idx, satir) in satirlar.iter().enumerate() {
                        let row_bg = if row_idx % 2 == 0 {
                            egui::Color32::from_rgba_unmultiplied(60, 60, 80, 40)
                        } else {
                            egui::Color32::TRANSPARENT
                        };
                        let hucreler: [&str; 3] = [&satir.part, satir.fs, &satir.size];
                        ui.horizontal(|ui| {
                            ui.set_height(satir_yukseklik);
                            ui.spacing_mut().item_spacing.x = 0.0;
                            for (j, deger) in hucreler.iter().enumerate() {
                                let w = tam * col_widths[j];
                                let (rect, _) = ui.allocate_exact_size(
                                    egui::vec2(w, satir_yukseklik),
                                    egui::Sense::hover(),
                                );
                                let mut cell_ui = ui.child_ui(rect, egui::Layout::top_down(egui::Align::Center));
                                egui::Frame::none()
                                    .fill(row_bg)
                                    .inner_margin(egui::Margin::symmetric(10.0, 4.0))
                                    .show(&mut cell_ui, |ui| {
                                        ui.vertical_centered(|ui| {
                                            ui.label(egui::RichText::new(*deger).size(13.0).color(crate::ui::theme::c_text()));
                                        });
                                    });
                            }
                        });
                    }
                });

            ui.add_space(8.0);
            ui.label(format!("{}: {}", t!("partition_table_type"), plan.table_type));

            // ── LUKS şifreleme ─────────────────────────────────────
            ui.add_space(12.0);
            ui.separator();
            ui.add_space(8.0);
            let plan = state.partition_plan.as_mut().unwrap();
            ui.checkbox(&mut plan.encrypt_root, t!("luks_enable_root"));
            if plan.encrypt_root {
                ui.horizontal(|ui| {
                    ui.label(t!("luks_password"));
                    if self.show_luks_password {
                        ui.text_edit_singleline(&mut plan.luks_password);
                    } else {
                        ui.add(egui::TextEdit::singleline(&mut plan.luks_password).password(true));
                    }
                    let eye = if self.show_luks_password { "\u{ECB5}" } else { "\u{ECB7}" };
                    if ui.small_button(eye).clicked() {
                        self.show_luks_password = !self.show_luks_password;
                    }
                });
                if plan.luks_password.len() < 4 && !plan.luks_password.is_empty() {
                    ui.colored_label(egui::Color32::YELLOW, t!("luks_password_weak"));
                }
            }

            ui.add_space(10.0);
            egui::Frame::none()
                .fill(egui::Color32::from_rgba_unmultiplied(200, 60, 40, 25))
                .rounding(5.0)
                .inner_margin(egui::Margin::same(8.0))
                .show(ui, |ui| {
                    ui.colored_label(
                        egui::Color32::from_rgb(210, 80, 60),
                        format!("⚠  {}: {}", t!("erase_warning"), plan.disk),
                    );
                });
        }
    }
}

// ─────────────────────────────────────────────
// Manuel mod
// ─────────────────────────────────────────────

impl PartitionStep {
    fn show_manual_mode(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
        let kart_genislik = 180.0;
        let kart_yukseklik = 160.0;

        // ── Disk seçimi (hedef disk) ────────────────────────────
        ui.group(|ui| {
            ui.label(t!("select_disk_label"));
            ui.add_space(8.0);
            let disks = state.available_disks.clone();

            egui::Grid::new("manual_disk_grid")
                .min_col_width(kart_genislik + 12.0)
                .spacing([12.0, 12.0])
                .show(ui, |ui| {
                    for (i, disk) in disks.iter().enumerate() {
                        let selected = state.selected_disk.as_deref() == Some(&disk.name);

                        let (rect, response) = ui.allocate_exact_size(
                            egui::vec2(kart_genislik, kart_yukseklik),
                            egui::Sense::click(),
                        );
                        let child_ui = &mut ui.child_ui(rect, egui::Layout::top_down(egui::Align::Center));

                        egui::Frame::none()
                            .fill(if selected {
                                egui::Color32::from_rgba_unmultiplied(237, 237, 224, 1)
                            } else if response.hovered() {
                                egui::Color32::from_rgba_unmultiplied(60, 60, 80, 180)
                            } else {
                                egui::Color32::from_rgba_unmultiplied(237, 237, 224, 1)
                            })
                            .stroke(egui::Stroke::new(
                                if selected { 2.0_f32 } else { 1.0_f32 },
                                if selected { crate::ui::theme::c_accent() } else { crate::ui::theme::c_border() },
                            ))
                            .rounding(egui::Rounding::same(8.0))
                            .inner_margin(egui::Margin::same(8.0))
                            .show(child_ui, |ui| {
                                ui.set_min_size(egui::vec2(kart_genislik - 16.0, kart_yukseklik - 16.0));
                                ui.add_space(8.0);
                                ui.add(
                                    egui::Image::new(egui::include_image!("../../assets/disk.png"))
                                        .max_width(64.0)
                                        .max_height(64.0)
                                        .rounding(egui::Rounding::same(6.0)),
                                );
                                ui.add_space(6.0);
                                let marka = if disk.vendor.is_empty() {
                                    &disk.model
                                } else {
                                    &disk.vendor
                                };

                                ui.label(
                                    egui::RichText::new(marka)
                                        .size(11.0)
                                        .color(crate::ui::theme::c_text_dim()),
                                );

                                ui.label(
                                    egui::RichText::new(format!("{} GB", disk.size_gb))
                                        .size(14.0)
                                        .strong()
                                        .color(crate::ui::theme::c_text()),
                                );

                            });

                        if response.clicked() {
                            state.selected_disk = Some(disk.name.clone());
                            self.selected_disk_size_mb = Some(disk.size_bytes / 1_048_576);
                            eprintln!("DEBUG DISK SELECT: disk={} size_bytes={} size_mb={}", disk.name, disk.size_bytes, disk.size_bytes / 1_048_576);
                            state.custom_partitions = read_existing_partitions(&disk.name);
                            self.manual.error = None;
                        }

                        if (i + 1) % 3 == 0 {
                            ui.end_row();
                        }
                    }
                });
        });

        ui.add_space(8.0);

        let disk = match &state.selected_disk {
            Some(d) => d.clone(),
            None => {
                ui.label(t!("mp_select_disk_first"));
                return;
            }
        };
        let max_mb = self.selected_disk_size_mb.unwrap_or(256 * 1024) as f64;
        eprintln!("DEBUG MAX_MB: selected_disk_size_mb={:?} max_mb={}", self.selected_disk_size_mb, max_mb);

        // ── Mevcut bölüm listesi tablosu ───────────────────────
        ui.label(egui::RichText::new(t!("mp_plan_title")).strong().color(crate::ui::theme::c_text()));
        ui.add_space(6.0);

        let delete_idx: Option<usize> = None;

        let col_widths = [0.25, 0.12, 0.16, 0.24, 0.23];
        let tam_genislik = ui.available_width();
        let header_color = egui::Color32::from_rgb(33, 37, 41);
        let header_text = egui::Color32::WHITE;
        let _border_stroke = egui::Stroke::new(1.0_f32, crate::ui::theme::c_border());

        // ── Başlık satırı ─────────────────────────────────
        let headers: [String; 5] = [
            t!("mp_device").to_string(),
            t!("mp_size").to_string(),
            t!("mp_fstype").to_string(),
            t!("mp_mountpoint").to_string(),
            t!("mp_format_status").to_string(),
        ];
        ui.horizontal(|ui| {
            ui.set_height(30.0);
            ui.spacing_mut().item_spacing.x = 0.0;
            for (j, h) in headers.into_iter().enumerate() {
                let (rect, _) = ui.allocate_exact_size(
                    egui::vec2(tam_genislik * col_widths[j], 30.0),
                    egui::Sense::hover(),
                );
                let child_ui = &mut ui.child_ui(rect, egui::Layout::top_down(egui::Align::Center));
                egui::Frame::none()
                    .fill(header_color)
                    .stroke(egui::Stroke::new(1.0_f32, header_color))
                    .inner_margin(egui::Margin::symmetric(8.0, 4.0))
                    .show(child_ui, |ui| {
                        ui.label(egui::RichText::new(h).strong().color(header_text).size(13.0));
                    });
            }
        });

        // ── Veri satırları ────────────────────────────────
        for (row_idx, part) in state.custom_partitions.iter().enumerate() {
            let is_selected = self.manual.selected_idx == Some(row_idx);
            let row_bg = if is_selected {
                egui::Color32::from_rgba_unmultiplied(80, 100, 180, 80)
            } else if row_idx % 2 == 0 {
                egui::Color32::from_rgba_unmultiplied(60, 60, 80, 60)
            } else {
                egui::Color32::TRANSPARENT
            };

            let size_str = if part.size_mb == 0 {
                t!("mp_size_remaining").to_string()
            } else if part.size_mb >= 1024 {
                format!("{:.1} GB", part.size_mb as f64 / 1024.0)
            } else {
                format!("{} MB", part.size_mb)
            };

            let mut fstype_label = part.fstype.label().to_string();
            if part.encrypt {
                fstype_label = format!("🔐 {}", fstype_label);
            }

            // Entire row as a single clickable target (painter-based, no widget nesting)
            let (row_rect, row_response) = ui.allocate_exact_size(
                egui::vec2(tam_genislik, 34.0),
                egui::Sense::click(),
            );

            if row_response.clicked() {
                self.manual.selected_idx = Some(row_idx);
            }
            row_response.on_hover_cursor(egui::CursorIcon::PointingHand);

            // Paint row background
            let painter = ui.painter();
            painter.rect_filled(row_rect, egui::Rounding::ZERO, row_bg);

            // Paint cell texts directly (no child_ui/label widgets that steal clicks)
            let cell_texts = [
                part.device.as_str(),
                size_str.as_str(),
                fstype_label.as_str(),
                part.mountpoint.as_str(),
            ];
            let mut x = row_rect.left();
            for (j, text) in cell_texts.iter().enumerate() {
                let cell_w = tam_genislik * col_widths[j];
                let text_rect = egui::Rect::from_min_size(
                    egui::pos2(x + 8.0, row_rect.top() + 4.0),
                    egui::vec2(cell_w - 16.0, 26.0),
                );
                painter.text(
                    text_rect.center(),
                    egui::Align2::CENTER_CENTER,
                    *text,
                    egui::FontId::proportional(13.0),
                    crate::ui::theme::c_text(),
                );
                x += cell_w;
            }

            // Format sütunu: ikon karakteri (konumlandırılmış)
            let icon_cell_w = tam_genislik * col_widths[4];
            let icon_rect = egui::Rect::from_min_size(
                egui::pos2(x + (icon_cell_w - 20.0) / 2.0, row_rect.top() + (34.0 - 20.0) / 2.0),
                egui::vec2(20.0, 20.0),
            );
            if part.skip_format {
                // lock ikonu
                ui.put(icon_rect, egui::Label::new(
                    egui::RichText::new("\u{EECD}")
                        .color(egui::Color32::from_rgb(180, 60, 40))
                        .size(18.0)
                ));
            } else {
                // check ikonu
                ui.put(icon_rect, egui::Label::new(
                    egui::RichText::new("\u{EB7B}")
                        .color(egui::Color32::from_rgb(255, 251, 0))
                        .size(18.0)
                ));
            };

            if row_idx < state.custom_partitions.len() - 1 {
                ui.separator();
            }
        }

        // ── Bölümleme Planı (manuel) ──────────────────────────
        if !state.custom_partitions.is_empty() {
            ui.add_space(12.0);
            ui.separator();
            ui.add_space(8.0);
            ui.label(egui::RichText::new(t!("partition_plan_title")).strong().color(crate::ui::theme::c_text()));
            ui.add_space(6.0);
            manual_partition_bar(ui, &state.custom_partitions);
        }

        // Silme onayı
        if let Some(idx) = delete_idx {
            self.manual.delete_idx = Some(idx);
        }
        if let Some(idx) = self.manual.delete_idx {
            let dev = state.custom_partitions.get(idx)
                .map(|p| p.device.clone())
                .unwrap_or_default();
            egui::Window::new(t!("mp_delete_confirm_title"))
                .collapsible(false)
                .resizable(false)
                .anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
                .show(ui.ctx(), |ui| {
                    ui.label(t!("mp_confirm_delete", dev = dev));
                    ui.add_space(8.0);
                    ui.horizontal(|ui| {
                        if theme::danger_button(ui, &t!("mp_delete_confirm_yes")).clicked() {
                            if idx < state.custom_partitions.len() {
                                state.custom_partitions.remove(idx);
                            }
                            self.manual.delete_idx = None;
                            self.manual.selected_idx = None;
                        }
                        if theme::secondary_button(ui, &t!("cancel")).clicked() {
                            self.manual.delete_idx = None;
                        }
                    });
                });
        }

        ui.add_space(8.0);

        // ── Butonlar: Yeni Bölüm / Düzenle / Sil ───────────
        ui.horizontal(|ui| {
            let has_selection = self.manual.selected_idx.is_some();
            let selected = self.manual.selected_idx
                .and_then(|i| state.custom_partitions.get(i));

            // Yeni Bölüm
            if theme::primary_button(ui, &format!("\u{EA13} {}", t!("mp_new_partition"))).clicked() {
                self.manual.adding = true;
                self.manual.editing = false;
                self.manual.edit_idx = None;
                let next_num = state.custom_partitions.len() + 1;
                self.manual.add_mountpoint.clear();
                self.manual.add_encrypt = false;
                self.manual.add_luks_password.clear();
                self.manual.add_mountpoint = match next_num {
                    1 if self.is_uefi => "/boot/efi".to_string(),
                    1 => "/".to_string(),
                    2 if self.is_uefi => "swap".to_string(),
                    2 => "swap".to_string(),
                    3 => "/".to_string(),
                    _ => String::new(),
                };
                // Mountpoint'e göre otomatik boyut ata
                self.manual.add_size_str = match self.manual.add_mountpoint.as_str() {
                    "/boot/efi" => "1024".to_string(), // 1GB
                    "swap" => "1024".to_string(), // Sabit 1GB
                    "/" => "remaining".to_string(), // Geri kalan alan
                    _ => String::new(),
                };
                self.manual.add_fstype = match self.manual.add_mountpoint.as_str() {
                    "swap" => FS_OPTIONS.iter().position(|(_, t)| *t == FsType::Swap).unwrap_or(0),
                    "/boot/efi" => FS_OPTIONS.iter().position(|(_, t)| *t == FsType::Fat32).unwrap_or(0),
                    _ => 0,
                };
                // Yeni bölümler varsayılan olarak biçimlendirilir
                self.manual.add_skip_format = false;
            }

            // Düzenle
            ui.add_enabled_ui(has_selection, |ui| {
                if theme::secondary_button(ui, &format!("\u{EFE0} {}", t!("mp_edit_partition"))).clicked() {
                    if let Some(part) = selected {
                        self.manual.editing = true;
                        self.manual.adding = false;
                        self.manual.edit_idx = self.manual.selected_idx;
                        self.manual.add_size_str = if part.size_mb == 0 {
                            String::new()
                        } else {
                            part.size_mb.to_string()
                        };
                        self.manual.add_mountpoint = part.mountpoint.clone();
                        self.manual.add_fstype = FS_OPTIONS.iter()
                            .position(|(_, ft)| *ft == part.fstype)
                            .unwrap_or(0);
                        self.manual.add_encrypt = part.encrypt;
                        self.manual.add_luks_password = part.luks_password.clone();
                        self.manual.add_skip_format = part.skip_format;
                    }
                }
            });

            // Sil
            ui.add_enabled_ui(has_selection, |ui| {
                if theme::danger_button(ui, &format!("\u{EC28} {}", t!("mp_delete"))).clicked() {
                    self.manual.delete_idx = self.manual.selected_idx;
                }
            });
        });

        // ── Bölüm Ekle / Düzenle diyaloğu ─────────────────
        let dialog_open = self.manual.adding || self.manual.editing;
        if dialog_open {
            let is_edit = self.manual.editing;
            let title = if is_edit { t!("mp_edit_partition") } else { t!("mp_new_partition") };
            egui::Window::new(title)
                .collapsible(false)
                .resizable(false)
                .default_size(egui::vec2(420.0, 300.0))
                //.anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
                .default_pos(ui.ctx().screen_rect().center() - egui::vec2(210.0, 150.0))
                .show(ui.ctx(), |ui| {
                    ui.set_min_width(420.0);
                    ui.set_max_width(420.0);
                    ui.label(t!("mp_fstype"));
                    let prev_fs = self.manual.add_fstype;
                    let fs_label = FS_OPTIONS.get(self.manual.add_fstype).map(|x| x.0).unwrap_or("?");
                    theme::show_combo_box(ui, "fs_combo", fs_label, ui.available_width(), |ui, w| {
                        for (i, (label, _)) in FS_OPTIONS.iter().enumerate() {
                            theme::selectable_value(ui, &mut self.manual.add_fstype, i, *label, w);
                        }
                    });
                    // FS tipi değişince akıllı boyut öner
                    if !is_edit && prev_fs != self.manual.add_fstype && self.manual.add_size_str.is_empty() {
                        let fs = FS_OPTIONS.get(self.manual.add_fstype).map(|x| &x.1);
                        match fs {
                            Some(FsType::Fat32) => self.manual.add_size_str = "300".to_string(),
                            Some(FsType::Swap)  => self.manual.add_size_str = format!("{}", recommended_swap_mb()),
                            _ => {}
                        }
                    }

                    ui.add_space(6.0);
                    form_label(ui, &t!("mp_size_hint"));
                    ui.horizontal(|ui| {
                        ui.add_sized(
                            [160.0, 32.0], // Genişlik 160.0, Yükseklik 40.0 piksel
                            egui::TextEdit::singleline(&mut self.manual.add_size_str)
                                .text_color(egui::Color32::from_rgb(230, 230, 230))
                                .vertical_align(egui::Align::Center)
                        );
                        // ui.add(egui::TextEdit::singleline(&mut self.manual.add_size_str)
                        //     .desired_width(120.0)
                        //     .text_color(egui::Color32::from_rgb(230, 230, 230)));
                        let size_str = self.manual.add_size_str.trim();
                        if size_str == "remaining" {
                            ui.label(egui::RichText::new(t!("mp_size_remaining"))
                                .color(crate::ui::theme::c_success())
                                .size(12.0));
                        } else {
                            let parsed: u64 = size_str.parse().unwrap_or(0);
                            if parsed > 0 {
                                let gb = parsed as f64 / 1024.0;
                                ui.label(format!("{} MB", format_number_thousands(parsed)));
                                ui.label(egui::RichText::new(format!("(≈ {:.1} GB)", gb))
                                    .color(crate::ui::theme::c_text_dim())
                                    .size(11.0));
                            } else {
                                ui.label("MB");
                            }
                        }
                    });
                    // Slider — kullanılabilir alan kadar
                    let used_mb: u64 = state.custom_partitions.iter()
                        .enumerate()
                        .filter(|(i, p)| p.size_mb > 0 && Some(*i) != self.manual.edit_idx)
                        .map(|(_, p)| p.size_mb)
                        .sum();
                    let avail_mb = (max_mb as u64).saturating_sub(used_mb).max(1);
                    eprintln!("DEBUG EDIT: max_mb={} used_mb={} avail_mb={} edit_idx={:?} partitions={:?}",
                        max_mb, used_mb, avail_mb, self.manual.edit_idx,
                        state.custom_partitions.iter().map(|p| (p.mountpoint.clone(), p.size_mb)).collect::<Vec<_>>());
                    let mut size_val = self.manual.add_size_str.trim().parse::<f64>().unwrap_or(0.0);
                    ui.add_space(2.0);
                    if ui.add(egui::Slider::new(&mut size_val, 0.0..=avail_mb as f64)
                        .show_value(false)
                        .max_decimals(0)
                    ).changed() {
                        if size_val == 0.0 {
                            self.manual.add_size_str = "0".to_string();
                        } else {
                            self.manual.add_size_str = format!("{}", size_val as u64);
                        }
                    }

                    ui.add_space(6.0);
                    ui.separator();

                    ui.label(t!("mp_mountpoint"));
                    ui.horizontal(|ui| {
                        let current_mp = if self.manual.add_mountpoint.is_empty() {
                            t!("mp_select_hint").to_string()
                        } else {
                            self.manual.add_mountpoint.clone()
                        };
                        let prev_mp = self.manual.add_mountpoint.clone();
                        theme::show_combo_box(ui, "mp_combo", &current_mp, 120.0, |ui, w| {
                            for mp in COMMON_MOUNTPOINTS {
                                theme::selectable_value(ui, &mut self.manual.add_mountpoint, mp.to_string(), *mp, w);
                            }
                        });
                        // ui.add(egui::TextEdit::singleline(&mut self.manual.add_mountpoint)
                        //     .desired_width(160.0)
                        //     .text_color(egui::Color32::from_rgb(230, 230, 230)));
                        ui.add_sized(
                            [160.0, 32.0], // Genişlik 160.0, Yükseklik 40.0 piksel
                            egui::TextEdit::singleline(&mut self.manual.add_mountpoint)
                                .text_color(egui::Color32::from_rgb(230, 230, 230))
                                .vertical_align(egui::Align::Center)
                        );
                        
                        // Mountpoint değiştiğinde boyutu otomatik güncelle (eğer değer boşsa veya varsayılansa)
                        if prev_mp != self.manual.add_mountpoint {
                            let mp = self.manual.add_mountpoint.trim().to_lowercase();
                            let current_size = self.manual.add_size_str.trim();
                            let is_empty_or_default = current_size.is_empty() 
                                || current_size == "0" 
                                || current_size == "remaining";

                            if is_empty_or_default {
                                self.manual.add_size_str = match mp.as_str() {
                                    "/boot/efi" => "1024".to_string(), // 1GB
                                    "swap" => {
                                        // Swap için minimum 1GB, varsa RAM boyutu kadar
                                        if let Ok(mem) = std::fs::read_to_string("/proc/meminfo") {
                                            if let Some(line) = mem.lines().find(|l| l.starts_with("MemTotal:")) {
                                                let kb: u64 = line.split_whitespace()
                                                    .nth(1)
                                                    .and_then(|s| s.parse().ok())
                                                    .unwrap_or(4194304); // 4GB varsayılan
                                                let mb = kb / 1024;
                                                // Minimum 1GB, RAM boyutu ile karşılaştır
                                                let swap_size = if mb < 1024 { 1024 } else { mb };
                                                swap_size.to_string()
                                            } else {
                                                "1024".to_string() // 1GB varsayılan
                                            }
                                        } else {
                                            "1024".to_string() // 1GB varsayılan
                                        }
                                    },
                                    "/" => "remaining".to_string(), // Geri kalan alan
                                    _ => self.manual.add_size_str.clone(), // Diğerleri için mevcut değeri koru
                                };
                            }
                        }
                    });

                    // mountpoint "swap" seçildiğinde FS tipini otomatik swap yap
                    let mp = self.manual.add_mountpoint.trim().to_lowercase();
                    let current_fs = FS_OPTIONS.get(self.manual.add_fstype).map(|x| &x.1);
                    let idx = |fs: FsType| FS_OPTIONS.iter().position(|(_, t)| *t == fs).unwrap_or(0);
                    if mp == "swap" && current_fs != Some(&FsType::Swap) {
                        self.manual.add_fstype = idx(FsType::Swap);
                    } else if mp == "/boot/efi" && current_fs != Some(&FsType::Fat32) {
                        self.manual.add_fstype = idx(FsType::Fat32);
                    }

                    ui.add_space(6.0);
                    ui.separator();
                    
                    let fstype = FS_OPTIONS.get(self.manual.add_fstype).map(|x| x.1.clone()).unwrap_or(FsType::Ext4);
                    let can_encrypt = matches!(fstype, FsType::Ext4 | FsType::Ext3 | FsType::Btrfs | FsType::Xfs);
                    
                    // ui.label(t!("luks_enable_root"));
                    // ui.add_enabled_ui(can_encrypt, |ui| {
                    //     ui.checkbox(&mut self.manual.add_encrypt, "");
                    // });
                    ui.add_enabled_ui(can_encrypt, |ui| {
                        // Checkbox'ı yazısıyla birlikte tek bir bileşen olarak ekliyoruz:
                        ui.checkbox(&mut self.manual.add_encrypt, 
                            egui::RichText::new(t!("luks_enable_root")).color(egui::Color32::from_rgb(128, 128, 128))
                        );
                       
                    });
                    if !can_encrypt { self.manual.add_encrypt = false; }

                    if self.manual.add_encrypt {
                        ui.add_space(6.0);
                        ui.label(t!("luks_password"));
                        let pw = &mut self.manual.add_luks_password;
                        ui.horizontal(|ui| {
                            if self.show_luks_password {
                                ui.add_sized(
                                    [200.0, 32.0], // Genişlik 200.0, Yükseklik 32.0 piksel
                                    egui::TextEdit::singleline(pw)
                                );
                            } else {
                                ui.add_sized(
                                    [200.0, 32.0], // Genişlik 200.0, Yükseklik 32.0 piksel
                                    egui::TextEdit::singleline(pw).password(true)
                                        .text_color(egui::Color32::from_rgb(230, 230, 230))
                                        .vertical_align(egui::Align::Center)
                                );
                                let eye = if self.show_luks_password { "\u{ECB5}" } else { "\u{ECB7}" };
                                if ui.small_button(eye).clicked() {
                                    self.show_luks_password = !self.show_luks_password;
                                }
                            }
                        });
                    }

                    ui.add_space(6.0);
                    ui.checkbox(&mut self.manual.add_skip_format, 
                        egui::RichText::new(t!("mp_skip_format")).color(egui::Color32::from_rgb(128, 128, 128)));

                    ui.add_space(8.0);
                    ui.separator();
                    ui.horizontal(|ui| {
                        let ok_label = if is_edit { t!("mp_save") } else { t!("mp_add_btn") };
                        if theme::primary_button(ui, &ok_label).clicked() {
                            let size_str = self.manual.add_size_str.trim();
                            let size_mb: u64 = if size_str == "remaining" {
                                // Kalan alanı hesapla
                                if let Some(disk_size) = self.selected_disk_size_mb {
                                    let used: u64 = state.custom_partitions.iter()
                                        .enumerate()
                                        .filter(|(i, _)| Some(*i) != self.manual.edit_idx)
                                        .map(|(_, p)| p.size_mb)
                                        .sum();
                                    let remaining = disk_size.saturating_sub(used);
                                    eprintln!("DEBUG REMAINING: disk_size={} used={} remaining={}", disk_size, used, remaining);
                                    if remaining > 0 { remaining } else { disk_size }
                                } else {
                                    0
                                }
                            } else {
                                size_str.parse().unwrap_or(0)
                            };
                            let mp = self.manual.add_mountpoint.trim().to_string();
                            let fstype = FS_OPTIONS.get(self.manual.add_fstype).map(|x| x.1.clone()).unwrap_or(FsType::Ext4);
                            let encrypt = self.manual.add_encrypt;
                            let luks_password = if encrypt { self.manual.add_luks_password.clone() } else { String::new() };

                            if mp.is_empty() {
                                self.manual.error = Some(t!("mp_error_empty_mountpoint").to_string());
                            } else if is_edit {
                                if let Some(idx) = self.manual.edit_idx {
                                    if idx < state.custom_partitions.len() {
                                        let device = state.custom_partitions[idx].device.clone();
                                        let skip_format = self.manual.add_skip_format;
                                        state.custom_partitions[idx] = CustomPartition {
                                            device,
                                            size_mb,
                                            fstype,
                                            mountpoint: mp,
                                            encrypt,
                                            luks_password,
                                            luks_name: String::new(),
                                            skip_format,
                                        };
                                    }
                                }
                                self.manual.editing = false;
                                self.manual.edit_idx = None;
                                self.manual.selected_idx = None;
                                self.manual.error = None;
                            } else {
                                let part_num = state.custom_partitions.len() + 1;
                                let device = crate::installer::part_path(&disk, part_num as u32);
                                state.custom_partitions.push(CustomPartition {
                                    device,
                                    size_mb,
                                    fstype,
                                    mountpoint: mp,
                                    encrypt,
                                    luks_password,
                                    luks_name: String::new(),
                                    skip_format: self.manual.add_skip_format,
                                });
                                self.manual.add_encrypt = false;
                                self.manual.add_luks_password.clear();
                                self.manual.error = None;
                                self.manual.adding = false;
                            }
                        }
                        if theme::secondary_button(ui, &t!("cancel")).clicked() {
                            self.manual.adding = false;
                            self.manual.editing = false;
                            self.manual.edit_idx = None;
                        }
                    });
                });
        }

        // ── LVM Yapılandırması ──────────────────────────────────
        ui.add_space(12.0);
        let has_lvm_pvs = state.custom_partitions.iter().any(|p| p.fstype == FsType::Lvm);
        if has_lvm_pvs {
            ui.label(egui::RichText::new("LVM Volume Groups").strong().size(14.0));
            ui.add_space(4.0);
            egui::Grid::new("lvm_vg_grid")
                .num_columns(4)
                .spacing([12.0, 6.0])
                .striped(true)
                .show(ui, |ui| {
                    ui.label("VG Name");
                    ui.label("PV Devices");
                    ui.label("Size");
                    ui.label("");
                    ui.end_row();

                    let mut remove_vg: Option<usize> = None;
                    for (vi, vg) in state.volume_groups.iter().enumerate() {
                        let pv_list = vg.pv_devices.join(", ");
                        let size_str = if vg.size_mb >= 1024 {
                            format!("{:.1} GB", vg.size_mb as f64 / 1024.0)
                        } else {
                            format!("{} MB", vg.size_mb)
                        };
                        ui.label(&vg.name);
                        ui.label(&pv_list);
                        ui.label(&size_str);
                        if ui.small_button("🗑").clicked() {
                            remove_vg = Some(vi);
                        }
                        ui.end_row();
                    }
                    if let Some(vi) = remove_vg {
                        state.volume_groups.remove(vi);
                    }

                    // Yeni VG ekleme
                    ui.horizontal(|ui| {
                        ui.text_edit_singleline(&mut self.manual.add_vg_name);
                        if ui.small_button("➕ VG").clicked()
                            && !self.manual.add_vg_name.is_empty()
                        {
                            let pvs: Vec<String> = state.custom_partitions.iter()
                                .filter(|p| p.fstype == FsType::Lvm)
                                .map(|p| p.device.clone())
                                .collect();
                            let size: u64 = state.custom_partitions.iter()
                                .filter(|p| p.fstype == FsType::Lvm)
                                .map(|p| p.size_mb)
                                .sum();
                            state.volume_groups.push(VolumeGroup {
                                name: self.manual.add_vg_name.clone(),
                                pv_devices: pvs,
                                size_mb: size,
                            });
                            self.manual.add_vg_name.clear();
                        }
                    });
                    ui.label("");
                    ui.label("");
                    ui.end_row();
                });

            // ── LVM Logical Volumes Tablosu ──────────────────────────
            let has_vgs = !state.volume_groups.is_empty();
            if has_vgs {
                ui.add_space(12.0);
                ui.label(egui::RichText::new(t!("lvm_lv_title")).strong().size(14.0));
                ui.add_space(4.0);

                let mut remove_lv: Option<usize> = None;
                egui::Grid::new("lvm_lv_grid")
                    .num_columns(5)
                    .spacing([12.0, 6.0])
                    .striped(true)
                    .show(ui, |ui| {
                        ui.label(egui::RichText::new(t!("lvm_lv_name")).strong().color(crate::ui::theme::c_text()));
                        ui.label(egui::RichText::new(t!("lvm_lv_vg")).strong().color(crate::ui::theme::c_text()));
                        ui.label(egui::RichText::new(t!("mp_size")).strong().color(crate::ui::theme::c_text()));
                        ui.label(egui::RichText::new(t!("mp_mountpoint")).strong().color(crate::ui::theme::c_text()));
                        ui.label(egui::RichText::new(t!("mp_action")).strong().color(crate::ui::theme::c_text()));
                        ui.end_row();

                        for (li, lv) in state.logical_volumes.iter().enumerate() {
                            let size_str = if lv.size_mb == 0 {
                                t!("mp_size_remaining").to_string()
                            } else {
                                format!("{} MB", lv.size_mb)
                            };
                            ui.label(&lv.name);
                            ui.label(&lv.vg_name);
                            ui.label(size_str);
                            ui.label(&lv.mountpoint);
                            if ui.small_button("🗑").clicked() {
                                remove_lv = Some(li);
                            }
                            ui.end_row();
                        }
                    });

                if let Some(li) = remove_lv {
                    state.logical_volumes.remove(li);
                }

                ui.add_space(8.0);
                // "Logical Volume Ekle" butonu
                if theme::primary_button(ui, &format!("➕  {}", t!("lvm_lv_add"))).clicked() {
                    self.manual.adding_lv = true;
                    self.manual.add_lv_name.clear();
                    self.manual.add_lv_vg_idx = 0;
                    self.manual.add_lv_size_str.clear();
                    self.manual.add_lv_fstype = 0;
                    self.manual.add_lv_mountpoint.clear();
                }
            }
        }

        // ── Logical Volume Ekleme Diyaloğu ────────────────────────
        if self.manual.adding_lv {
            egui::Window::new(t!("lvm_lv_add"))
                .collapsible(false)
                .resizable(false)
                .anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
                .show(ui.ctx(), |ui| {
                    egui::Grid::new("add_lv_grid")
                        .num_columns(2)
                        .spacing([12.0, 8.0])
                        .show(ui, |ui| {
                            // Hacim Grubu (VG) seçimi
                            ui.label(t!("lvm_lv_vg"));
                            let current_vg = state.volume_groups.get(self.manual.add_lv_vg_idx)
                                .map(|vg| vg.name.as_str())
                                .unwrap_or("?");
                            theme::show_combo_box(ui, "lv_vg_combo", current_vg, ui.available_width(), |ui, w| {
                                for (vi, vg) in state.volume_groups.iter().enumerate() {
                                    theme::selectable_value(ui, &mut self.manual.add_lv_vg_idx, vi, vg.name.as_str(), w);
                                }
                            });
                            ui.end_row();

                            // LV Adı
                            ui.label(t!("lvm_lv_name"));
                            ui.text_edit_singleline(&mut self.manual.add_lv_name);
                            ui.end_row();

                            // Dosya sistemi
                            ui.label(t!("mp_fstype"));
                            let lv_fs_label = FS_OPTIONS.get(self.manual.add_lv_fstype).map(|x| x.0).unwrap_or("?");
                            theme::show_combo_box(ui, "lv_fs_combo", lv_fs_label, ui.available_width(), |ui, w| {
                                for (i, (label, _)) in FS_OPTIONS.iter().enumerate() {
                                    theme::selectable_value(ui, &mut self.manual.add_lv_fstype, i, *label, w);
                                }
                            });
                            ui.end_row();

                            // Boyut
                            ui.label(t!("mp_size_hint"));
                            ui.text_edit_singleline(&mut self.manual.add_lv_size_str);
                            ui.end_row();

                            // Bağlama noktası (2 aşamalı: combo + input)
                            ui.label(t!("mp_mountpoint"));
                            ui.horizontal(|ui| {
                                let current_mp = if self.manual.add_lv_mountpoint.is_empty() {
                                    t!("mp_select_hint").to_string()
                                } else {
                                    self.manual.add_lv_mountpoint.clone()
                                };
                                theme::show_combo_box(ui, "lv_mp_combo", &current_mp, 120.0, |ui, w| {
                                    for mp in COMMON_MOUNTPOINTS {
                                        theme::selectable_value(ui, &mut self.manual.add_lv_mountpoint, mp.to_string(), *mp, w);
                                    }
                                });
                                let mp_field = egui::TextEdit::singleline(&mut self.manual.add_lv_mountpoint)
                                    .hint_text(t!("mp_add_dialog_hint"));
                                ui.add(mp_field);
                            });
                            ui.end_row();
                        });

                    ui.add_space(8.0);
                    ui.horizontal(|ui| {
                        if theme::primary_button(ui, &t!("mp_add_btn")).clicked() {
                            let size_mb: u64 = self.manual.add_lv_size_str.trim().parse().unwrap_or(0);
                            let mp = self.manual.add_lv_mountpoint.trim().to_string();
                            let lv_name = self.manual.add_lv_name.trim().to_string();
                            let fstype = FS_OPTIONS.get(self.manual.add_lv_fstype).map(|x| x.1.clone()).unwrap_or(FsType::Ext4);

                            if lv_name.is_empty() {
                                self.manual.error = Some("LV Adı boş olamaz.".to_string());
                            } else if mp.is_empty() {
                                self.manual.error = Some(t!("mp_error_empty_mountpoint").to_string());
                            } else if let Some(vg) = state.volume_groups.get(self.manual.add_lv_vg_idx) {
                                // VG sınır doğrulaması
                                let current_sum: u64 = state.logical_volumes.iter()
                                    .filter(|lv| lv.vg_name == vg.name)
                                    .map(|lv| lv.size_mb)
                                    .sum();
                                if current_sum + size_mb > vg.size_mb && size_mb > 0 {
                                    self.manual.error = Some(t!("lvm_lv_error_size").to_string());
                                } else {
                                    state.logical_volumes.push(crate::installer::LogicalVolume {
                                        name: lv_name,
                                        vg_name: vg.name.clone(),
                                        size_mb,
                                        fstype,
                                        mountpoint: mp,
                                    });
                                    self.manual.error = None;
                                    self.manual.adding_lv = false;
                                }
                            } else {
                                self.manual.error = Some(t!("lvm_lv_error_vg").to_string());
                            }
                        }
                        if theme::secondary_button(ui, &t!("cancel")).clicked() {
                            self.manual.adding_lv = false;
                        }
                    });
                });
        }

        // ── Doğrulama mesajları ─────────────────────────────────
        ui.add_space(6.0);
        if let Some(ref err) = self.manual.error {
            ui.colored_label(egui::Color32::from_rgb(217, 0, 91), err);
        }
        if !state.custom_partitions.is_empty() {
            if let Some(warn) = validate_manual(&state.custom_partitions, &state.logical_volumes, self.is_uefi) {
                ui.colored_label(
                    egui::Color32::from_rgb(220, 160, 40),
                    format!("\u{ECA1} {}", warn),
                );
            } else {
                ui.colored_label(
                    egui::Color32::from_rgb(7, 255, 0),
                    format!("\u{EB7B} {}", t!("mp_plan_valid")),
                );

            }
        }
    }
}

// ─────────────────────────────────────────────
// Yardımcı: renkli bölüm şeridi (manuel)
// ─────────────────────────────────────────────

fn manual_partition_bar(ui: &mut egui::Ui, parts: &[CustomPartition]) {
    let bar_height = 28.0;
    let (rect, _) = ui.allocate_exact_size(
        egui::vec2(ui.available_width(), bar_height),
        egui::Sense::hover(),
    );
    let painter = ui.painter();

    if parts.is_empty() {
        return;
    }

    // Each partition gets at least MIN_VISIBLE of the bar so all are visible
    let sized_total: f32 = parts.iter().map(|p| p.size_mb as f32).sum();
    let min_visible = 0.04;

    let mut raw: Vec<f32> = parts.iter().map(|p| {
        if sized_total > 0.0 {
            (p.size_mb as f32 / sized_total).max(min_visible)
        } else {
            min_visible
        }
    }).collect();

    // Normalize to sum 1.0
    let sum: f32 = raw.iter().sum();
    for v in raw.iter_mut() {
        *v /= sum;
    }

    let mut segments: Vec<(&str, f32, egui::Color32)> = Vec::new();

    for (i, part) in parts.iter().enumerate() {
        let label = part.mountpoint.as_str();
        let color = if part.fstype == FsType::Fat32 {
            egui::Color32::from_rgb(80, 160, 220)
        } else if part.fstype == FsType::Swap {
            egui::Color32::from_rgb(220, 160, 40)
        } else if part.mountpoint == "/" {
            egui::Color32::from_rgb(80, 190, 100)
        } else {
            egui::Color32::from_rgb(160, 130, 200)
        };
        segments.push((label, raw[i], color));
    }

    let mut x = rect.left();
    let rounding = egui::Rounding::same(4.0);
    for (i, (label, frac, color)) in segments.iter().enumerate() {
        let w = frac * rect.width();
        let seg_rect = egui::Rect::from_min_size(
            egui::pos2(x, rect.top()),
            egui::vec2(w - 1.0, bar_height),
        );
        let seg_rounding = if i == 0 {
            egui::Rounding { nw: rounding.nw, sw: rounding.sw, ne: 0.0, se: 0.0 }
        } else if i == segments.len() - 1 {
            egui::Rounding { nw: 0.0, sw: 0.0, ne: rounding.ne, se: rounding.se }
        } else {
            egui::Rounding::ZERO
        };
        painter.rect_filled(seg_rect, seg_rounding, *color);
        painter.text(
            seg_rect.center(),
            egui::Align2::CENTER_CENTER,
            *label,
            egui::FontId::proportional(12.0),
            egui::Color32::WHITE,
        );
        x += w;
    }
}

// ─────────────────────────────────────────────
// Yardımcı: renkli bölüm şeridi (otomatik)
// ─────────────────────────────────────────────

fn partition_bar(ui: &mut egui::Ui, plan: &PartitionPlan) {
    let total = (plan.efi_mb + plan.swap_mb + plan.root_mb) as f32;
    let bar_height = 28.0;
    let (rect, _) = ui.allocate_exact_size(
        egui::vec2(ui.available_width(), bar_height),
        egui::Sense::hover(),
    );
    let painter = ui.painter();

    struct Seg<'a> { frac: f32, color: egui::Color32, label: &'a str }
    let mut segments: Vec<Seg> = Vec::new();

    if plan.efi_mb > 0 {
        segments.push(Seg {
            frac: plan.efi_mb as f32 / total,
            color: egui::Color32::from_rgb(80, 160, 220),
            label: "EFI",
        });
    }
    segments.push(Seg {
        frac: plan.swap_mb as f32 / total,
        color: egui::Color32::from_rgb(220, 160, 40),
        label: "swap",
    });
    segments.push(Seg {
        frac: plan.root_mb as f32 / total,
        color: egui::Color32::from_rgb(80, 190, 100),
        label: "/",
    });

    let mut x = rect.left();
    let rounding = egui::Rounding::same(4.0);
    for (i, seg) in segments.iter().enumerate() {
        let w = seg.frac * rect.width();
        let seg_rect = egui::Rect::from_min_size(
            egui::pos2(x, rect.top()),
            egui::vec2(w - 1.0, bar_height),
        );
        let seg_rounding = if i == 0 {
            egui::Rounding { nw: rounding.nw, sw: rounding.sw, ne: 0.0, se: 0.0 }
        } else if i == segments.len() - 1 {
            egui::Rounding { nw: 0.0, sw: 0.0, ne: rounding.ne, se: rounding.se }
        } else {
            egui::Rounding::ZERO
        };
        painter.rect_filled(seg_rect, seg_rounding, seg.color);
        painter.text(
            seg_rect.center(),
            egui::Align2::CENTER_CENTER,
            seg.label,
            egui::FontId::proportional(12.0),
            egui::Color32::WHITE,
        );
        x += w;
    }
}

/// Sayıyı nokta ile binlik ayraçlı formata çevirir (örn. 7000000 → 7.000.000).
fn format_number_thousands(n: u64) -> String {
    let s = n.to_string();
    let mut result = String::new();
    for (i, c) in s.chars().enumerate() {
        if i > 0 && (s.len() - i) % 3 == 0 {
            result.push('.');
        }
        result.push(c);
    }
    result
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::installer::{LogicalVolume, PartitionTableType};

    fn disk(name: &str, size_gb: u64) -> DiskInfo {
        DiskInfo {
            name: name.to_string(),
            vendor: "ATA".to_string(),
            model: "VBOX HARDDISK".to_string(),
            drive_type: "HDD".to_string(),
            size_gb,
            size_bytes: size_gb * 1_073_741_824,
        }
    }

    fn part(device: &str, size_mb: u64, fstype: FsType, mountpoint: &str) -> CustomPartition {
        CustomPartition {
            device: device.to_string(),
            size_mb,
            fstype,
            mountpoint: mountpoint.to_string(),
            encrypt: false,
            luks_password: String::new(),
            luks_name: String::new(),
            skip_format: false,
        }
    }

    fn step(uefi: bool) -> PartitionStep {
        PartitionStep {
            scanned: true,
            is_uefi: uefi,
            manual: ManualState::default(),
            show_luks_password: false,
            selected_disk_size_mb: None,
        }
    }

    // ── make_plan ────────────────────────────────────────────

    #[test]
    fn plan_rejects_small_disk() {
        let d = disk("/dev/sdb", 9);
        assert!(make_plan(&d, true).is_none());
        assert!(make_plan(&d, false).is_none());
    }

    #[test]
    fn plan_uefi_large_disk() {
        let d = disk("/dev/sda", 100);
        let plan = make_plan(&d, true).expect("100GB disk için plan oluşmalı");
        assert_eq!(plan.disk, "/dev/sda");
        assert_eq!(plan.table_type, PartitionTableType::Gpt);
        assert!(plan.efi_mb > 0, "UEFI planında EFI bölümü olmalı");
        // EFI + swap + root, overhead payı düşülmüş disk boyutunu aşmamalı
        assert!(plan.efi_mb + plan.swap_mb + plan.root_mb <= 100 * 1024);
    }

    #[test]
    fn plan_bios_large_disk() {
        let d = disk("/dev/sda", 100);
        let plan = make_plan(&d, false).expect("100GB disk için plan oluşmalı");
        assert_eq!(plan.table_type, PartitionTableType::Mbr);
        assert_eq!(plan.efi_mb, 0, "BIOS modunda EFI bölümü olmamalı");
    }

    // ── validate_manual ───────────────────────────────────────

    #[test]
    fn manual_empty_plan_fails() {
        assert!(validate_manual(&[], &[], true).is_some());
        assert!(validate_manual(&[], &[], false).is_some());
    }

    #[test]
    fn manual_root_only_ok_on_bios() {
        let parts = vec![part("/dev/sda1", 20_000, FsType::Ext4, "/")];
        assert!(validate_manual(&parts, &[], false).is_none());
    }

    #[test]
    fn manual_uefi_requires_efi_part() {
        let parts = vec![part("/dev/sda1", 20_000, FsType::Ext4, "/")];
        assert!(
            validate_manual(&parts, &[], true).is_some(),
            "UEFI modunda EFI bölümü zorunlu"
        );

        let with_efi = vec![
            part("/dev/sda1", 300, FsType::Fat32, "/boot/efi"),
            part("/dev/sda2", 20_000, FsType::Ext4, "/"),
        ];
        assert!(validate_manual(&with_efi, &[], true).is_none());
    }

    #[test]
    fn manual_root_can_come_from_lv() {
        let parts = vec![part("/dev/sda1", 20_000, FsType::Lvm, "")];
        let lvs = vec![LogicalVolume {
            name: "root".to_string(),
            vg_name: "vg0".to_string(),
            size_mb: 10_000,
            fstype: FsType::Ext4,
            mountpoint: "/".to_string(),
        }];
        assert!(validate_manual(&parts, &lvs, false).is_none());
    }

    // ── InstallerStep arayüzü ─────────────────────────────────

    #[test]
    fn auto_mode_complete_only_with_plan() {
        let st = step(true);
        let mut state = crate::installer::GlobalState::default();
        state.erase_disk = true;

        assert!(!st.is_complete(&state), "plan yokken tamamlanmamalı");
        state.partition_plan = make_plan(&disk("/dev/sda", 100), true);
        assert!(st.is_complete(&state), "plan varken tamamlanmalı");
    }

    #[test]
    fn manual_mode_complete_with_valid_partitions() {
        let st = step(true);
        let mut state = crate::installer::GlobalState::default();
        state.erase_disk = false;

        assert!(!st.is_complete(&state), "bölüm yokken tamamlanmamalı");

        // Kök var ama EFI yok → tamamlanmamalı
        state.custom_partitions.push(part("/dev/sda1", 20_000, FsType::Ext4, "/"));
        assert!(!st.is_complete(&state), "eksik EFI bölümü ile tamamlanmamalı");

        // Geçerli düzen → tamamlanmalı
        state.custom_partitions.push(part("/dev/sda1", 300, FsType::Fat32, "/boot/efi"));
        assert!(st.is_complete(&state), "geçerli düzen ile tamamlanmalı");
    }

    // ── format_number_thousands ───────────────────────────────

    #[test]
    fn formats_thousands() {
        assert_eq!(format_number_thousands(0), "0");
        assert_eq!(format_number_thousands(999), "999");
        assert_eq!(format_number_thousands(1000), "1.000");
        assert_eq!(format_number_thousands(7000000), "7.000.000");
    }

    // ── detect_drive_type ─────────────────────────────────────

    #[test]
    fn drive_type_by_name() {
        assert_eq!(detect_drive_type("nvme0n1"), "NVMe SSD");
        assert_eq!(detect_drive_type("mmcblk0"), "MMC/SD");
        assert_eq!(detect_drive_type("nonexistent99"), "HDD");
    }

    // ── lsblk / sysfs okumaları (canlı sistem) ────────────────

    #[test]
    fn read_existing_partitions_never_panics() {
        // Var olmayan disk → boş liste, çökmemeli
        assert!(read_existing_partitions("/dev/does-not-exist").is_empty());

        // Var olan disklerde dönen bölümler /dev/ ön ekli olmalı
        for d in list_block_devices().iter().take(1) {
            for p in read_existing_partitions(&d.name) {
                assert!(p.device.starts_with("/dev/"));
            }
        }
    }

    #[test]
    fn list_block_devices_scrubs_loop_ram() {
        for d in list_block_devices() {
            let base = d.name.trim_start_matches("/dev/");
            assert!(!base.starts_with("loop"));
            assert!(!base.starts_with("ram"));
            assert!(!base.starts_with("sr"));
            assert!(!base.starts_with("zram"));
        }
    }
}
