#![deny(rustdoc::broken_intra_doc_links)]

use crate::intervals::*;
use duplicate::duplicate_item;
use num_valid::core::errors::capture_backtrace;

//------------------------------------------------------------------------------------------------

#[duplicate_item(
    T;
    [Interval];
    [IntervalFinitePositiveLength];
)]
impl<PartitionDomain1D: BuildIntervalInPartition> From<SubIntervalInPartition<PartitionDomain1D>>
    for T<PartitionDomain1D::RealType>
where
    T<PartitionDomain1D::RealType>: From<PartitionDomain1D>,
{
    #[inline(always)]
    fn from(src: SubIntervalInPartition<PartitionDomain1D>) -> Self {
        match src {
            SubIntervalInPartition::Only(interval) => interval.into(),
            SubIntervalInPartition::First(interval) => interval.into(),
            SubIntervalInPartition::Middle(interval) => interval.into(),
            SubIntervalInPartition::Last(interval) => interval.into(),
        }
    }
}
//------------------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------------------
#[duplicate_item(
    src;
    [IntervalClosed];
    [IntervalOpen];
    [IntervalLowerClosedUpperOpen];
    [IntervalLowerOpenUpperClosed];
    [IntervalSingleton]
)]
impl<RealType: RealScalar> From<src<RealType>> for Interval<RealType> {
    fn from(interval: src<RealType>) -> Self {
        Interval::FiniteLength(IntervalFiniteLength::from(interval))
    }
}

impl<RealType: RealScalar> From<IntervalFinitePositiveLength<RealType>> for Interval<RealType> {
    fn from(interval: IntervalFinitePositiveLength<RealType>) -> Self {
        Interval::FiniteLength(IntervalFiniteLength::PositiveLength(interval))
    }
}

impl<RealType: RealScalar> From<IntervalFiniteLength<RealType>> for Interval<RealType> {
    fn from(interval: IntervalFiniteLength<RealType>) -> Self {
        Interval::FiniteLength(interval)
    }
}

#[duplicate_item(
    src;
    [IntervalLowerClosedUpperUnbounded];
    [IntervalLowerOpenUpperUnbounded];
    [IntervalLowerUnboundedUpperClosed];
    [IntervalLowerUnboundedUpperOpen];
    [IntervalLowerUnboundedUpperUnbounded];
)]
impl<RealType: RealScalar> From<src<RealType>> for Interval<RealType> {
    fn from(interval: src<RealType>) -> Self {
        Interval::InfiniteLength(IntervalInfiniteLength::from(interval))
    }
}

//------------------------------------------------------------------------------------------------
// NOTE: Into<Interval> is implemented for specific IntervalBounded type combinations
//
// The implementations above for type aliases (IntervalClosed, IntervalOpen, etc.) provide
// Into<Interval> for these SPECIFIC combinations of bound types:
//   - IntervalBounded<T, Closed, Closed> (via IntervalClosed)
//   - IntervalBounded<T, Open, Open> (via IntervalOpen)
//   - IntervalBounded<T, Closed, Open> (via IntervalLowerClosedUpperOpen)
//   - IntervalBounded<T, Open, Closed> (via IntervalLowerOpenUpperClosed)
//
// IMPORTANT: There is NO blanket implementation:
//   impl<T, L, U> From<IntervalBounded<T, L, U>> for Interval<T>
//   where L: BoundType, U: BoundType { ... }  // ❌ Does NOT exist
//
// This means:
// ✅ Works: let bounded: IntervalBounded<f64, Closed, Open> = ...;
//           bounded.into() // OK - concrete types match an existing impl
//
// ✅ Works: fn convert<L, U>(i: IntervalBounded<f64, L, U>) -> Interval<f64>
//           where IntervalBounded<f64, L, U>: Into<Interval<f64>> { i.into() }
//           // OK when called with concrete L,U due to monomorphization
//
// ❌ Fails: fn convert<L, U>(i: IntervalBounded<f64, L, U>) -> Interval<f64>
//           where L: BoundType, U: BoundType { i.into() }
//           // ERROR: compiler can't prove Into exists for arbitrary L,U
//
// The reason: Implementing From for arbitrary L,U would require type-level inspection
// of the bound types at compile time, which Rust doesn't support without specialization.
//------------------------------------------------------------------------------------------------

