use adw::prelude::*;
use outlay_core::db::Database;
use std::rc::Rc;

pub struct GoalsView {
    pub container: gtk::Box,
}

impl GoalsView {
    pub fn new(db: Rc<Database>) -> Self {
        let container = gtk::Box::new(gtk::Orientation::Vertical, 0);
        let toast_overlay = adw::ToastOverlay::new();

        let clamp = adw::Clamp::new();
        clamp.set_maximum_size(700);
        clamp.set_margin_start(16);
        clamp.set_margin_end(16);

        let inner = gtk::Box::new(gtk::Orientation::Vertical, 20);
        inner.set_margin_top(20);
        inner.set_margin_bottom(20);

        let active_group = adw::PreferencesGroup::builder()
            .title("SAVINGS GOALS")
            .build();

        let completed_group = adw::PreferencesGroup::builder()
            .title("COMPLETED")
            .build();
        completed_group.set_visible(false);

        let add_btn = gtk::Button::with_label("Add Goal");
        add_btn.add_css_class("suggested-action");
        add_btn.add_css_class("pill");
        add_btn.set_halign(gtk::Align::Center);
        add_btn.set_margin_top(8);

        Self::load_goals(&db, &active_group, &completed_group, &toast_overlay);

        {
            let db_ref = db.clone();
            let active_ref = active_group.clone();
            let completed_ref = completed_group.clone();
            let toast_ref = toast_overlay.clone();
            add_btn.connect_clicked(move |btn| {
                Self::show_add_dialog(btn, &db_ref, &active_ref, &completed_ref, &toast_ref);
            });
        }

        inner.append(&active_group);
        inner.append(&add_btn);
        inner.append(&completed_group);

        clamp.set_child(Some(&inner));

        let scroll = gtk::ScrolledWindow::builder()
            .hscrollbar_policy(gtk::PolicyType::Never)
            .vexpand(true)
            .child(&clamp)
            .build();

        toast_overlay.set_child(Some(&scroll));
        container.append(&toast_overlay);

        GoalsView { container }
    }

