use std::fs;

use camino::Utf8Path;
use miette::IntoDiagnostic;
use miette::Result;
use relative_path::RelativePathBuf;
use time::OffsetDateTime;
use time_tz::OffsetDateTimeExt as _;

use crate::ImporterProtocol;

#[tracing::instrument(fields(importer = importer.name()))]
pub(crate) fn file_name(
    importer: &dyn ImporterProtocol<Error = miette::Report>,
    file: &Utf8Path,
    buffer: &[u8],
) -> Result<RelativePathBuf> {
    let account = importer.account(buffer)?;

    let binding = importer.filename(buffer).transpose()?;
    let name = binding
        .as_deref()
        .unwrap_or_else(|| file.file_name().unwrap());

    let date = importer.date(buffer).unwrap_or_else(|| {
        let metadata = file.metadata().into_diagnostic()?;
        let ctime = metadata.created().into_diagnostic()?;
        let ctime = OffsetDateTime::from(ctime);

        let tz = time_tz::system::get_timezone().into_diagnostic()?;
        let ctime = ctime.to_timezone(tz);

        Ok(ctime.date())
    })?;

    // The returned filename cannot contain the file path separator character.
    miette::ensure!(
        !name.contains(std::path::MAIN_SEPARATOR),
        "filename contains path separator character"
    );

    /*
        TODO "if re.match(r'\d\d\d\d-\d\d-\d\d\.', filename):
            raise Error("The name contains what looks like a date.")
    */

    // Prepend account directory and date prefix.
    let mut path = RelativePathBuf::new();
    path.extend(account.segments().map(|seg| &**seg));

    let file_name = format!("{date}.{name}");
    path.push(file_name);

    Ok(path)
}

#[tracing::instrument]
pub(crate) fn move_file(file: &Utf8Path, destination: &Utf8Path) -> Result<()> {
    if let Some(path) = destination.parent() {
        fs::create_dir_all(path).into_diagnostic()?;
    }

    fs::rename(file, destination).into_diagnostic()?;

    Ok(())
}