#[duplicate_item(
    src                            tgt;
    [IntervalClosed]               [Closed];
    [IntervalOpen]                 [Open];
    [IntervalLowerOpenUpperClosed] [LowerOpenUpperClosed];
    [IntervalLowerClosedUpperOpen] [LowerClosedUpperOpen];
)]
impl<RealType: RealScalar> From<src<RealType>> for IntervalFinitePositiveLength<RealType> {
    fn from(interval: src<RealType>) -> Self {
        IntervalFinitePositiveLength::tgt(interval)
    }
}

#[duplicate_item(
    src;
    [IntervalClosed]              ;
    [IntervalOpen]                ;
    [IntervalLowerOpenUpperClosed];
    [IntervalLowerClosedUpperOpen];
)]
impl<RealType: RealScalar> From<src<RealType>> for IntervalFiniteLength<RealType> {
    fn from(interval: src<RealType>) -> Self {
        IntervalFiniteLength::PositiveLength(IntervalFinitePositiveLength::from(interval))
    }
}

impl<RealType: RealScalar> From<IntervalFinitePositiveLength<RealType>>
    for IntervalFiniteLength<RealType>
{
    fn from(interval: IntervalFinitePositiveLength<RealType>) -> Self {
        IntervalFiniteLength::PositiveLength(interval)
    }
}

impl<RealType: RealScalar> From<IntervalSingleton<RealType>> for IntervalFiniteLength<RealType> {
    fn from(interval: IntervalSingleton<RealType>) -> Self {
        IntervalFiniteLength::ZeroLength(interval)
    }
}

#[duplicate_item(
    src                                    tgt;
    [IntervalLowerClosedUpperUnbounded]    [LowerClosedUpperUnbounded];
    [IntervalLowerOpenUpperUnbounded]      [LowerOpenUpperUnbounded];
    [IntervalLowerUnboundedUpperClosed]    [LowerUnboundedUpperClosed];
    [IntervalLowerUnboundedUpperOpen]      [LowerUnboundedUpperOpen];
    [IntervalLowerUnboundedUpperUnbounded] [LowerUnboundedUpperUnbounded];
)]
impl<RealType: RealScalar> From<src<RealType>> for IntervalInfiniteLength<RealType> {
    fn from(interval: src<RealType>) -> Self {
        IntervalInfiniteLength::tgt(interval)
    }
}
//------------------------------------------------------------------------------------------------

impl<RealType: RealScalar> TryFrom<Interval<RealType>> for IntervalFiniteLength<RealType> {
    type Error = ErrorsIntervalConversion<RealType>;

    fn try_from(interval: Interval<RealType>) -> Result<Self, Self::Error> {
        match interval {
            Interval::FiniteLength(interval_finite_length) => Ok(interval_finite_length),
            Interval::InfiniteLength(_) => Err(ErrorsIntervalConversion::NotIntervalFiniteLength {
                interval,
                backtrace: capture_backtrace(),
            }),
        }
    }
}

impl<RealType: RealScalar> TryFrom<Interval<RealType>> for IntervalFinitePositiveLength<RealType> {
    type Error = ErrorsIntervalConversion<RealType>;

    fn try_from(interval: Interval<RealType>) -> Result<Self, Self::Error> {
        match interval {
            Interval::FiniteLength(interval_finite_lenght) => match interval_finite_lenght {
                IntervalFiniteLength::PositiveLength(interval_positive_lenght) => {
                    Ok(interval_positive_lenght)
                }
                IntervalFiniteLength::ZeroLength(interval_zero_length) => {
                    Err(ErrorsIntervalConversion::NotIntervalPositiveLength {
                        interval: interval_zero_length.into(),
                        backtrace: capture_backtrace(),
                    })
                }
            },
            Interval::InfiniteLength(_) => {
                Err(ErrorsIntervalConversion::NotIntervalPositiveLength {
                    interval,
                    backtrace: capture_backtrace(),
                })
            }
        }
    }
}

impl<RealType: RealScalar> TryFrom<Interval<RealType>> for IntervalInfiniteLength<RealType> {
    type Error = ErrorsIntervalConversion<RealType>;

    fn try_from(interval: Interval<RealType>) -> Result<Self, Self::Error> {
        match interval {
            Interval::InfiniteLength(interval_infinite_length) => Ok(interval_infinite_length),
            _ => Err(ErrorsIntervalConversion::NotIntervalInfiniteLength {
                interval,
                backtrace: capture_backtrace(),
            }),
        }
    }
}

