use crate::*;

use std::{
    fmt::{self, Display, Formatter},
    ops::{Div, DivAssign, Mul, MulAssign},
    str::FromStr,
};

use derive_more::{Add, AddAssign, Neg, Sub, SubAssign};
use inner_space::{DotProduct, VectorSpace};
use scalars::{Real, Zero};
use vector_basis::Basis;

/// The 3D vector type.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Add, AddAssign, Sub, SubAssign, Neg)]
pub struct Vector<T> {
    /// The component representing the x axis.
    pub x: T,
    /// The component representing the y axis.
    pub y: T,
    /// The component representing the z axis.
    pub z: T,
}

impl<T> Vector<T> {
    /// Creates a new vector from its components.
    pub fn new(x: T, y: T, z: T) -> Self {
        Self { x, y, z }
    }
}

impl<T: Zero> Vector<T> {
    /// Creates a new vector along the x axis.
    pub fn x(x: T) -> Self {
        Self {
            x,
            y: T::zero(),
            z: T::zero(),
        }
    }

    /// Creates a new vector along the y axis.
    pub fn y(y: T) -> Self {
        Self {
            x: T::zero(),
            y,
            z: T::zero(),
        }
    }

    /// Creates a new vector along the z axis.
    pub fn z(z: T) -> Self {
        Self {
            x: T::zero(),
            y: T::zero(),
            z,
        }
    }
}

impl<T: Real> Vector<T> {
    /// Returns the wedge product (exterior product) of two vectors as a bivector.
    pub fn wedge(self, other: Self) -> Bivector<T> {
        Bivector {
            xy: self.x * other.y - self.y * other.x,
            xz: self.x * other.z - self.z * other.x,
            yz: self.y * other.z - self.z * other.y,
        }
    }

    /// Returns the cross product of two vectors (Hodge dual of the wedge product).
    pub fn cross(self, other: Self) -> Self {
        Self {
            x: self.y * other.z - self.z * other.y,
            y: self.z * other.x - self.x * other.z,
            z: self.x * other.y - self.y * other.x,
        }
    }
}

impl<T: Real> Basis<0> for Vector<T> {
    fn unit_basis() -> Self {
        Self {
            x: T::one(),
            y: T::zero(),
            z: T::zero(),
        }
    }

    fn basis_of(x: T) -> Self {
        Self {
            x,
            y: T::zero(),
            z: T::zero(),
        }
    }

    fn basis(&self) -> Self::Scalar {
        self.x
    }

    fn basis_mut(&mut self) -> &mut Self::Scalar {
        &mut self.x
    }

    fn with_basis(self, x: T) -> Self {
        Self { x, ..self }
    }
}

impl<T: Real> Basis<1> for Vector<T> {
    fn unit_basis() -> Self {
        Self {
            x: T::zero(),
            y: T::one(),
            z: T::zero(),
        }
    }

    fn basis_of(y: T) -> Self {
        Self {
            x: T::zero(),
            y,
            z: T::zero(),
        }
    }

    fn basis(&self) -> Self::Scalar {
        self.y
    }

    fn basis_mut(&mut self) -> &mut Self::Scalar {
        &mut self.y
    }

    fn with_basis(self, y: T) -> Self {
        Self { y, ..self }
    }
}

impl<T: Real> Basis<2> for Vector<T> {
    fn unit_basis() -> Self {
        Self {
            x: T::zero(),
            y: T::zero(),
            z: T::one(),
        }
    }

    fn basis_of(z: T) -> Self {
        Self {
            x: T::zero(),
            y: T::zero(),
            z,
        }
    }

    fn basis(&self) -> Self::Scalar {
        self.z
    }

    fn basis_mut(&mut self) -> &mut Self::Scalar {
        &mut self.z
    }

    fn with_basis(self, z: T) -> Self {
        Self { z, ..self }
    }
}

impl<T: Zero> Zero for Vector<T> {
    fn zero() -> Self {
        Self {
            x: T::zero(),
            y: T::zero(),
            z: T::zero(),
        }
    }

    fn is_zero(&self) -> bool {
        self.x.is_zero() && self.y.is_zero() && self.z.is_zero()
    }
}