    fn load_goals(
        db: &Rc<Database>,
        active_group: &adw::PreferencesGroup,
        completed_group: &adw::PreferencesGroup,
        toast_overlay: &adw::ToastOverlay,
    ) {
        Self::clear_group(active_group);
        Self::clear_group(completed_group);

        let goals = db.list_goals().unwrap_or_default();
        let mut has_completed = false;

        let base_currency = db
            .get_setting("base_currency")
            .ok()
            .flatten()
            .unwrap_or_else(|| "USD".to_string());

        for goal in &goals {
            let pct = if goal.target > 0.0 {
                (goal.saved / goal.target * 100.0).min(100.0)
            } else {
                0.0
            };
            let is_complete = goal.saved >= goal.target;

            let remaining = goal.target - goal.saved;
            let subtitle = if is_complete {
                format!("Completed - {:.2} {}", goal.target, goal.currency)
            } else {
                let mut parts = vec![
                    format!("{:.2} / {:.2} {} ({:.0}%)", goal.saved, goal.target, goal.currency, pct),
                ];
                if remaining > 0.0 {
                    parts.push(format!("{:.2} remaining", remaining));
                }
                if let Some(deadline) = goal.deadline {
                    let today = chrono::Local::now().date_naive();
                    let days_left = (deadline - today).num_days();
                    if days_left > 0 {
                        parts.push(format!("{} days left", days_left));
                    } else if days_left == 0 {
                        parts.push("Due today".to_string());
                    } else {
                        parts.push(format!("{} days overdue", days_left.abs()));
                    }
                }
                // Monthly amount needed
                if let Ok(Some(monthly)) = db.get_required_monthly(goal.id) {
                    if monthly > 0.0 {
                        parts.push(format!("Need {:.2}/month", monthly));
                    }
                }
                // Projection based on average contribution rate
                if let Ok(avg_rate) = db.get_goal_avg_monthly_contribution(goal.id) {
                    if avg_rate > 0.0 && remaining > 0.0 {
                        let months_remaining = (remaining / avg_rate).ceil() as i32;
                        let today = chrono::Local::now().date_naive();
                        let projected = today + chrono::Months::new(months_remaining as u32);
                        if let Some(deadline) = goal.deadline {
                            let margin_days = (deadline - projected).num_days();
                            if margin_days >= 0 {
                                let margin_months = margin_days / 30;
                                parts.push(format!("On track - ~{} month{} ahead", margin_months, if margin_months == 1 { "" } else { "s" }));
                            } else {
                                let catch_up = remaining / ((deadline - today).num_days().max(1) as f64 / 30.0);
                                parts.push(format!("Behind - need {:.2}/month to catch up", catch_up));
                            }
                        } else {
                            parts.push(format!("Reachable by {}", projected.format("%b %Y")));
                        }
                    } else if remaining > 0.0 {
                        parts.push("Start contributing to see projection".to_string());
                    }
                }
                parts.join(" - ")
            };

            let row = adw::ActionRow::builder()
                .title(&goal.name)
                .subtitle(&subtitle)
                .activatable(true)
                .build();

            // Progress bar
            let level = gtk::LevelBar::builder()
                .min_value(0.0)
                .max_value(1.0)
                .value(pct / 100.0)
                .hexpand(true)
                .valign(gtk::Align::Center)
                .build();
            level.set_width_request(120);

            if is_complete {
                let check = gtk::Image::from_icon_name("object-select-symbolic");
                check.add_css_class("success");
                row.add_prefix(&check);
            } else if let Some(ref icon_name) = goal.icon {
                let icon = gtk::Image::from_icon_name(icon_name);
                icon.set_pixel_size(24);
                row.add_prefix(&icon);
            }

            let suffix_box = gtk::Box::new(gtk::Orientation::Horizontal, 8);
            suffix_box.set_valign(gtk::Align::Center);

            if !is_complete {
                let contribute_btn = gtk::Button::from_icon_name("list-add-symbolic");
                contribute_btn.add_css_class("flat");
                contribute_btn.set_tooltip_text(Some("Add funds"));
                contribute_btn.set_valign(gtk::Align::Center);

                let goal_id = goal.id;
                let db_contribute = db.clone();
                let active_c = active_group.clone();
                let completed_c = completed_group.clone();
                let toast_c = toast_overlay.clone();
                let currency = goal.currency.clone();
                contribute_btn.connect_clicked(move |btn| {
                    Self::show_contribute_dialog(
                        btn, goal_id, &currency,
                        &db_contribute, &active_c, &completed_c, &toast_c,
                    );
                });
                suffix_box.append(&contribute_btn);
            }

            suffix_box.append(&level);
            row.add_suffix(&suffix_box);

            // Click to edit
            let goal_id = goal.id;
            let db_edit = db.clone();
            let active_e = active_group.clone();
            let completed_e = completed_group.clone();
            let toast_e = toast_overlay.clone();
            row.connect_activated(move |row| {
                Self::show_edit_dialog(
                    row, goal_id,
                    &db_edit, &active_e, &completed_e, &toast_e,
                );
            });

            if is_complete {
                completed_group.add(&row);
                has_completed = true;
            } else {
                active_group.add(&row);
            }
        }

        completed_group.set_visible(has_completed);

        if goals.iter().all(|g| g.saved >= g.target) && !goals.is_empty() {
            // All goals completed - no empty state needed
        } else if goals.iter().filter(|g| g.saved < g.target).count() == 0 && goals.is_empty() {
            let empty_row = adw::ActionRow::builder()
                .title("No savings goals yet")
                .subtitle("Set a goal and track your progress")
                .activatable(false)
                .build();
            empty_row.add_css_class("dim-label");
            active_group.add(&empty_row);
        }
    }

