use eframe::egui;
use rust_i18n::t;
use crate::installer::{GlobalState, InstallerStep};

pub struct LocationStep {
    pub regions: Vec<String>,
    pub zones_by_region: std::collections::HashMap<String, Vec<String>>,
    pub geoip_done: bool,
    pub datetime_init_done: bool,
}

fn load_timezones() -> Vec<String> {
    if let Ok(out) = std::process::Command::new("timedatectl")
        .args(["list-timezones"])
        .output()
    {
        if out.status.success() {
            let text = String::from_utf8_lossy(&out.stdout);
            let zones: Vec<String> = text
                .lines()
                .map(|l| l.trim().to_string())
                .filter(|l| !l.is_empty())
                .collect();
            if !zones.is_empty() {
                return zones;
            }
        }
    }
    if let Ok(text) = std::fs::read_to_string("/usr/share/zoneinfo/zone.tab") {
        let zones: Vec<String> = text
            .lines()
            .filter(|l| !l.starts_with('#') && !l.trim().is_empty())
            .filter_map(|l| l.split('\t').nth(2))
            .map(|s| s.to_string())
            .collect();
        if !zones.is_empty() {
            return zones;
        }
    }
    vec![
        "Africa/Cairo", "Africa/Casablanca", "Africa/Johannesburg", "Africa/Lagos",
        "Africa/Nairobi", "America/Argentina/Buenos_Aires", "America/Bogota",
        "America/Caracas", "America/Chicago", "America/Denver", "America/Lima",
        "America/Los_Angeles", "America/Mexico_City", "America/New_York",
        "America/Panama", "America/Sao_Paulo", "America/Santiago", "America/Toronto",
        "America/Vancouver", "Asia/Almaty", "Asia/Baghdad", "Asia/Baku",
        "Asia/Bangkok", "Asia/Dubai", "Asia/Ho_Chi_Minh", "Asia/Hong_Kong",
        "Asia/Istanbul", "Asia/Jakarta", "Asia/Jerusalem", "Asia/Kabul",
        "Asia/Karachi", "Asia/Kathmandu", "Asia/Kolkata", "Asia/Kuala_Lumpur",
        "Asia/Manila", "Asia/Riyadh", "Asia/Seoul", "Asia/Shanghai",
        "Asia/Singapore", "Asia/Taipei", "Asia/Tashkent", "Asia/Tehran",
        "Asia/Tokyo", "Asia/Yangon", "Australia/Adelaide", "Australia/Brisbane",
        "Australia/Melbourne", "Australia/Perth", "Australia/Sydney",
        "Europe/Amsterdam", "Europe/Athens", "Europe/Berlin", "Europe/Brussels",
        "Europe/Bucharest", "Europe/Copenhagen", "Europe/Dublin",
        "Europe/Helsinki", "Europe/Istanbul", "Europe/Kyiv", "Europe/Lisbon",
        "Europe/London", "Europe/Madrid", "Europe/Moscow", "Europe/Oslo",
        "Europe/Paris", "Europe/Prague", "Europe/Rome", "Europe/Stockholm",
        "Europe/Vienna", "Europe/Warsaw", "Europe/Zurich",
        "Pacific/Auckland", "Pacific/Fiji", "Pacific/Honolulu",
        "Pacific/Port_Moresby",
    ].iter().map(|s| s.to_string()).collect()
}

fn build_tz_data(zones: &[String]) -> (Vec<String>, std::collections::HashMap<String, Vec<String>>) {
    let mut regions_set = std::collections::BTreeSet::new();
    let mut zones_by_region: std::collections::HashMap<String, Vec<String>> = std::collections::HashMap::new();

    for tz in zones {
        if let Some(slash) = tz.find('/') {
            let region = tz[..slash].to_string();
            let zone = tz[slash + 1..].to_string();
            regions_set.insert(region.clone());
            zones_by_region.entry(region).or_default().push(zone);
        }
    }

    for zones in zones_by_region.values_mut() {
        zones.sort();
    }

    let regions: Vec<String> = regions_set.into_iter().collect();
    (regions, zones_by_region)
}

