use super::{run_chroot, Job, UiSender};

/// /etc/locale.conf ve /etc/locale.gen'i yazar, sonra locale-gen çalıştırır.
pub struct ConfigureLocaleJob {
    pub mount:    String,
    pub locale:   String,  // ör. "tr_TR.UTF-8"
}

#[async_trait::async_trait]
impl Job for ConfigureLocaleJob {
    fn name(&self) -> &str { "job_locale" }

    async fn run(&self, ui: &UiSender) -> Result<(), String> {
        // Locale değeri doğrulama: yalnızca alfanumerik, '.', '_', '-', '@'
        // karakterlerine izin ver. Yol manipülasyonu ve injection önlenir.
        let locale_valid = !self.locale.is_empty()
            && !self.locale.contains("..")
            && !self.locale.contains('/')
            && !self.locale.contains('\n')
            && self.locale.chars().all(|c| c.is_alphanumeric() || "._-@".contains(c));
        if !locale_valid {
            return Err(format!("Geçersiz locale değeri: '{}'", self.locale));
        }

        let etc_dir = format!("{}/etc", self.mount);
        let _ = tokio::fs::create_dir_all(&etc_dir).await;
        let _ = tokio::fs::create_dir_all(format!("{}/etc/env.d", self.mount)).await;

        // /etc/locale.conf  (systemd-style)
        let conf_path = format!("{}/etc/locale.conf", self.mount);
        let conf = format!(
            "LANG={locale}\nLC_ALL={locale}\n",
            locale = self.locale
        );
        ui.log(format!("Yazılıyor: {}", conf_path));
        let _ = tokio::fs::write(&conf_path, conf).await;

        // /etc/env.d/03locale  (PisiLinux native)
        let pisi_locale_path = format!("{}/etc/env.d/03locale", self.mount);
        let pisi_locale = format!(
            "LANG={locale}\nLC_ALL={locale}\n",
            locale = self.locale
        );
        ui.log(format!("Yazılıyor: {}", pisi_locale_path));
        let _ = tokio::fs::write(&pisi_locale_path, pisi_locale).await;

        // /etc/locale.gen — satırın başındaki # kaldırılır
        let gen_path = format!("{}/etc/locale.gen", self.mount);
        ui.log(format!("Güncelleniyor: {}", gen_path));
        let content = tokio::fs::read_to_string(&gen_path).await.unwrap_or_default();
        // Her zaman aktif olması gereken yedek yerel ayarlar
        let fallback_locales = ["en_US.UTF-8", "C.UTF-8"];
        let mut updated: Vec<String> = content
            .lines()
            .map(|line| {
                let stripped = line.trim_start_matches('#').trim_start();
                if stripped.starts_with(&self.locale)
                    || fallback_locales.iter().any(|l| stripped.starts_with(l))
                {
                    stripped.to_string() // yorumu kaldır
                } else {
                    line.to_string()
                }
            })
            .collect();

        // Yedek yerel ayarlar dosyada yoksa sona ekle
        for loc in fallback_locales {
            let present = updated.iter().any(|line| {
                line.trim_start_matches('#').trim_start().starts_with(loc)
            });
            if !present {
                updated.push(format!("{} UTF-8", loc));
            }
        }

        let content_to_write = updated.join("\n") + "\n";

        tokio::fs::write(&gen_path, content_to_write)
            .await
            .map_err(|e| format!("/etc/locale.gen yazılamadı: {}", e))?;

        // locale.gen çalıştır — kurulum sonrası locale desteği için zorunlu
        ui.log("locale.gen çalıştırılıyor…");
        run_chroot(&self.mount, &["locale-gen"]).await?;

        Ok(())
    }
}

/// Zaman dilimini ayarlar ve hwclock'u senkronize eder.
pub struct ConfigureTimezoneJob {
    pub mount:    String,
    pub timezone: String, // ör. "Europe/Istanbul"
}

#[async_trait::async_trait]
impl Job for ConfigureTimezoneJob {
    fn name(&self) -> &str { "job_timezone" }

    async fn run(&self, ui: &UiSender) -> Result<(), String> {
        // Path traversal koruması: timezone değeri yalnızca alfanumerik,
        // '/', '_', '-', '+' karakterlerine izin verir; ".." asla geçemez.
        let tz = &self.timezone;
        let tz_valid = !tz.is_empty()
            && !tz.contains("..")
            && tz.chars().all(|c| c.is_alphanumeric() || "/._-+".contains(c));
        if !tz_valid {
            return Err(format!("Geçersiz timezone değeri: '{}'", tz));
        }

        // Sembolik link: /etc/localtime → /usr/share/zoneinfo/<tz>
        let link_target = format!("/usr/share/zoneinfo/{}", self.timezone);
        let link_path   = format!("{}/etc/localtime", self.mount);

        ui.log(format!("ln -sf {} {}", link_target, link_path));
        // Önce varsa eski linki sil
        let _ = tokio::fs::remove_file(&link_path).await;
        // tokio'da Unix symlink için spawn_blocking kullan
        let lt = link_target.clone();
        let lp = link_path.clone();
        tokio::task::spawn_blocking(move || {
            std::os::unix::fs::symlink(&lt, &lp)
        }).await
            .map_err(|e| format!("symlink spawn hatası: {}", e))?
            .map_err(|e| format!("localtime symlink: {}", e))?;

        // hwclock --systohc
        ui.log("hwclock --systohc çalıştırılıyor…");
        // Hata kritik değil, uyar ve devam et
        match run_chroot(&self.mount, &["hwclock", "--systohc"]).await {
            Ok(_) => ui.log("hwclock senkronize edildi."),
            Err(e) => ui.log(format!("⚠ hwclock uyarısı (kritik değil): {}", e)),
        }

        Ok(())
    }
}

/// NTP ve manuel tarih/saat yapılandırması.
pub struct ConfigureDateTimeJob {
    pub mount:         String,
    pub use_ntp:       bool,
    pub year:          i32,
    pub month:         u32,
    pub day:           u32,
    pub hour:          u32,
    pub minute:        u32,
}

#[async_trait::async_trait]
impl Job for ConfigureDateTimeJob {
    fn name(&self) -> &str { "job_datetime" }

    async fn run(&self, ui: &UiSender) -> Result<(), String> {
        if self.use_ntp {
            ui.log("NTP etkinleştiriliyor…");
            // ntpd servisini başlat
            let _ = run_chroot(&self.mount, &["service", "ntpd", "start"]).await;
        } else {
            ui.log("Manuel tarih/saat ayarlanıyor…");
            let date_str = format!(
                "{:04}-{:02}-{:02} {:02}:{:02}:00",
                self.year, self.month, self.day, self.hour, self.minute
            );
            let _ = run_chroot(&self.mount, &["date", "-s", &date_str]).await;
            let _ = run_chroot(&self.mount, &["hwclock", "--systohc"]).await;
        }
        Ok(())
    }
}
