use crate::types::validation_errors::ValidationError;
use serde::{Deserialize, Serialize};

use super::{
    Renavam, VehicleId, VehicleMake, VehicleModel, VehicleOwner, VehicleRegistration, VehicleType,
    VehicleUsage,
};

/// Dados do veículo
///
/// Ref: <https://docs.konduto.com/reference/vehicles-1>
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Vehicle {
    /// Marca do veículo (obrigatório)
    pub make: VehicleMake,

    /// Modelo do veículo (obrigatório)
    pub model: VehicleModel,

    /// Proprietário do veículo (obrigatório)
    pub owner: VehicleOwner,

    /// VID - Identificador único do veículo (recomendado)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub vid: Option<VehicleId>,

    /// RENAVAM (recomendado)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub renavam: Option<Renavam>,

    /// Placa/Licença do veículo (recomendado)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub registration: Option<VehicleRegistration>,

    /// Tipo do veículo (recomendado)
    #[serde(rename = "type")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub vehicle_type: Option<VehicleType>,

    /// Uso do veículo (recomendado)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub usage: Option<VehicleUsage>,
}

impl Vehicle {
    /// Cria um builder para construir um veículo
    pub fn builder() -> VehicleBuilder {
        VehicleBuilder::default()
    }
}

/// Builder para criar veículos
#[derive(Default)]
pub struct VehicleBuilder {
    make: Option<VehicleMake>,
    model: Option<VehicleModel>,
    owner: Option<VehicleOwner>,
    vid: Option<VehicleId>,
    renavam: Option<Renavam>,
    registration: Option<VehicleRegistration>,
    vehicle_type: Option<VehicleType>,
    usage: Option<VehicleUsage>,
}

impl VehicleBuilder {
    pub fn make(mut self, make: VehicleMake) -> Self {
        self.make = Some(make);
        self
    }

    pub fn make_str(mut self, make: impl Into<String>) -> Result<Self, ValidationError> {
        self.make = Some(VehicleMake::try_new(make)?);
        Ok(self)
    }

    pub fn model(mut self, model: VehicleModel) -> Self {
        self.model = Some(model);
        self
    }

    pub fn model_str(mut self, model: impl Into<String>) -> Result<Self, ValidationError> {
        self.model = Some(VehicleModel::try_new(model)?);
        Ok(self)
    }

    pub fn owner(mut self, owner: VehicleOwner) -> Self {
        self.owner = Some(owner);
        self
    }

    pub fn vid(mut self, vid: VehicleId) -> Self {
        self.vid = Some(vid);
        self
    }

    pub fn vid_str(mut self, vid: impl Into<String>) -> Result<Self, ValidationError> {
        self.vid = Some(VehicleId::try_new(vid)?);
        Ok(self)
    }

    pub fn renavam(mut self, renavam: Renavam) -> Self {
        self.renavam = Some(renavam);
        self
    }

    pub fn renavam_str(mut self, renavam: impl Into<String>) -> Result<Self, ValidationError> {
        self.renavam = Some(Renavam::try_new(renavam)?);
        Ok(self)
    }

    pub fn registration(mut self, registration: VehicleRegistration) -> Self {
        self.registration = Some(registration);
        self
    }

    pub fn registration_str(
        mut self,
        registration: impl Into<String>,
    ) -> Result<Self, ValidationError> {
        self.registration = Some(VehicleRegistration::try_new(registration)?);
        Ok(self)
    }

    pub fn vehicle_type(mut self, vehicle_type: VehicleType) -> Self {
        self.vehicle_type = Some(vehicle_type);
        self
    }

    pub fn vehicle_type_str(
        mut self,
        vehicle_type: impl Into<String>,
    ) -> Result<Self, ValidationError> {
        self.vehicle_type = Some(VehicleType::new(vehicle_type)?);
        Ok(self)
    }

    pub fn usage(mut self, usage: VehicleUsage) -> Self {
        self.usage = Some(usage);
        self
    }

    pub fn usage_str(mut self, usage: impl Into<String>) -> Result<Self, ValidationError> {
        self.usage = Some(VehicleUsage::new(usage)?);
        Ok(self)
    }

