Skip to content
use eframe::egui;

use crate::client::Client;
use crate::protocol::{Request, TimerInfo, TimerStatus};
use crate::task::Task;

pub struct HyperfocusApp {
    tasks: Vec<Task>,
    timer_info: TimerInfo,
    selected_task: Option<usize>,

    new_task_name: String,
    new_task_duration: String,
}

impl HyperfocusApp {
    pub fn new(_cc: &eframe::CreationContext<'_>) -> Self {
        let mut app = Self {
            tasks: Vec::new(),
            timer_info: TimerInfo::default(),
            selected_task: None,
            new_task_name: String::new(),
            new_task_duration: String::from("25"),
        };
        app.refresh();
        app
    }

    /// Fetch latest state from the service.
    fn refresh(&mut self) {
        if let Ok(resp) = Client::send(&Request::Status) {
            if let Some(tasks) = resp.tasks {
                self.tasks = tasks;
            }
            if let Some(timer) = resp.timer {
                self.timer_info = timer;
            }
        }
    }

    /// Send a command to the service and update local caches from the response.
    fn send(&mut self, req: &Request) {
        if let Ok(resp) = Client::send(req) {
            if let Some(tasks) = resp.tasks {
                self.tasks = tasks;
            }
            if let Some(timer) = resp.timer {
                self.timer_info = timer;
            }
        }
    }

    fn format_remaining(&self) -> String {
        let total = self.timer_info.remaining_secs;
        let mins = total / 60;
        let secs = total % 60;
        format!("{mins:02}:{secs:02}")
    }

    #[allow(clippy::cast_precision_loss)]
    fn progress(&self) -> f32 {
        if self.timer_info.total_secs == 0 {
            return 0.0;
        }
        1.0 - (self.timer_info.remaining_secs as f32 / self.timer_info.total_secs as f32)
    }
}

impl eframe::App for HyperfocusApp {
    #[allow(clippy::too_many_lines)]
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        // Poll service while timer is running
        if self.timer_info.state == TimerStatus::Running {
            self.refresh();
            ctx.request_repaint_after(std::time::Duration::from_millis(250));
        }

        // Sync selected_task with service's active task when timer is active
        if matches!(
            self.timer_info.state,
            TimerStatus::Running | TimerStatus::Paused
        ) {
            self.selected_task = self.timer_info.task_index;
        }

