/*
Copyright 2024, Savanni D'Gerinel <savanni@luminescent-dreams.com>

This file is part of FitnessTrax.

FitnessTrax is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

FitnessTrax is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License along with FitnessTrax. If not, see <https://www.gnu.org/licenses/>.
*/

use crate::{components::DateField, types::DayInterval};
use chrono::{Duration, Local, Months};
use glib::Object;
use gtk::{prelude::*, subclass::prelude::*};
use std::cell::RefCell;

type OnSearch = dyn Fn(DayInterval) + 'static;

pub struct DateRangePickerPrivate {
    start: DateField,
    end: DateField,

    on_search: RefCell<Box<OnSearch>>,
}

#[glib::object_subclass]
impl ObjectSubclass for DateRangePickerPrivate {
    const NAME: &'static str = "DateRangePicker";
    type Type = DateRangePicker;
    type ParentType = gtk::Box;

    fn new() -> Self {
        let default_date = Local::now().date_naive();
        let start = DateField::new(default_date);
        start.add_css_class("date-range-picker__date-field");
        let end = DateField::new(default_date);
        end.add_css_class("date-range-picker__date-field");

        Self {
            start,
            end,
            on_search: RefCell::new(Box::new(|_| {})),
        }
    }
}

impl ObjectImpl for DateRangePickerPrivate {}
impl WidgetImpl for DateRangePickerPrivate {}
impl BoxImpl for DateRangePickerPrivate {}

glib::wrapper! {
    pub struct DateRangePicker(ObjectSubclass<DateRangePickerPrivate>) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable;
}

impl DateRangePicker {
    pub fn connect_on_search<OnSearch>(&self, f: OnSearch)
    where
        OnSearch: Fn(DayInterval) + 'static,
    {
        *self.imp().on_search.borrow_mut() = Box::new(f);
    }

    pub fn set_interval(&self, start: chrono::NaiveDate, end: chrono::NaiveDate) {
        self.imp().start.set_date(start);
        self.imp().end.set_date(end);
    }

    pub fn interval(&self) -> DayInterval {
        DayInterval {
            start: self.imp().start.date(),
            end: self.imp().end.date(),
        }
    }
}

impl Default for DateRangePicker {
    fn default() -> Self {
        let s: Self = Object::builder().build();
        s.set_orientation(gtk::Orientation::Vertical);
        s.add_css_class("date-range-picker");

        let search_button = gtk::Button::builder()
            .css_classes(["date-range-picker__search-button"])
            .label("Search")
            .build();
        search_button.connect_clicked({
            let s = s.clone();
            move |_| (s.imp().on_search.borrow())(s.interval())
        });

        let last_week_button = gtk::Button::builder()
            .css_classes(["date-range-picker__range-button"])
            .label("week")
            .build();
        last_week_button.connect_clicked({
            let s = s.clone();
            move |_| {
                let end = Local::now().date_naive();
                let start = end - Duration::days(7);
                s.set_interval(start, end);
                (s.imp().on_search.borrow())(s.interval());
            }
        });

        let two_weeks_button = gtk::Button::builder()
            .css_classes(["date-range-picker__range-button"])
            .label("two weeks")
            .build();
        two_weeks_button.connect_clicked({
            let s = s.clone();
            move |_| {
                let end = Local::now().date_naive();
                let start = end - Duration::days(14);
                s.set_interval(start, end);
                (s.imp().on_search.borrow())(s.interval());
            }
        });

        let last_month_button = gtk::Button::builder()
            .css_classes(["date-range-picker__range-button"])
            .label("month")
            .build();
        last_month_button.connect_clicked({
            let s = s.clone();
            move |_| {
                let end = Local::now().date_naive();
                let start = end - Months::new(1);
                s.set_interval(start, end);
                (s.imp().on_search.borrow())(s.interval());
            }
        });

        let six_months_button = gtk::Button::builder()
            .css_classes(["date-range-picker__range-button"])
            .label("six months")
            .build();
        six_months_button.connect_clicked({
            let s = s.clone();
            move |_| {
                let end = Local::now().date_naive();
                let start = end - Months::new(6);
                s.set_interval(start, end);
                (s.imp().on_search.borrow())(s.interval());
            }
        });

        let last_year_button = gtk::Button::builder()
            .css_classes(["date-range-picker__range-button"])
            .label("year")
            .build();
        last_year_button.connect_clicked({
            let s = s.clone();
            move |_| {
                let end = Local::now().date_naive();
                let start = end - Months::new(12);
                s.set_interval(start, end);
                (s.imp().on_search.borrow())(s.interval());
            }
        });

        let date_row = gtk::Box::builder()
            .orientation(gtk::Orientation::Horizontal)
            .build();
        date_row.append(&s.imp().start);
        date_row.append(&gtk::Label::new(Some("to")));
        date_row.append(&s.imp().end);
        date_row.append(&search_button);

        let quick_picker = gtk::Box::builder()
            .orientation(gtk::Orientation::Horizontal)
            .build();
        quick_picker.append(&last_week_button);
        quick_picker.append(&two_weeks_button);
        quick_picker.append(&last_month_button);
        quick_picker.append(&six_months_button);
        quick_picker.append(&last_year_button);

        s.append(&date_row);
        s.append(&quick_picker);

        s
    }
}