impl<T> Mul<T> for Vector<T>
where
    T: Mul<Output = T> + Copy,
{
    type Output = Self;
    fn mul(self, other: T) -> Self {
        Self {
            x: self.x * other,
            y: self.y * other,
            z: self.z * other,
        }
    }
}

impl<T> MulAssign<T> for Vector<T>
where
    T: MulAssign + Copy,
{
    fn mul_assign(&mut self, other: T) {
        self.x *= other;
        self.y *= other;
        self.z *= other;
    }
}

impl<T> Div<T> for Vector<T>
where
    T: Div<Output = T> + Copy,
{
    type Output = Self;
    fn div(self, other: T) -> Self {
        Self {
            x: self.x / other,
            y: self.y / other,
            z: self.z / other,
        }
    }
}

impl<T> DivAssign<T> for Vector<T>
where
    T: DivAssign + Copy,
{
    fn div_assign(&mut self, other: T) {
        self.x /= other;
        self.y /= other;
        self.z /= other;
    }
}

impl<T: Real> VectorSpace for Vector<T> {
    type Scalar = T;
}

impl<T: Real> DotProduct for Vector<T> {
    type Output = Self::Scalar;
    fn dot(&self, other: &Self) -> T {
        self.x * other.x + self.y * other.y + self.z * other.z
    }
}

impl<T: Real> DotProduct<Bivector<T>> for Vector<T> {
    type Output = Self;
    fn dot(&self, other: &Bivector<T>) -> Self {
        Self {
            x: self.y * other.xy - self.z * other.xz,
            y: -self.x * other.xy + self.z * other.yz,
            z: self.x * other.xz - self.y * other.yz,
        }
    }
}

impl<T: Real> DotProduct<Rotor<T>> for Vector<T> {
    type Output = Self;
    fn dot(&self, other: &Rotor<T>) -> Self {
        *self * other.scalar
            + Self {
                x: self.y * other.xy - self.z * other.xz,
                y: -self.x * other.xy + self.z * other.yz,
                z: self.x * other.xz - self.y * other.yz,
            }
    }
}

impl<T: Real> Mul for Vector<T> {
    type Output = Rotor<T>;
    fn mul(self, other: Self) -> Rotor<T> {
        Rotor {
            scalar: self.dot(&other),
            xy: self.x * other.y - self.y * other.x,
            xz: self.x * other.z - self.z * other.x,
            yz: self.y * other.z - self.z * other.y,
        }
    }
}

impl<T> From<[T; 3]> for Vector<T> {
    fn from([x, y, z]: [T; 3]) -> Self {
        Self { x, y, z }
    }
}

impl<T> From<Vector<T>> for [T; 3] {
    fn from(Vector { x, y, z }: Vector<T>) -> Self {
        [x, y, z]
    }
}

impl<T> From<(T, T, T)> for Vector<T> {
    fn from((x, y, z): (T, T, T)) -> Self {
        Self { x, y, z }
    }
}

impl<T> From<Vector<T>> for (T, T, T) {
    fn from(Vector { x, y, z }: Vector<T>) -> Self {
        (x, y, z)
    }
}

impl<T: Display> Display for Vector<T> {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
        write!(formatter, "({}, {}, {})", self.x, self.y, self.z)
    }
}

impl<T: FromStr> FromStr for Vector<T> {
    type Err = ParseVectorError;

    fn from_str(source: &str) -> Result<Self, Self::Err> {
        let trimmed = source.trim();
        let inner = trimmed
            .strip_prefix('(')
            .and_then(|s| s.strip_suffix(')'))
            .ok_or(ParseVectorError)?;
        let parts: Vec<&str> = inner.split(',').collect();
        if parts.len() != 3 {
            return Err(ParseVectorError);
        }
        let x = parts[0].trim().parse().map_err(|_| ParseVectorError)?;
        let y = parts[1].trim().parse().map_err(|_| ParseVectorError)?;
        let z = parts[2].trim().parse().map_err(|_| ParseVectorError)?;
        Ok(Self { x, y, z })
    }
}

/// Error returned when parsing a vector from a string fails.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseVectorError;

impl Display for ParseVectorError {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
        write!(formatter, "invalid vector format")
    }
}

impl std::error::Error for ParseVectorError {}