        egui::TopBottomPanel::top("header").show(ctx, |ui| {
            ui.add_space(4.0);
            ui.horizontal(|ui| {
                ui.heading("Hyperfocus");
                ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
                    let remaining = self.tasks.iter().filter(|t| !t.completed).count();
                    ui.label(format!("{remaining} task(s) remaining"));
                });
            });
            ui.add_space(4.0);
        });

        egui::SidePanel::left("tasks_panel")
            .resizable(true)
            .default_width(240.0)
            .min_width(180.0)
            .show(ctx, |ui| {
                ui.add_space(8.0);
                ui.heading("Tasks");
                ui.separator();

                // Add task form
                ui.horizontal(|ui| {
                    let name_response = ui.add(
                        egui::TextEdit::singleline(&mut self.new_task_name)
                            .hint_text("Task name")
                            .desired_width(100.0),
                    );
                    ui.add(
                        egui::TextEdit::singleline(&mut self.new_task_duration)
                            .hint_text("min")
                            .desired_width(32.0),
                    );
                    let add_clicked = ui.button("Add").clicked();
                    let enter_pressed =
                        name_response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter));

                    if (add_clicked || enter_pressed) && !self.new_task_name.trim().is_empty() {
                        let duration: u32 = self.new_task_duration.trim().parse().unwrap_or(25);
                        self.send(&Request::AddTask {
                            name: self.new_task_name.trim().to_string(),
                            duration_minutes: duration,
                        });
                        self.new_task_name.clear();
                        self.new_task_duration = String::from("25");
                    }
                });

                ui.add_space(4.0);
                ui.separator();
                ui.add_space(4.0);

                // Task list
                let mut to_remove: Option<usize> = None;
                let mut to_toggle: Option<usize> = None;

                egui::ScrollArea::vertical().show(ui, |ui| {
                    for (i, task) in self.tasks.iter().enumerate() {
                        let is_selected = self.selected_task == Some(i);
                        let is_active = self.timer_info.task_index == Some(i)
                            && matches!(
                                self.timer_info.state,
                                TimerStatus::Running | TimerStatus::Paused
                            );

                        ui.horizontal(|ui| {
                            let mut completed = task.completed;
                            if ui.checkbox(&mut completed, "").changed() {
                                to_toggle = Some(i);
                            }

                            let label = if is_active {
                                format!("\u{25b6} {} ({}m)", task.name, task.duration_minutes)
                            } else {
                                format!("{} ({}m)", task.name, task.duration_minutes)
                            };

                            let response = ui.selectable_label(is_selected, &label);
                            if response.clicked()
                                && (self.timer_info.state == TimerStatus::Idle
                                    || self.timer_info.state == TimerStatus::Finished)
                            {
                                self.selected_task = Some(i);
                            }

                            ui.with_layout(
                                egui::Layout::right_to_left(egui::Align::Center),
                                |ui| {
                                    if ui.small_button("\u{2715}").clicked() {
                                        to_remove = Some(i);
                                    }
                                },
                            );
                        });
                    }
                });

                if let Some(i) = to_toggle {
                    self.send(&Request::ToggleDone { index: i });
                }

                if let Some(i) = to_remove {
                    if self.selected_task == Some(i) {
                        self.selected_task = None;
                    } else if let Some(sel) = self.selected_task
                        && sel > i
                    {
                        self.selected_task = Some(sel - 1);
                    }
                    self.send(&Request::RemoveTask { index: i });
                }
            });

        egui::CentralPanel::default().show(ctx, |ui| {
            ui.add_space(16.0);

            match self.selected_task {
                Some(idx) if idx < self.tasks.len() => {
                    let task_name = self.tasks[idx].name.clone();
                    let task_duration = self.tasks[idx].duration_minutes;

                    ui.vertical_centered(|ui| {
                        ui.heading(&task_name);
                        ui.add_space(4.0);
                        ui.label(format!("Duration: {task_duration} minutes"));
                        ui.add_space(24.0);

                        // Timer display
                        ui.label(
                            egui::RichText::new(self.format_remaining())
                                .size(64.0)
                                .monospace(),
                        );

                        ui.add_space(8.0);

                        // Progress bar
                        let bar = egui::ProgressBar::new(self.progress()).show_percentage();
                        ui.add_sized([280.0, 20.0], bar);

                        ui.add_space(16.0);

                        // Controls
                        ui.horizontal(|ui| {
                            ui.add_space((ui.available_width() - 200.0).max(0.0) / 2.0);

                            match self.timer_info.state {
                                TimerStatus::Idle | TimerStatus::Finished => {
                                    if ui
                                        .add_sized(
                                            [90.0, 36.0],
                                            egui::Button::new("\u{25b6}  Start"),
                                        )
                                        .clicked()
                                    {
                                        self.send(&Request::StartTimer { index: idx });
                                    }
                                }
                                TimerStatus::Running => {
                                    if ui
                                        .add_sized(
                                            [90.0, 36.0],
                                            egui::Button::new("\u{23f8}  Pause"),
                                        )
                                        .clicked()
                                    {
                                        self.send(&Request::PauseTimer);
                                    }
                                    if ui
                                        .add_sized(
                                            [90.0, 36.0],
                                            egui::Button::new("\u{23f9}  Stop"),
                                        )
                                        .clicked()
                                    {
                                        self.send(&Request::StopTimer);
                                    }
                                }
                                TimerStatus::Paused => {
                                    if ui
                                        .add_sized(
                                            [90.0, 36.0],
                                            egui::Button::new("\u{25b6}  Resume"),
                                        )
                                        .clicked()
                                    {
                                        self.send(&Request::ResumeTimer);
                                    }
                                    if ui
                                        .add_sized(
                                            [90.0, 36.0],
                                            egui::Button::new("\u{23f9}  Stop"),
                                        )
                                        .clicked()
                                    {
                                        self.send(&Request::StopTimer);
                                    }
                                }
                            }
                        });

                        if self.timer_info.state == TimerStatus::Finished {
                            ui.add_space(16.0);
                            ui.label(
                                egui::RichText::new("\u{2705} Timer finished!")
                                    .size(18.0)
                                    .color(egui::Color32::from_rgb(80, 200, 80)),
                            );

                            let next = self
                                .tasks
                                .iter()
                                .enumerate()
                                .skip(idx + 1)
                                .find(|(_, t)| !t.completed)
                                .map(|(i, _)| i);

                            if let Some(next_idx) = next {
                                let next_name = self.tasks[next_idx].name.clone();
                                ui.add_space(8.0);
                                if ui.button(format!("Start next: {next_name}")).clicked() {
                                    self.selected_task = Some(next_idx);
                                    self.send(&Request::StartTimer { index: next_idx });
                                }
                            }
                        }
                    });
                }
                _ => {
                    ui.vertical_centered(|ui| {
                        ui.add_space(80.0);
                        ui.label(
                            egui::RichText::new("Select a task to start focusing")
                                .size(20.0)
                                .weak(),
                        );
                        ui.add_space(8.0);
                        ui.label("Add tasks on the left, then click one to begin.");
                    });
                }
            }
        });
    }
}