use crate::config::Configuration;
use crate::error::JournalError;
use crate::journal::Journal;
use clap::Parser;
use log::debug;
use std::path::PathBuf;

#[derive(Debug, Parser)]
pub struct Config {}

impl Config {
    pub fn run(&self, config: &Configuration) -> Result<(), JournalError> {
        config.dump();
        Ok(())
    }
}

#[derive(Debug, Parser)]
pub struct Init {
    #[clap(help = "Short name for journal")]
    journalname: String,

    #[clap(help = "Short description of journal, its title")]
    description: String,
}

impl Init {
    pub fn run(&self, config: &Configuration) -> Result<(), JournalError> {
        debug!(
            "init: journalname={:?} description={:?}",
            self.journalname, self.description
        );
        Journal::init(&config.dirname, &config.entries)?;
        Ok(())
    }
}

#[derive(Debug, Parser)]
pub struct IsJournal {}

impl IsJournal {
    pub fn run(&self, config: &Configuration) -> Result<(), JournalError> {
        if !Journal::is_journal(&config.dirname, &config.entries) {
            return Err(JournalError::NotAJournal(
                config.dirname.display().to_string(),
            ));
        }
        Ok(())
    }
}

#[derive(Debug, Parser)]
pub struct New {
    #[clap(help = "Title of new draft")]
    title: String,

    #[clap(long, help = "Add links to topic pages")]
    topic: Vec<PathBuf>,
}

impl New {
    pub fn run(&self, config: &Configuration) -> Result<(), JournalError> {
        let journal = Journal::new(&config.dirname, &config.entries)?;
        journal.new_draft(&self.title, &self.topic, &config.editor)?;
        Ok(())
    }
}

#[derive(Debug, Parser)]
pub struct List {}

impl List {
    pub fn run(&self, config: &Configuration) -> Result<(), JournalError> {
        let journal = Journal::new(&config.dirname, &config.entries)?;
        journal.list_drafts()?;
        Ok(())
    }
}

#[derive(Debug, Parser)]
pub struct NewTopic {
    #[clap(help = "Path to topic page in journal")]
    path: PathBuf,

    #[clap(help = "Title of topic page")]
    title: String,
}

impl NewTopic {
    pub fn run(&self, config: &Configuration) -> Result<(), JournalError> {
        let journal = Journal::new(&config.dirname, &config.entries)?;
        journal.new_topic(&self.path, &self.title, &config.editor)?;
        Ok(())
    }
}

#[derive(Debug, Parser)]
pub struct Edit {
    /// Draft id.
    draft: String,
}

impl Edit {
    pub fn run(&self, config: &Configuration) -> Result<(), JournalError> {
        let journal = Journal::new(&config.dirname, &config.entries)?;
        let filename = journal.pick_draft(&self.draft)?;
        journal.edit_draft(&config.editor, &filename)?;
        Ok(())
    }
}

#[derive(Debug, Parser)]
pub struct Remove {
    /// Draft id.
    draft: String,
}

impl Remove {
    pub fn run(&self, config: &Configuration) -> Result<(), JournalError> {
        let journal = Journal::new(&config.dirname, &config.entries)?;
        let filename = journal.pick_draft(&self.draft)?;
        journal.remove_draft(&filename)?;
        Ok(())
    }
}

#[derive(Debug, Parser)]
pub struct Finish {
    /// Draft id.
    draft: String,

    /// Set base name of published file.
    basename: String,
}

impl Finish {
    pub fn run(&self, config: &Configuration) -> Result<(), JournalError> {
        let journal = Journal::new(&config.dirname, &config.entries)?;
        let filename = journal.pick_draft(&self.draft)?;
        journal.finish_draft(&filename, &self.basename)?;
        Ok(())
    }
}