impl Default for LocationStep {
    fn default() -> Self {
        let all_zones = load_timezones();
        let (regions, zones_by_region) = build_tz_data(&all_zones);
        Self {
            regions,
            zones_by_region,
            geoip_done: false,
            datetime_init_done: false,
        }
    }
}

impl LocationStep {
    fn geoip_lookup(state: &mut GlobalState) {
        let out = std::process::Command::new("curl")
            .args(["-s", "--connect-timeout", "3", "http://ip-api.com/json"])
            .output();
        if let Ok(o) = out {
            if let Ok(text) = String::from_utf8(o.stdout) {
                let extract = |key: &str| -> Option<String> {
                    let pat = format!("\"{}\":\"", key);
                    text.find(&pat).and_then(|pos| {
                        let start = pos + pat.len();
                        text[start..].find('"').map(|end| text[start..start+end].to_string())
                    })
                };
                if let Some(country) = extract("countryCode") {
                    match country.as_str() {
                        "TR" => state.language = "tr".to_string(),
                        "DE" => state.language = "de".to_string(),
                        "FR" => state.language = "fr".to_string(),
                        "IT" => state.language = "it".to_string(),
                        "ES" => state.language = "es".to_string(),
                        "RU" => state.language = "ru".to_string(),
                        "NL" => state.language = "nl".to_string(),
                        "PL" => state.language = "pl".to_string(),
                        _ => {}
                    }
                }
                if let Some(tz) = extract("timezone") {
                    if !tz.is_empty() {
                        state.timezone = tz;
                    }
                }
            }
        }
    }

    fn init_from_system(&mut self, state: &mut GlobalState) {
        use chrono::{Datelike, Timelike};
        let now_str = chrono::Local::now().format("%Y-%m-%d %H:%M").to_string();
        if let Ok(dt) = chrono::NaiveDateTime::parse_from_str(&now_str, "%Y-%m-%d %H:%M") {
            state.manual_year   = dt.year();
            state.manual_month  = dt.month();
            state.manual_day    = dt.day();
            state.manual_hour   = dt.hour();
            state.manual_minute = dt.minute();
        }
        self.datetime_init_done = true;
    }

    fn split_tz(tz: &str) -> (String, String) {
        if let Some(slash) = tz.find('/') {
            (tz[..slash].to_string(), tz[slash + 1..].to_string())
        } else {
            ("Other".to_string(), tz.to_string())
        }
    }
}

impl InstallerStep for LocationStep {
    fn name(&self) -> String {
        format!("{} / {}", t!("location"), t!("datetime"))
    }

    fn on_enter(&mut self, state: &mut GlobalState) {
        if !self.geoip_done {
            Self::geoip_lookup(state);
            self.geoip_done = true;
        }
        if !self.datetime_init_done {
            self.init_from_system(state);
        }
        if state.timezone.is_empty() {
            state.timezone = "Europe/Istanbul".to_string();
        }
    }