    pub fn build(self) -> Result<Vehicle, ValidationError> {
        Ok(Vehicle {
            make: self
                .make
                .ok_or_else(|| ValidationError::EmptyField("vehicle_make".to_string()))?,
            model: self
                .model
                .ok_or_else(|| ValidationError::EmptyField("vehicle_model".to_string()))?,
            owner: self
                .owner
                .ok_or_else(|| ValidationError::EmptyField("vehicle_owner".to_string()))?,
            vid: self.vid,
            renavam: self.renavam,
            registration: self.registration,
            vehicle_type: self.vehicle_type,
            usage: self.usage,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_vehicle_complete() {
        let owner = VehicleOwner::builder()
            .tax_id_str("540.830.640-21")
            .unwrap()
            .name_str("Cicero")
            .unwrap()
            .build()
            .unwrap();

        let vehicle = Vehicle::builder()
            .make_str("Bentley")
            .unwrap()
            .model_str("Bacalar")
            .unwrap()
            .owner(owner)
            .vid_str("5GZCZ43D13S812715")
            .unwrap()
            .renavam_str("12312312312")
            .unwrap()
            .registration_str("ABC1234")
            .unwrap()
            .vehicle_type(VehicleType::Car)
            .usage(VehicleUsage::Private)
            .build()
            .unwrap();

        assert_eq!(vehicle.make.as_str(), "Bentley");
        assert_eq!(vehicle.model.as_str(), "Bacalar");
        assert_eq!(vehicle.vid.unwrap().as_str(), "5GZCZ43D13S812715");
        assert_eq!(vehicle.renavam.unwrap().as_str(), "12312312312");
        assert_eq!(vehicle.registration.unwrap().as_str(), "ABC1234");
    }

    #[test]
    fn test_vehicle_minimal() {
        let owner = VehicleOwner::builder()
            .tax_id_str("123.456.789-00")
            .unwrap()
            .build()
            .unwrap();

        let vehicle = Vehicle::builder()
            .make_str("Toyota")
            .unwrap()
            .model_str("Corolla")
            .unwrap()
            .owner(owner)
            .build()
            .unwrap();

        assert_eq!(vehicle.make.as_str(), "Toyota");
        assert_eq!(vehicle.model.as_str(), "Corolla");
        assert!(vehicle.vid.is_none());
        assert!(vehicle.vehicle_type.is_none());
    }

    #[test]
    fn test_vehicle_missing_make() {
        let owner = VehicleOwner::builder()
            .tax_id_str("123.456.789-00")
            .unwrap()
            .build()
            .unwrap();

        let result = Vehicle::builder()
            .model_str("Test")
            .unwrap()
            .owner(owner)
            .build();

        assert!(result.is_err());
    }

    #[test]
    fn test_vehicle_missing_model() {
        let owner = VehicleOwner::builder()
            .tax_id_str("123.456.789-00")
            .unwrap()
            .build()
            .unwrap();

        let result = Vehicle::builder()
            .make_str("Test")
            .unwrap()
            .owner(owner)
            .build();

        assert!(result.is_err());
    }

    #[test]
    fn test_vehicle_missing_owner() {
        let result = Vehicle::builder()
            .make_str("Ford")
            .unwrap()
            .model_str("Mustang")
            .unwrap()
            .build();

        assert!(result.is_err());
    }

    #[test]
    fn test_vehicle_serialization() {
        let owner = VehicleOwner::builder()
            .tax_id_str("111.222.333-44")
            .unwrap()
            .name_str("João")
            .unwrap()
            .build()
            .unwrap();

        let vehicle = Vehicle::builder()
            .make_str("Honda")
            .unwrap()
            .model_str("Civic")
            .unwrap()
            .owner(owner)
            .registration_str("XYZ9876")
            .unwrap()
            .vehicle_type(VehicleType::Car)
            .usage(VehicleUsage::Private)
            .build()
            .unwrap();

        let json = serde_json::to_string_pretty(&vehicle).unwrap();
        assert!(json.contains("Honda"));
        assert!(json.contains("Civic"));
        assert!(json.contains("XYZ9876"));
        assert!(json.contains("car"));
        assert!(json.contains("private"));
    }

    #[test]
    fn test_vehicle_deserialization() {
        let json = r#"{
            "make": "Bentley",
            "model": "Bacalar",
            "renavam": "12312312312",
            "registration": "ABC1234",
            "vid": "5GZCZ43D13S812715",
            "type": "car",
            "usage": "private",
            "owner": {
                "tax_id": "540.830.640-21",
                "name": "Cicero"
            }
        }"#;

        let vehicle: Vehicle = serde_json::from_str(json).unwrap();

        assert_eq!(vehicle.make.as_str(), "Bentley");
        assert_eq!(vehicle.model.as_str(), "Bacalar");
        assert_eq!(vehicle.renavam.as_ref().unwrap().as_str(), "12312312312");
        assert_eq!(vehicle.vehicle_type, Some(VehicleType::Car));
        assert_eq!(vehicle.usage, Some(VehicleUsage::Private));
    }

    #[test]
    fn test_vehicle_roundtrip() {
        let owner = VehicleOwner::builder()
            .tax_id_str("123.456.789-00")
            .unwrap()
            .build()
            .unwrap();

        let original = Vehicle::builder()
            .make_str("Volkswagen")
            .unwrap()
            .model_str("Golf")
            .unwrap()
            .owner(owner)
            .registration_str("ABC1234")
            .unwrap()
            .build()
            .unwrap();

        let json = serde_json::to_string(&original).unwrap();
        let deserialized: Vehicle = serde_json::from_str(&json).unwrap();

        assert_eq!(original, deserialized);
    }

    #[test]
    fn test_vehicle_types() {
        let types = vec![
            VehicleType::Car,
            VehicleType::Bus,
            VehicleType::Truck,
            VehicleType::Motorcycle,
            VehicleType::Aircraft,
            VehicleType::Boat,
            VehicleType::Bicycle,
        ];

        for vehicle_type in types {
            let owner = VehicleOwner::builder()
                .tax_id_str("123")
                .unwrap()
                .build()
                .unwrap();

            let vehicle = Vehicle::builder()
                .make_str("Test")
                .unwrap()
                .model_str("Model")
                .unwrap()
                .owner(owner)
                .vehicle_type(vehicle_type.clone())
                .build()
                .unwrap();

            assert_eq!(vehicle.vehicle_type, Some(vehicle_type));
        }
    }

    #[test]
    fn test_vehicle_usages() {
        let usages = vec![
            VehicleUsage::Private,
            VehicleUsage::Commercial,
            VehicleUsage::Government,
            VehicleUsage::Military,
        ];

        for usage in usages {
            let owner = VehicleOwner::builder()
                .tax_id_str("123")
                .unwrap()
                .build()
                .unwrap();

            let vehicle = Vehicle::builder()
                .make_str("Test")
                .unwrap()
                .model_str("Model")
                .unwrap()
                .owner(owner)
                .usage(usage.clone())
                .build()
                .unwrap();

            assert_eq!(vehicle.usage, Some(usage));
        }
    }
}