    fn show_add_dialog(
        parent: &gtk::Button,
        db: &Rc<Database>,
        active_group: &adw::PreferencesGroup,
        completed_group: &adw::PreferencesGroup,
        toast_overlay: &adw::ToastOverlay,
    ) {
        let dialog = adw::Dialog::builder()
            .title("Add Savings Goal")
            .content_width(360)
            .content_height(350)
            .build();

        let toolbar = adw::ToolbarView::new();
        toolbar.add_top_bar(&adw::HeaderBar::new());

        let content = gtk::Box::new(gtk::Orientation::Vertical, 16);
        content.set_margin_top(16);
        content.set_margin_bottom(16);
        content.set_margin_start(16);
        content.set_margin_end(16);

        let name_row = adw::EntryRow::builder()
            .title("Goal Name")
            .build();

        let target_row = adw::EntryRow::builder()
            .title("Target Amount")
            .build();
        target_row.set_input_purpose(gtk::InputPurpose::Number);
        crate::numpad::attach_numpad(&target_row);

        let base_currency = db
            .get_setting("base_currency")
            .ok()
            .flatten()
            .unwrap_or_else(|| "USD".to_string());

        let (deadline_row, deadline_label) = crate::date_picker::make_date_row("Deadline (optional)", "");

        let form = adw::PreferencesGroup::new();
        form.add(&name_row);
        form.add(&target_row);
        form.add(&deadline_row);

        let save_btn = gtk::Button::with_label("Save");
        save_btn.add_css_class("suggested-action");
        save_btn.add_css_class("pill");
        save_btn.set_halign(gtk::Align::Center);

        content.append(&form);
        content.append(&save_btn);
        toolbar.set_content(Some(&content));
        dialog.set_child(Some(&toolbar));

        {
            let db_ref = db.clone();
            let dialog_ref = dialog.clone();
            let active_ref = active_group.clone();
            let completed_ref = completed_group.clone();
            let toast_ref = toast_overlay.clone();
            let bc = base_currency.clone();
            save_btn.connect_clicked(move |_| {
                let name = name_row.text();
                if name.is_empty() {
                    let toast = adw::Toast::new("Please enter a goal name");
                    toast_ref.add_toast(toast);
                    return;
                }
                let target: f64 = match target_row.text().trim().parse() {
                    Ok(v) if v > 0.0 => v,
                    _ => {
                        let toast = adw::Toast::new("Please enter a valid target amount");
                        toast_ref.add_toast(toast);
                        return;
                    }
                };
                let deadline_text = deadline_label.label();
                let deadline = if deadline_text.is_empty() {
                    None
                } else {
                    chrono::NaiveDate::parse_from_str(deadline_text.trim(), "%Y-%m-%d").ok()
                };

                match db_ref.insert_goal(&name, target, &bc, deadline, None, None) {
                    Ok(_) => {
                        dialog_ref.close();
                        let toast = adw::Toast::new("Goal created");
                        toast_ref.add_toast(toast);
                        Self::load_goals(&db_ref, &active_ref, &completed_ref, &toast_ref);
                    }
                    Err(e) => {
                        let toast = adw::Toast::new(&format!("Error: {}", e));
                        toast_ref.add_toast(toast);
                    }
                }
            });
        }

        dialog.present(Some(parent));
    }