    fn show(&mut self, ui: &mut egui::Ui, state: &mut GlobalState) {
        use crate::ui::theme;

        theme::section_heading(ui, &t!("location_title"));
        ui.label(
            egui::RichText::new(t!("location_description"))
                .color(theme::c_text_dim())
                .size(13.0),
        );
        ui.add_space(8.0);

        let (mut cur_region, mut cur_zone) = Self::split_tz(&state.timezone);

        if !self.regions.contains(&cur_region) {
            if let Some(first) = self.regions.first() {
                cur_region = first.clone();
                if let Some(zones) = self.zones_by_region.get(&cur_region) {
                    cur_zone = zones.first().cloned().unwrap_or_default();
                }
                state.timezone = format!("{}/{}", cur_region, cur_zone);
            }
        }

        ui.horizontal(|ui| {
            ui.vertical(|ui| {
                ui.add_space(6.0);
                ui.label(egui::RichText::new(t!("region")).strong().color(theme::c_text()));
            });
            ui.add_space(4.0);

            let rw = 140.0_f32.min(ui.available_width() / 3.0);
            let region_text = cur_region.clone();
            theme::show_combo_box(ui, "tz_region_select", region_text.as_str(), rw, |ui, w| {
                for region in &self.regions {
                    if theme::selectable_value(ui, &mut cur_region, region.clone(), region.as_str(), w).clicked() {
                        if let Some(zones) = self.zones_by_region.get(&cur_region) {
                            cur_zone = zones.first().cloned().unwrap_or_default();
                        }
                        state.timezone = format!("{}/{}", cur_region, cur_zone);
                    }
                }
            });

            ui.add_space(16.0);

            ui.vertical(|ui| {
                ui.add_space(6.0);
                ui.label(egui::RichText::new(t!("timezone")).strong().color(theme::c_text()));
            });
            ui.add_space(4.0);

            let zw = ui.available_width().max(160.0);
            if let Some(zones) = self.zones_by_region.get(&cur_region) {
                if !zones.contains(&cur_zone) {
                    cur_zone = zones.first().cloned().unwrap_or_default();
                    state.timezone = format!("{}/{}", cur_region, cur_zone);
                }
                let zone_text = cur_zone.clone();
                theme::show_combo_box(ui, "tz_zone_select", zone_text.as_str(), zw, |ui, w| {
                    for zone in zones {
                        if theme::selectable_value(ui, &mut cur_zone, zone.clone(), zone.as_str(), w).clicked() {
                            state.timezone = format!("{}/{}", cur_region, cur_zone);
                        }
                    }
                });
            }
        });

        ui.add_space(16.0);
        ui.separator();
        ui.add_space(16.0);

        theme::section_heading(ui, &t!("datetime_title"));
        ui.label(
            egui::RichText::new(t!("datetime_description"))
                .color(theme::c_text_dim())
                .size(13.0),
        );
        ui.add_space(8.0);

        egui::Frame::group(ui.style())        
            .rounding(6.0)
            .inner_margin(egui::Margin::same(12.0))
            .show(ui, |ui| {
                ui.set_width(ui.available_width());
                egui::Grid::new("datetime_grid")
                    .num_columns(2)
                    .spacing([12.0, 10.0])
                    .show(ui, |ui| {
                        ui.label(egui::RichText::new(t!("datetime_ntp_label")).strong().color(theme::c_text()));
                        ui.horizontal(|ui| {
                            ui.add(egui::Checkbox::new(&mut state.use_ntp, ""));
                            let status = if state.use_ntp { t!("datetime_ntp_on") } else { t!("datetime_ntp_off") };
                            ui.colored_label(
                                if state.use_ntp { theme::c_success() } else { theme::c_error() },
                                status,
                            );
                        });
                        ui.end_row();

                        if !state.use_ntp {
                            ui.label(egui::RichText::new(t!("datetime_date_label")).strong().color(theme::c_text()));
                            ui.horizontal(|ui| {
                                ui.label(t!("datetime_year"));
                                ui.add(egui::DragValue::new(&mut state.manual_year).clamp_range(2000..=2100).speed(1));
                                ui.label(t!("datetime_month"));
                                ui.add(egui::DragValue::new(&mut state.manual_month).clamp_range(1..=12).speed(1));
                                ui.label(t!("datetime_day"));
                                ui.add(egui::DragValue::new(&mut state.manual_day).clamp_range(1..=31).speed(1));
                            });
                            ui.end_row();

                            ui.label(egui::RichText::new(t!("datetime_time_label")).strong().color(theme::c_text()));
                            ui.horizontal(|ui| {
                                ui.add(egui::DragValue::new(&mut state.manual_hour).clamp_range(0..=23).speed(1));
                                ui.label(":");
                                ui.add(egui::DragValue::new(&mut state.manual_minute).clamp_range(0..=59).speed(1));
                            });
                            ui.end_row();
                        }
                    });
            });

        ui.add_space(8.0);
        if state.use_ntp {
            ui.label(
                egui::RichText::new(t!("datetime_ntp_info"))
                    .size(11.0)
                    .color(theme::c_text_dim()),
            );
        } else {
            ui.label(
                egui::RichText::new(t!("datetime_manual_info"))
                    .size(11.0)
                    .color(theme::c_text_dim()),
            );
        }
    }

    fn is_complete(&self, state: &GlobalState) -> bool {
        !state.timezone.is_empty()
    }
}