impl<RealType: RealScalar> From<IntervalInfiniteLength<RealType>> for Interval<RealType> {
    fn from(interval_infinite_length: IntervalInfiniteLength<RealType>) -> Self {
        Interval::InfiniteLength(interval_infinite_length)
    }
}

#[duplicate_item(
    src                            ok_enum                err ;
    [IntervalClosed]               [Closed]               [NotIntervalClosed];
    [IntervalOpen]                 [Open]                 [NotIntervalOpen];
    [IntervalLowerOpenUpperClosed] [LowerOpenUpperClosed] [NotIntervalLowerOpenUpperClosed];
    [IntervalLowerClosedUpperOpen] [LowerClosedUpperOpen] [NotIntervalLowerClosedUpperOpen];
)]
impl<RealType: RealScalar> TryFrom<Interval<RealType>> for src<RealType> {
    type Error = ErrorsIntervalConversion<RealType>;

    fn try_from(interval: Interval<RealType>) -> Result<Self, Self::Error> {
        let interval_finite_positive_lenght: IntervalFinitePositiveLength<RealType> =
            interval.try_into()?;
        match interval_finite_positive_lenght {
            IntervalFinitePositiveLength::ok_enum(interval) => Ok(interval),
            _ => Err(ErrorsIntervalConversion::err {
                interval: interval_finite_positive_lenght.into(),
                backtrace: capture_backtrace(),
            }),
        }
    }
}

#[duplicate_item(
    src                            ok_enum                err ;
    [IntervalClosed]               [Closed]               [NotIntervalClosed];
    [IntervalOpen]                 [Open]                 [NotIntervalOpen];
    [IntervalLowerOpenUpperClosed] [LowerOpenUpperClosed] [NotIntervalLowerOpenUpperClosed];
    [IntervalLowerClosedUpperOpen] [LowerClosedUpperOpen] [NotIntervalLowerClosedUpperOpen];
)]
impl<RealType: RealScalar> TryFrom<IntervalFinitePositiveLength<RealType>> for src<RealType> {
    type Error = ErrorsIntervalConversion<RealType>;

    fn try_from(
        interval_finite_positive_length: IntervalFinitePositiveLength<RealType>,
    ) -> Result<Self, Self::Error> {
        match interval_finite_positive_length {
            IntervalFinitePositiveLength::ok_enum(interval) => Ok(interval),
            _ => Err(ErrorsIntervalConversion::err {
                interval: interval_finite_positive_length.into(),
                backtrace: capture_backtrace(),
            }),
        }
    }
}

impl<RealType: RealScalar> TryFrom<Interval<RealType>> for IntervalSingleton<RealType> {
    type Error = ErrorsIntervalConversion<RealType>;

    fn try_from(interval: Interval<RealType>) -> Result<Self, Self::Error> {
        let interval_finite_length: IntervalFiniteLength<RealType> = interval.try_into()?;
        match interval_finite_length {
            IntervalFiniteLength::ZeroLength(singleton) => Ok(singleton),
            _ => Err(ErrorsIntervalConversion::NotIntervalSingleton {
                interval: interval_finite_length.into(),
                backtrace: capture_backtrace(),
            }),
        }
    }
}

#[duplicate_item(
    src                                 variant                     error_variant;
    [IntervalLowerUnboundedUpperClosed] [LowerUnboundedUpperClosed] [NotIntervalLowerUnboundedUpperClosed];
    [IntervalLowerUnboundedUpperOpen]   [LowerUnboundedUpperOpen]   [NotIntervalLowerUnboundedUpperOpen];
    [IntervalLowerClosedUpperUnbounded] [LowerClosedUpperUnbounded] [NotIntervalLowerClosedUpperUnbounded];
    [IntervalLowerOpenUpperUnbounded]   [LowerOpenUpperUnbounded]   [NotIntervalLowerOpenUpperUnbounded];
)]
impl<RealType: RealScalar> TryFrom<Interval<RealType>> for src<RealType> {
    type Error = ErrorsIntervalConversion<RealType>;

    fn try_from(interval: Interval<RealType>) -> Result<Self, Self::Error> {
        let interval_infinite_lenght: IntervalInfiniteLength<RealType> = interval.try_into()?;
        match interval_infinite_lenght {
            IntervalInfiniteLength::variant(interval) => Ok(interval),
            _ => Err(ErrorsIntervalConversion::error_variant {
                interval: interval_infinite_lenght.into(),
                backtrace: capture_backtrace(),
            }),
        }
    }
}
