use std::convert::Infallible;

use chrono::Duration;
use thiserror::Error;

use super::{Lookback, MinIterationInterval, Period};

#[derive(Error, Debug)]
#[non_exhaustive]
pub enum PeriodValidationError {
    #[error(
        "Invalid period, must be at least {} candles. Value: {value}",
        Period::MIN
    )]
    TooShort { value: u64 },

    #[error(
        "Invalid period, must be at most {} candles. Value: {value}",
        Period::MAX
    )]
    TooLong { value: u64 },
}

#[derive(Error, Debug)]
#[non_exhaustive]
pub enum LookbackValidationError {
    #[error(transparent)]
    Period(#[from] PeriodValidationError),

    #[error(
        "Lookback duration exceeds maximum of {} days. Duration: {} days",
        Lookback::MAX.num_days(),
        duration.num_days()
    )]
    ExceedsMaxLookback { duration: Duration },
}

impl From<Infallible> for LookbackValidationError {
    fn from(never: Infallible) -> Self {
        match never {}
    }
}

#[derive(Error, Debug)]
#[non_exhaustive]
pub enum MinIterationIntervalValidationError {
    #[error(
        "Invalid minimum iteration interval, must be at least {}. Value: {}s",
        MinIterationInterval::MIN,
        value.num_seconds()
    )]
    TooShort { value: Duration },

    #[error(
        "Invalid minimum iteration interval, must be at most {}. Value: {}s",
        MinIterationInterval::MAX,
        value.num_seconds()
    )]
    TooLong { value: Duration },
}