    fn show_contribute_dialog(
        parent: &gtk::Button,
        goal_id: i64,
        currency: &str,
        db: &Rc<Database>,
        active_group: &adw::PreferencesGroup,
        completed_group: &adw::PreferencesGroup,
        toast_overlay: &adw::ToastOverlay,
    ) {
        let dialog = adw::Dialog::builder()
            .title("Add Funds")
            .content_width(320)
            .content_height(180)
            .build();

        let toolbar = adw::ToolbarView::new();
        toolbar.add_top_bar(&adw::HeaderBar::new());

        let content = gtk::Box::new(gtk::Orientation::Vertical, 16);
        content.set_margin_top(16);
        content.set_margin_bottom(16);
        content.set_margin_start(16);
        content.set_margin_end(16);

        let amount_row = adw::EntryRow::builder()
            .title(&format!("Amount ({})", currency))
            .build();
        amount_row.set_input_purpose(gtk::InputPurpose::Number);
        crate::numpad::attach_numpad(&amount_row);

        let form = adw::PreferencesGroup::new();
        form.add(&amount_row);

        let save_btn = gtk::Button::with_label("Add");
        save_btn.add_css_class("suggested-action");
        save_btn.add_css_class("pill");
        save_btn.set_halign(gtk::Align::Center);

        content.append(&form);
        content.append(&save_btn);
        toolbar.set_content(Some(&content));
        dialog.set_child(Some(&toolbar));

        {
            let db_ref = db.clone();
            let dialog_ref = dialog.clone();
            let active_ref = active_group.clone();
            let completed_ref = completed_group.clone();
            let toast_ref = toast_overlay.clone();
            save_btn.connect_clicked(move |_| {
                let amount: f64 = match amount_row.text().trim().parse() {
                    Ok(v) if v > 0.0 => v,
                    _ => {
                        let toast = adw::Toast::new("Please enter a valid amount");
                        toast_ref.add_toast(toast);
                        return;
                    }
                };

                match db_ref.contribute_to_goal(goal_id, amount) {
                    Ok(()) => {
                        dialog_ref.close();
                        let toast = adw::Toast::new(&format!("Added {:.2}", amount));
                        toast_ref.add_toast(toast);
                        Self::load_goals(&db_ref, &active_ref, &completed_ref, &toast_ref);
                    }
                    Err(e) => {
                        let toast = adw::Toast::new(&format!("Error: {}", e));
                        toast_ref.add_toast(toast);
                    }
                }
            });
        }

        dialog.present(Some(parent));
    }

