use crate::{
    common::{AppTimeFormat, Content, Style, Toggle},
    duration::ONE_MINUTE,
    event::Event,
    widgets::pomodoro::{Mode as PomodoroMode, PauseDuration},
};
use color_eyre::eyre::Result;
use serde::{Deserialize, Deserializer, Serialize};
use std::fs;
use std::path::PathBuf;
use std::time::Duration;

const DEFAULT_WORK: Duration = ONE_MINUTE.saturating_mul(25); /* 25min */
const DEFAULT_PAUSE: Duration = ONE_MINUTE.saturating_mul(5); /* 5min */
const DEFAULT_COUNTDOWN: Duration = ONE_MINUTE.saturating_mul(10); /* 10min */
const DEFAULT_PAUSE_DURATION: PauseDuration = PauseDuration::Fixed(DEFAULT_PAUSE);

fn default_pause_duration() -> PauseDuration {
    DEFAULT_PAUSE_DURATION
}

fn deserialize_app_time_format<'de, D>(deserializer: D) -> Result<AppTimeFormat, D::Error>
where
    D: Deserializer<'de>,
{
    let s = String::deserialize(deserializer)?;
    match s.as_str() {
        // Hidden is deprecated - use `default` value instead
        "Hidden" => Ok(AppTimeFormat::default()),
        _ => s.parse().map_err(serde::de::Error::custom),
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct AppStorage {
    pub content: Content,
    pub show_menu: bool,
    #[serde(default)]
    pub vim: Toggle,
    pub notification: Toggle,
    pub blink: Toggle,
    #[serde(deserialize_with = "deserialize_app_time_format")]
    pub app_time_format: AppTimeFormat,
    pub style: Style,
    pub with_decis: bool,
    pub pomodoro_mode: PomodoroMode,
    pub pomodoro_count: u64,
    pub pomodoro_auto_switch: bool,
    // pomodoro -> work
    pub inital_value_work: Duration,
    pub current_value_work: Duration,
    // pomodoro -> pause
    #[serde(default = "default_pause_duration")]
    pub pause_duration: PauseDuration,
    pub current_value_pause: Duration,
    // countdown
    pub inital_value_countdown: Duration,
    pub current_value_countdown: Duration,
    pub elapsed_value_countdown: Duration,
    // timer
    pub current_value_timer: Duration,
    // event
    pub event: Event,
    // footer
    pub footer_app_time: Toggle,
}

impl Default for AppStorage {
    fn default() -> Self {
        AppStorage {
            content: Content::default(),
            show_menu: true,
            vim: Toggle::Off,
            notification: Toggle::Off,
            blink: Toggle::Off,
            app_time_format: AppTimeFormat::default(),
            style: Style::default(),
            with_decis: false,
            pomodoro_mode: PomodoroMode::Work,
            pomodoro_count: 1,
            pomodoro_auto_switch: false,
            // pomodoro -> work
            inital_value_work: DEFAULT_WORK,
            current_value_work: DEFAULT_WORK,
            // pomodoro -> pause
            pause_duration: DEFAULT_PAUSE_DURATION,
            current_value_pause: DEFAULT_PAUSE,
            // countdown
            inital_value_countdown: DEFAULT_COUNTDOWN,
            current_value_countdown: DEFAULT_COUNTDOWN,
            elapsed_value_countdown: Duration::ZERO,
            // timer
            current_value_timer: Duration::ZERO,
            // event
            event: Event::default(),
            // footer
            footer_app_time: Toggle::Off,
        }
    }
}

pub struct Storage {
    data_dir: PathBuf,
}

impl Storage {
    pub fn new(data_dir: PathBuf) -> Self {
        Self { data_dir }
    }

    fn get_storage_path(&self) -> PathBuf {
        self.data_dir.join("app.data")
    }

    pub fn save(&self, data: AppStorage) -> Result<()> {
        let file = fs::File::create(self.get_storage_path())?;
        serde_json::to_writer(file, &data)?;
        Ok(())
    }

    pub fn load(&self) -> Result<AppStorage> {
        let file = fs::File::open(self.get_storage_path())?;
        let data = serde_json::from_reader(file)?;
        Ok(data)
    }
}
