use adw::prelude::*;
use chrono::Datelike;
use gtk::{gdk, glib};
use outlay_core::db::Database;
use std::cell::Cell;
use std::rc::Rc;

use crate::budgets_view::BudgetsView;
use crate::icon_theme;
use crate::charts_view::ChartsView;
use crate::credit_cards_view::CreditCardsView;
use crate::forecast_view::ForecastView;
use crate::insights_view::InsightsView;
use crate::goals_view::GoalsView;
use crate::history_view::HistoryView;
use crate::log_view::LogView;
use crate::recurring_view::RecurringView;
use crate::settings_view::SettingsView;
use crate::subscriptions_view::SubscriptionsView;
use crate::wishlist_view::WishlistView;

pub struct MainWindow {
    pub window: adw::ApplicationWindow,
    pub log_view: Rc<LogView>,
    pub history_view: Rc<HistoryView>,
    pub charts_view: Rc<ChartsView>,
    pub budgets_view: Rc<BudgetsView>,
    pub insights_view: Rc<InsightsView>,
    sidebar_list: gtk::ListBox,
    content_stack: gtk::Stack,
    content_page: adw::NavigationPage,
}

struct SidebarItem {
    id: &'static str,
    label: &'static str,
    icon: &'static str,
    color: &'static str, // CSS color visible in both light and dark modes
}

struct SidebarSection {
    label: &'static str,
    items: &'static [SidebarItem],
}

const SIDEBAR_SECTIONS: &[SidebarSection] = &[
    SidebarSection {
        label: "TRACKING",
        items: &[
            SidebarItem { id: "log",     label: "Log",     icon: "outlay-log",     color: "#4dabf7" },
            SidebarItem { id: "history", label: "History", icon: "outlay-history", color: "#9775fa" },
            SidebarItem { id: "charts",  label: "Charts",  icon: "outlay-charts",  color: "#ff8787" },
        ],
    },
    SidebarSection {
        label: "PLANNING",
        items: &[
            SidebarItem { id: "budgets",  label: "Budgets",  icon: "outlay-budgets",  color: "#69db7c" },
            SidebarItem { id: "goals",    label: "Goals",    icon: "outlay-goals",    color: "#ffd43b" },
            SidebarItem { id: "forecast", label: "Forecast", icon: "outlay-forecast", color: "#74c0fc" },
        ],
    },
    SidebarSection {
        label: "MANAGEMENT",
        items: &[
            SidebarItem { id: "recurring",     label: "Recurring",     icon: "outlay-recurring",     color: "#38d9a9" },
            SidebarItem { id: "subscriptions", label: "Subscriptions", icon: "outlay-subscriptions", color: "#e599f7" },
            SidebarItem { id: "wishlist",      label: "Wishlist",      icon: "outlay-wishlist",      color: "#ffa94d" },
            SidebarItem { id: "creditcards",   label: "Credit Cards",  icon: "outlay-creditcards",   color: "#a9e34b" },
            SidebarItem { id: "insights",      label: "Insights",      icon: "outlay-insights",      color: "#f783ac" },
        ],
    },
];

const SETTINGS_ITEM: SidebarItem = SidebarItem { id: "settings", label: "Settings", icon: "outlay-settings", color: "#adb5bd" };

fn all_sidebar_items() -> Vec<&'static SidebarItem> {
    SIDEBAR_SECTIONS.iter().flat_map(|s| s.items.iter()).collect()
}