    fn show_edit_dialog(
        parent: &adw::ActionRow,
        goal_id: i64,
        db: &Rc<Database>,
        active_group: &adw::PreferencesGroup,
        completed_group: &adw::PreferencesGroup,
        toast_overlay: &adw::ToastOverlay,
    ) {
        let goal = match db.get_goal(goal_id) {
            Ok(g) => g,
            Err(_) => return,
        };

        let dialog = adw::Dialog::builder()
            .title("Edit Goal")
            .content_width(360)
            .content_height(350)
            .build();

        let toolbar = adw::ToolbarView::new();
        toolbar.add_top_bar(&adw::HeaderBar::new());

        let content = gtk::Box::new(gtk::Orientation::Vertical, 16);
        content.set_margin_top(16);
        content.set_margin_bottom(16);
        content.set_margin_start(16);
        content.set_margin_end(16);

        let name_row = adw::EntryRow::builder()
            .title("Goal Name")
            .text(&goal.name)
            .build();

        let target_row = adw::EntryRow::builder()
            .title("Target Amount")
            .text(&format!("{:.2}", goal.target))
            .build();
        target_row.set_input_purpose(gtk::InputPurpose::Number);
        crate::numpad::attach_numpad(&target_row);

        let initial_deadline = goal.deadline
            .map(|d| d.format("%Y-%m-%d").to_string())
            .unwrap_or_default();
        let (deadline_row, deadline_label) = crate::date_picker::make_date_row("Deadline (optional)", &initial_deadline);

        let form = adw::PreferencesGroup::new();
        form.add(&name_row);
        form.add(&target_row);
        form.add(&deadline_row);

        let btn_box = gtk::Box::new(gtk::Orientation::Horizontal, 12);
        btn_box.set_halign(gtk::Align::Center);

        let delete_btn = gtk::Button::with_label("Delete");
        delete_btn.add_css_class("destructive-action");
        delete_btn.add_css_class("pill");

        let save_btn = gtk::Button::with_label("Save");
        save_btn.add_css_class("suggested-action");
        save_btn.add_css_class("pill");

        btn_box.append(&delete_btn);
        btn_box.append(&save_btn);

        content.append(&form);
        content.append(&btn_box);
        toolbar.set_content(Some(&content));
        dialog.set_child(Some(&toolbar));

        {
            let db_ref = db.clone();
            let dialog_ref = dialog.clone();
            let active_ref = active_group.clone();
            let completed_ref = completed_group.clone();
            let toast_ref = toast_overlay.clone();
            let currency = goal.currency.clone();
            save_btn.connect_clicked(move |_| {
                let name = name_row.text();
                if name.is_empty() {
                    let toast = adw::Toast::new("Please enter a goal name");
                    toast_ref.add_toast(toast);
                    return;
                }
                let target: f64 = match target_row.text().trim().parse() {
                    Ok(v) if v > 0.0 => v,
                    _ => {
                        let toast = adw::Toast::new("Please enter a valid target amount");
                        toast_ref.add_toast(toast);
                        return;
                    }
                };
                let deadline_text = deadline_label.label();
                let deadline = if deadline_text.is_empty() {
                    None
                } else {
                    chrono::NaiveDate::parse_from_str(deadline_text.trim(), "%Y-%m-%d").ok()
                };

                match db_ref.update_goal(goal_id, &name, target, &currency, deadline, None, None) {
                    Ok(()) => {
                        dialog_ref.close();
                        let toast = adw::Toast::new("Goal updated");
                        toast_ref.add_toast(toast);
                        Self::load_goals(&db_ref, &active_ref, &completed_ref, &toast_ref);
                    }
                    Err(e) => {
                        let toast = adw::Toast::new(&format!("Error: {}", e));
                        toast_ref.add_toast(toast);
                    }
                }
            });
        }

        {
            let db_ref = db.clone();
            let dialog_ref = dialog.clone();
            let active_ref = active_group.clone();
            let completed_ref = completed_group.clone();
            let toast_ref = toast_overlay.clone();
            delete_btn.connect_clicked(move |btn| {
                let alert = adw::AlertDialog::new(
                    Some("Delete this goal?"),
                    Some("This will permanently remove this savings goal."),
                );
                alert.add_response("cancel", "Cancel");
                alert.add_response("delete", "Delete");
                alert.set_response_appearance("delete", adw::ResponseAppearance::Destructive);
                alert.set_default_response(Some("cancel"));
                alert.set_close_response("cancel");

                let db_del = db_ref.clone();
                let dialog_del = dialog_ref.clone();
                let active_del = active_ref.clone();
                let completed_del = completed_ref.clone();
                let toast_del = toast_ref.clone();
                alert.connect_response(None, move |_, response| {
                    if response == "delete" {
                        match db_del.delete_goal(goal_id) {
                            Ok(()) => {
                                dialog_del.close();
                                let toast = adw::Toast::new("Goal deleted");
                                toast_del.add_toast(toast);
                                Self::load_goals(&db_del, &active_del, &completed_del, &toast_del);
                            }
                            Err(e) => {
                                let toast = adw::Toast::new(&format!("Error: {}", e));
                                toast_del.add_toast(toast);
                            }
                        }
                    }
                });

                alert.present(Some(btn));
            });
        }

        dialog.present(Some(parent));
    }

    fn clear_group(group: &adw::PreferencesGroup) {
        let mut rows = Vec::new();
        let mut child = group.upcast_ref::<gtk::Widget>().first_child();
        while let Some(c) = child {
            if let Some(row) = c.downcast_ref::<adw::ActionRow>() {
                rows.push(row.clone());
            }
            let mut inner = c.first_child();
            while let Some(ic) = inner {
                if let Some(row) = ic.downcast_ref::<adw::ActionRow>() {
                    rows.push(row.clone());
                }
                let mut inner2 = ic.first_child();
                while let Some(ic2) = inner2 {
                    if let Some(row) = ic2.downcast_ref::<adw::ActionRow>() {
                        rows.push(row.clone());
                    }
                    inner2 = ic2.next_sibling();
                }
                inner = ic.next_sibling();
            }
            child = c.next_sibling();
        }
        for row in &rows {
            group.remove(row);
        }
    }
}