impl MainWindow {
    pub fn new(app: &adw::Application, db: Rc<Database>) -> Self {
        let content_stack = gtk::Stack::new();
        content_stack.set_transition_type(gtk::StackTransitionType::Crossfade);

        // Log view
        let log_view = Rc::new(LogView::new(db.clone(), app));
        let log_scroll = gtk::ScrolledWindow::builder()
            .hscrollbar_policy(gtk::PolicyType::Never)
            .child(&log_view.container)
            .build();
        log_view.toast_overlay.set_child(Some(&log_scroll));
        content_stack.add_named(&log_view.toast_overlay, Some("log"));

        // History view
        let history_view = HistoryView::new(db.clone());
        let history_scroll = gtk::ScrolledWindow::builder()
            .hscrollbar_policy(gtk::PolicyType::Never)
            .child(&history_view.container)
            .build();
        content_stack.add_named(&history_scroll, Some("history"));

        // Charts view
        let charts_view = ChartsView::new(db.clone());
        content_stack.add_named(&charts_view.container, Some("charts"));

        // Budgets view
        let budgets_view = BudgetsView::new(db.clone());
        content_stack.add_named(&budgets_view.container, Some("budgets"));

        // Goals view
        let goals_view = GoalsView::new(db.clone());
        content_stack.add_named(&goals_view.container, Some("goals"));

        // Recurring view
        let recurring_view = Rc::new(RecurringView::new(db.clone()));
        content_stack.add_named(&recurring_view.container, Some("recurring"));

        // Subscriptions view
        let subscriptions_view = Rc::new(SubscriptionsView::new(db.clone()));
        content_stack.add_named(&subscriptions_view.container, Some("subscriptions"));

        // Cross-view refresh: changes in subscriptions refresh recurring and vice versa
        {
            let rec_ref = recurring_view.clone();
            subscriptions_view.set_on_change(move || {
                rec_ref.refresh();
            });
        }
        {
            let sub_ref = subscriptions_view.clone();
            recurring_view.set_on_change(move || {
                sub_ref.refresh();
            });
        }

        // Wishlist view
        let wishlist_view = WishlistView::new(db.clone());
        content_stack.add_named(&wishlist_view.container, Some("wishlist"));

        // Forecast view
        let forecast_view = ForecastView::new(db.clone());
        content_stack.add_named(&forecast_view.container, Some("forecast"));

        // Insights view
        let insights_view = InsightsView::new(db.clone());
        content_stack.add_named(&insights_view.container, Some("insights"));

        // Credit Cards view
        let credit_cards_view = CreditCardsView::new(db.clone());
        content_stack.add_named(&credit_cards_view.container, Some("creditcards"));

        // Settings view
        let settings_view = SettingsView::new(db.clone(), app);
        content_stack.add_named(&settings_view.container, Some("settings"));

        // Main sidebar items (top) - grouped by section with headers
        let sidebar_list = gtk::ListBox::new();
        sidebar_list.set_selection_mode(gtk::SelectionMode::Single);
        sidebar_list.add_css_class("navigation-sidebar");

        let all_items = all_sidebar_items();
        for item in &all_items {
            let row = Self::make_sidebar_row(item);
            sidebar_list.append(&row);
        }

        // Compute section boundary indices: the row index where each section starts
        // TRACKING: 0, PLANNING: 3, MANAGEMENT: 6
        let mut section_starts: Vec<(i32, &'static str)> = Vec::new();
        let mut idx = 0i32;
        for section in SIDEBAR_SECTIONS {
            section_starts.push((idx, section.label));
            idx += section.items.len() as i32;
        }

        sidebar_list.set_header_func(move |row, _before| {
            let ri = row.index();
            for &(start, label) in &section_starts {
                if ri == start {
                    let header_box = gtk::Box::new(gtk::Orientation::Vertical, 0);

                    // Add separator before all sections except the first
                    if start > 0 {
                        let sep = gtk::Separator::new(gtk::Orientation::Horizontal);
                        sep.set_margin_top(6);
                        sep.set_margin_bottom(2);
                        sep.set_margin_start(12);
                        sep.set_margin_end(12);
                        header_box.append(&sep);
                    }

                    let section_label = gtk::Label::new(Some(label));
                    section_label.add_css_class("sidebar-section-label");
                    section_label.set_halign(gtk::Align::Start);
                    header_box.append(&section_label);

                    row.set_header(Some(&header_box));
                    return;
                }
            }
            row.set_header(gtk::Widget::NONE);
        });

        // Settings item (bottom)
        let settings_list = gtk::ListBox::new();
        settings_list.set_selection_mode(gtk::SelectionMode::Single);
        settings_list.add_css_class("navigation-sidebar");
        settings_list.append(&Self::make_sidebar_row(&SETTINGS_ITEM));

        let sidebar_box = gtk::Box::new(gtk::Orientation::Vertical, 0);
        sidebar_list.set_vexpand(true);
        sidebar_box.append(&sidebar_list);
        sidebar_box.append(&gtk::Separator::new(gtk::Orientation::Horizontal));
        sidebar_box.append(&settings_list);

        let sidebar_toolbar = adw::ToolbarView::new();
        sidebar_toolbar.add_top_bar(&adw::HeaderBar::new());
        sidebar_toolbar.set_content(Some(&sidebar_box));

        let sidebar_page = adw::NavigationPage::builder()
            .title("Outlay")
            .child(&sidebar_toolbar)
            .build();

        let content_toolbar = adw::ToolbarView::new();
        content_toolbar.add_top_bar(&adw::HeaderBar::new());
        content_toolbar.set_content(Some(&content_stack));

        let content_page = adw::NavigationPage::builder()
            .title("Log")
            .child(&content_toolbar)
            .build();

        // Wire sidebar selection to switch content, update title, and refresh views
        let history_view_ref = Rc::new(history_view);
        let charts_view_ref = Rc::new(charts_view);
        let budgets_view_ref = Rc::new(budgets_view);
        let insights_view_ref = Rc::new(insights_view);

        // Wire up data reset callback to refresh all views
        {
            let log_ref = log_view.clone();
            let hist_ref = history_view_ref.clone();
            let chart_ref = charts_view_ref.clone();
            let budget_ref = budgets_view_ref.clone();
            let insights_ref = insights_view_ref.clone();
            settings_view.set_on_data_reset(move || {
                log_ref.refresh_categories();
                hist_ref.refresh();
                chart_ref.refresh();
                let today = chrono::Local::now().date_naive();
                budget_ref.set_month(today.year(), today.month());
                insights_ref.refresh();
            });
        }

        // Shared month state for syncing across views
        let shared_month: Rc<Cell<(i32, u32)>> = {
            let today = chrono::Local::now().date_naive();
            Rc::new(Cell::new((today.year(), today.month())))
        };

        // Main list selection - deselect settings
        {
            let content_stack_ref = content_stack.clone();
            let content_page_ref = content_page.clone();
            let history_ref = history_view_ref.clone();
            let charts_ref = charts_view_ref.clone();
            let budgets_ref = budgets_view_ref.clone();
            let log_ref = log_view.clone();
            let insights_ref = insights_view_ref.clone();
            let settings_list_ref = settings_list.clone();
            let shared = shared_month.clone();
            sidebar_list.connect_row_selected(move |_, row| {
                if let Some(row) = row {
                    settings_list_ref.unselect_all();
                    let idx = row.index() as usize;
                    if idx < all_sidebar_items().len() {
                        // Save month from the view we're leaving
                        let current_view = content_stack_ref.visible_child_name();
                        if let Some(ref name) = current_view {
                            let month = match name.as_str() {
                                "history" => Some(history_ref.get_month()),
                                "charts" => Some(charts_ref.get_month()),
                                "budgets" => Some(budgets_ref.get_month()),
                                _ => None,
                            };
                            if let Some(m) = month {
                                shared.set(m);
                            }
                        }

                        content_stack_ref.set_visible_child_name(all_sidebar_items()[idx].id);
                        content_page_ref.set_title(all_sidebar_items()[idx].label);

                        // Sync month to the view we're entering and refresh
                        let (sy, sm) = shared.get();
                        match all_sidebar_items()[idx].id {
                            "log" => log_ref.refresh_categories(),
                            "history" => {
                                history_ref.set_month(sy, sm);
                            }
                            "charts" => {
                                charts_ref.set_month(sy, sm);
                            }
                            "budgets" => {
                                budgets_ref.set_month(sy, sm);
                            }
                            "insights" => {
                                insights_ref.refresh();
                            }
                            _ => {}
                        }
                    }
                }
            });
        }

        // Settings list selection - deselect main list
        {
            let content_stack_ref = content_stack.clone();
            let content_page_ref = content_page.clone();
            let sidebar_list_ref = sidebar_list.clone();
            settings_list.connect_row_selected(move |_, row| {
                if row.is_some() {
                    sidebar_list_ref.unselect_all();
                    content_stack_ref.set_visible_child_name(SETTINGS_ITEM.id);
                    content_page_ref.set_title(SETTINGS_ITEM.label);
                }
            });
        }

        // Select the first row by default
        if let Some(first_row) = sidebar_list.row_at_index(0) {
            sidebar_list.select_row(Some(&first_row));
        }

        let split_view = adw::NavigationSplitView::new();
        split_view.set_sidebar(Some(&sidebar_page));
        split_view.set_content(Some(&content_page));

        // Restore window size from settings
        let saved_width: i32 = db
            .get_setting("window_width")
            .ok()
            .flatten()
            .and_then(|s| s.parse().ok())
            .unwrap_or(900);
        let saved_height: i32 = db
            .get_setting("window_height")
            .ok()
            .flatten()
            .and_then(|s| s.parse().ok())
            .unwrap_or(600);
        let saved_maximized: bool = db
            .get_setting("window_maximized")
            .ok()
            .flatten()
            .map(|s| s == "true")
            .unwrap_or(false);

        let window = adw::ApplicationWindow::builder()
            .application(app)
            .title("Outlay")
            .default_width(saved_width)
            .default_height(saved_height)
            .content(&split_view)
            .build();

        if saved_maximized {
            window.maximize();
        }

        // Hide window on close instead of quitting
        {
            let db_ref = db.clone();
            window.connect_close_request(move |win| {
                let (width, height) = win.default_size();
                db_ref.set_setting("window_width", &width.to_string()).ok();
                db_ref.set_setting("window_height", &height.to_string()).ok();
                db_ref
                    .set_setting("window_maximized", if win.is_maximized() { "true" } else { "false" })
                    .ok();
                win.set_visible(false);
                glib::Propagation::Stop
            });
        }

        // Keyboard shortcuts
        {
            let key_ctrl = gtk::EventControllerKey::new();
            let sidebar_ref = sidebar_list.clone();
            let settings_list_ref = settings_list.clone();
            let content_ref = content_stack.clone();
            let page_ref = content_page.clone();
            let log_ref = log_view.clone();
            let hist_ref = history_view_ref.clone();
            let chart_ref = charts_view_ref.clone();
            let window_ref = window.clone();
            key_ctrl.connect_key_pressed(move |_, key, _, modifier| {
                if !modifier.contains(gdk::ModifierType::CONTROL_MASK) {
                    return glib::Propagation::Proceed;
                }
                match key {
                    gdk::Key::_1 | gdk::Key::_2 | gdk::Key::_3 | gdk::Key::_4 | gdk::Key::_5 | gdk::Key::_6 | gdk::Key::_7 | gdk::Key::_8 | gdk::Key::_9 | gdk::Key::_0 => {
                        let idx = match key {
                            gdk::Key::_1 => 0,
                            gdk::Key::_2 => 1,
                            gdk::Key::_3 => 2,
                            gdk::Key::_4 => 3,
                            gdk::Key::_5 => 4,
                            gdk::Key::_6 => 5,
                            gdk::Key::_7 => 6,
                            gdk::Key::_8 => 7,
                            gdk::Key::_9 => 8,
                            gdk::Key::_0 => 9,
                            _ => 0,
                        };
                        if let Some(row) = sidebar_ref.row_at_index(idx) {
                            settings_list_ref.unselect_all();
                            sidebar_ref.select_row(Some(&row));
                            content_ref.set_visible_child_name(all_sidebar_items()[idx as usize].id);
                            page_ref.set_title(all_sidebar_items()[idx as usize].label);
                            if idx == 0 { log_ref.refresh_categories(); }
                            if idx == 1 { hist_ref.refresh(); }
                            if idx == 2 { chart_ref.refresh(); }
                        }
                    }
                    gdk::Key::comma => {
                        sidebar_ref.unselect_all();
                        settings_list_ref.select_row(settings_list_ref.row_at_index(0).as_ref());
                        content_ref.set_visible_child_name(SETTINGS_ITEM.id);
                        page_ref.set_title(SETTINGS_ITEM.label);
                    }
                    gdk::Key::e => {
                        if let Some(row) = sidebar_ref.row_at_index(0) {
                            settings_list_ref.unselect_all();
                            sidebar_ref.select_row(Some(&row));
                        }
                        content_ref.set_visible_child_name("log");
                        page_ref.set_title("Log");
                        log_ref.refresh_categories();
                        log_ref.set_income_mode(false);
                        log_ref.focus_amount();
                    }
                    gdk::Key::i => {
                        if let Some(row) = sidebar_ref.row_at_index(0) {
                            settings_list_ref.unselect_all();
                            sidebar_ref.select_row(Some(&row));
                        }
                        content_ref.set_visible_child_name("log");
                        page_ref.set_title("Log");
                        log_ref.refresh_categories();
                        log_ref.set_income_mode(true);
                        log_ref.focus_amount();
                    }
                    gdk::Key::question => {
                        Self::show_shortcuts_window(&window_ref);
                    }
                    _ => return glib::Propagation::Proceed,
                }
                glib::Propagation::Stop
            });
            window.add_controller(key_ctrl);
        }

        MainWindow {
            window,
            log_view,
            history_view: history_view_ref,
            charts_view: charts_view_ref,
            budgets_view: budgets_view_ref,
            insights_view: insights_view_ref,
            sidebar_list,
            content_stack,
            content_page,
        }
    }

    pub fn show(&self) {
        self.window.set_visible(true);
        self.window.present();
    }

    pub fn switch_to_log(&self, income: bool) {
        if let Some(row) = self.sidebar_list.row_at_index(0) {
            self.sidebar_list.select_row(Some(&row));
        }
        self.content_stack.set_visible_child_name("log");
        self.content_page.set_title("Log");
        self.log_view.refresh_categories();
        self.log_view.set_income_mode(income);
        self.log_view.focus_amount();
    }

    pub fn switch_to_history_filtered(&self, category_id: i64) {
        if let Some(row) = self.sidebar_list.row_at_index(1) {
            self.sidebar_list.select_row(Some(&row));
        }
        self.content_stack.set_visible_child_name("history");
        self.content_page.set_title("History");
        self.history_view.refresh();
        self.history_view.set_category_filter(category_id);
    }

    pub fn switch_to_insights(&self) {
        // Find the sidebar index for "insights"
        let idx = all_sidebar_items().iter().position(|item| item.id == "insights");
        if let Some(i) = idx {
            if let Some(row) = self.sidebar_list.row_at_index(i as i32) {
                self.sidebar_list.select_row(Some(&row));
            }
        }
        self.content_stack.set_visible_child_name("insights");
        self.content_page.set_title("Insights");
        self.insights_view.refresh();
    }

    pub fn save_window_state(&self, db: &Database) {
        let (width, height) = self.window.default_size();
        db.set_setting("window_width", &width.to_string()).ok();
        db.set_setting("window_height", &height.to_string()).ok();
        db.set_setting(
            "window_maximized",
            if self.window.is_maximized() { "true" } else { "false" },
        )
        .ok();
    }

    fn show_shortcuts_window(parent: &adw::ApplicationWindow) {
        let ui = r#"
        <interface>
          <object class="GtkShortcutsWindow" id="shortcuts_window">
            <property name="modal">true</property>
            <child>
              <object class="GtkShortcutsSection">
                <property name="title">Outlay</property>
                <property name="max-height">12</property>
                <child>
                  <object class="GtkShortcutsGroup">
                    <property name="title">Navigation</property>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;1</property>
                      <property name="title">Log</property>
                    </object></child>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;2</property>
                      <property name="title">History</property>
                    </object></child>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;3</property>
                      <property name="title">Charts</property>
                    </object></child>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;4</property>
                      <property name="title">Budgets</property>
                    </object></child>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;5</property>
                      <property name="title">Goals</property>
                    </object></child>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;6</property>
                      <property name="title">Recurring</property>
                    </object></child>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;7</property>
                      <property name="title">Subscriptions</property>
                    </object></child>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;8</property>
                      <property name="title">Wishlist</property>
                    </object></child>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;9</property>
                      <property name="title">Forecast</property>
                    </object></child>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;0</property>
                      <property name="title">Insights</property>
                    </object></child>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;comma</property>
                      <property name="title">Settings</property>
                    </object></child>
                  </object>
                </child>
                <child>
                  <object class="GtkShortcutsGroup">
                    <property name="title">Transaction Entry</property>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;e</property>
                      <property name="title">New expense</property>
                    </object></child>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;i</property>
                      <property name="title">New income</property>
                    </object></child>
                  </object>
                </child>
                <child>
                  <object class="GtkShortcutsGroup">
                    <property name="title">General</property>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;question</property>
                      <property name="title">Keyboard shortcuts</property>
                    </object></child>
                    <child><object class="GtkShortcutsShortcut">
                      <property name="accelerator">&lt;Ctrl&gt;q</property>
                      <property name="title">Quit</property>
                    </object></child>
                  </object>
                </child>
              </object>
            </child>
          </object>
        </interface>"#;
        let builder = gtk::Builder::from_string(ui);
        let win: gtk::ShortcutsWindow = builder.object("shortcuts_window").unwrap();
        win.set_transient_for(Some(parent));
        win.present();
    }

    fn make_sidebar_row(item: &SidebarItem) -> gtk::ListBoxRow {
        let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 14);
        hbox.set_margin_top(12);
        hbox.set_margin_bottom(12);
        hbox.set_margin_start(16);
        hbox.set_margin_end(12);

        let tinted = icon_theme::get_tinted_icon_name(item.icon, item.color);
        let icon = gtk::Image::from_icon_name(&tinted);
        icon.set_pixel_size(24);

        let label = gtk::Label::new(Some(item.label));
        label.set_halign(gtk::Align::Start);
        label.add_css_class("sidebar-label");

        hbox.append(&icon);
        hbox.append(&label);

        let row = gtk::ListBoxRow::new();
        row.set_child(Some(&hbox));
        row
    }
}
