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

/// Categoria de produto segundo a Konduto
///
/// Ref: <https://docs.konduto.com/reference/categorias-de-produtos-e-c%C3%B3digos>
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ProductCategory {
    // Animais & Bichos de Estimação
    AnimalsAndPets, // 100

    // Roupas e Acessórios
    ClothingGeneral,        // 201
    AccessoriesGeneral,     // 202
    CostumesAndAccessories, // 203
    BagWalletAccessories,   // 204
    BagsWalletsSuitcases,   // 205
    Jewelry,                // 206
    ShoeAccessories,        // 207
    Shoes,                  // 208
    ClothingOther,          // 299

    // Arte e Entretenimento
    ArtAndEntertainment, // 300

    // Bebês e Recém-nascidos
    BabiesAndNewborns, // 400

    // Negócios e Indústria
    AdvertisingMarketing, // 501
    Agriculture,          // 502
    Construction,         // 503
    FilmTV,               // 504
    FinanceInsurance,     // 505
    FoodServices,         // 506
    Lumber,               // 507
    HeavyMachinery,       // 508
    HotelLodging,         // 509
    IndustrialWarehouse,  // 510
    MilitaryEquipment,    // 511
    Manufacturing,        // 512
    MaterialHandling,     // 513
    Medicine,             // 514
    Mining,               // 515
    PiercingTattoo,       // 516
    Retail,               // 517
    ScienceLaboratory,    // 518
    SignsSignage,         // 519
    WorkSafetyEquipment,  // 520
    BusinessOther,        // 599

    // Câmeras e Óticas
    Cameras,           // 601
    CameraAccessories, // 602
    Photography,       // 603
    OpticsOther,       // 604

    // Eletrônicos
    Printers3D,                  // 701
    Audio,                       // 702
    CircuitComponents,           // 703
    Communication,               // 704
    Components,                  // 705
    Computers,                   // 706
    ElectronicAccessories,       // 707
    GPSDevice,                   // 708
    GPSAccessories,              // 709
    Networks,                    // 711
    PrintCopyScanFax,            // 712
    PrintCopyScanFaxAccessories, // 713
    Video,                       // 715
    VideoGameConsoles,           // 716
    VideoGameAccessories,        // 717
    ElectronicsOther,            // 799

    // Comidas, Bebidas e Cigarro
    FoodBeveragesTobacco, // 800

    // Móveis
    Furniture, // 900

    // Ferramentas
    Tools, // 1000

    // Saúde e Beleza
    HealthBeauty, // 1100

    // Casa e Jardim
    HomeGarden, // 1200

    // Malas e Bagagens
    LuggageBags, // 1300

    // Adulto
    Adult, // 1400

    // Armas e Munição
    WeaponsAmmunition, // 1500

    // Materiais de Escritório
    OfficeSupplies, // 1600

    // Religião e Cerimoniais
    ReligionCeremonial, // 1700

    // Software
    ComputerSoftware,     // 1801
    DigitalGoodsCurrency, // 1802
    DigitalServices,      // 1803
    VideoGames,           // 1804
    SoftwareOther,        // 1899

    // Equipamento de Esporte
    SportsEquipment, // 1900

    // Brinquedos e Jogos
    ToysGames, // 2000

    // Veículos e Peças
    VehiclesParts, // 2100

    // Livros
    Books, // 2300

    // DVDs e Vídeos
    DVDsVideos, // 2400

    // Revistas e Jornais
    MagazinesNewspapers, // 2500

    // Música
    CDsVinyl,           // 2601
    MusicalInstruments, // 2602
    DigitalMusic,       // 2603
    MusicOther,         // 2699

    // Outras categorias não especificadas
    Unspecified, // 9999

    // Código customizado
    Other(u32),
}

impl ProductCategory {
    /// Retorna o código numérico da categoria
    pub fn code(&self) -> u32 {
        match self {
            // Animais & Bichos de Estimação
            Self::AnimalsAndPets => 100,

            // Roupas e Acessórios
            Self::ClothingGeneral => 201,
            Self::AccessoriesGeneral => 202,
            Self::CostumesAndAccessories => 203,
            Self::BagWalletAccessories => 204,
            Self::BagsWalletsSuitcases => 205,
            Self::Jewelry => 206,
            Self::ShoeAccessories => 207,
            Self::Shoes => 208,
            Self::ClothingOther => 299,

            // Arte e Entretenimento
            Self::ArtAndEntertainment => 300,

            // Bebês e Recém-nascidos
            Self::BabiesAndNewborns => 400,

            // Negócios e Indústria
            Self::AdvertisingMarketing => 501,
            Self::Agriculture => 502,
            Self::Construction => 503,
            Self::FilmTV => 504,
            Self::FinanceInsurance => 505,
            Self::FoodServices => 506,
            Self::Lumber => 507,
            Self::HeavyMachinery => 508,
            Self::HotelLodging => 509,
            Self::IndustrialWarehouse => 510,
            Self::MilitaryEquipment => 511,
            Self::Manufacturing => 512,
            Self::MaterialHandling => 513,
            Self::Medicine => 514,
            Self::Mining => 515,
            Self::PiercingTattoo => 516,
            Self::Retail => 517,
            Self::ScienceLaboratory => 518,
            Self::SignsSignage => 519,
            Self::WorkSafetyEquipment => 520,
            Self::BusinessOther => 599,

            // Câmeras e Óticas
            Self::Cameras => 601,
            Self::CameraAccessories => 602,
            Self::Photography => 603,
            Self::OpticsOther => 604,

            // Eletrônicos
            Self::Printers3D => 701,
            Self::Audio => 702,
            Self::CircuitComponents => 703,
            Self::Communication => 704,
            Self::Components => 705,
            Self::Computers => 706,
            Self::ElectronicAccessories => 707,
            Self::GPSDevice => 708,
            Self::GPSAccessories => 709,
            Self::Networks => 711,
            Self::PrintCopyScanFax => 712,
            Self::PrintCopyScanFaxAccessories => 713,
            Self::Video => 715,
            Self::VideoGameConsoles => 716,
            Self::VideoGameAccessories => 717,
            Self::ElectronicsOther => 799,

            // Comidas, Bebidas e Cigarro
            Self::FoodBeveragesTobacco => 800,

            // Móveis
            Self::Furniture => 900,

            // Ferramentas
            Self::Tools => 1000,

            // Saúde e Beleza
            Self::HealthBeauty => 1100,

            // Casa e Jardim
            Self::HomeGarden => 1200,

            // Malas e Bagagens
            Self::LuggageBags => 1300,

            // Adulto
            Self::Adult => 1400,

            // Armas e Munição
            Self::WeaponsAmmunition => 1500,

            // Materiais de Escritório
            Self::OfficeSupplies => 1600,

            // Religião e Cerimoniais
            Self::ReligionCeremonial => 1700,

            // Software
            Self::ComputerSoftware => 1801,
            Self::DigitalGoodsCurrency => 1802,
            Self::DigitalServices => 1803,
            Self::VideoGames => 1804,
            Self::SoftwareOther => 1899,

            // Equipamento de Esporte
            Self::SportsEquipment => 1900,

            // Brinquedos e Jogos
            Self::ToysGames => 2000,

            // Veículos e Peças
            Self::VehiclesParts => 2100,

            // Livros
            Self::Books => 2300,

            // DVDs e Vídeos
            Self::DVDsVideos => 2400,

            // Revistas e Jornais
            Self::MagazinesNewspapers => 2500,

            // Música
            Self::CDsVinyl => 2601,
            Self::MusicalInstruments => 2602,
            Self::DigitalMusic => 2603,
            Self::MusicOther => 2699,

            // Outras categorias não especificadas
            Self::Unspecified => 9999,

            // Código customizado
            Self::Other(code) => *code,
        }
    }

    /// Retorna o nome da categoria em português
    pub fn name(&self) -> &str {
        match self {
            // Animais & Bichos de Estimação
            Self::AnimalsAndPets => "Animais & Bichos de Estimação",

            // Roupas e Acessórios
            Self::ClothingGeneral => "Roupas em Geral",
            Self::AccessoriesGeneral => "Acessórios em Geral",
            Self::CostumesAndAccessories => "Fantasias e Acessórios",
            Self::BagWalletAccessories => "Acessórios para Bolsas e Carteiras",
            Self::BagsWalletsSuitcases => "Bolsas, Carteiras e Malas",
            Self::Jewelry => "Jóias",
            Self::ShoeAccessories => "Acessórios para Sapatos",
            Self::Shoes => "Sapatos",
            Self::ClothingOther => "Roupas - Outros",

            // Arte e Entretenimento
            Self::ArtAndEntertainment => "Arte e Entretenimento",

            // Bebês e Recém-nascidos
            Self::BabiesAndNewborns => "Bebês e Recém-nascidos",

            // Negócios e Indústria
            Self::AdvertisingMarketing => "Propaganda e Marketing",
            Self::Agriculture => "Agricultura",
            Self::Construction => "Construção",
            Self::FilmTV => "Filme e Televisão",
            Self::FinanceInsurance => "Finanças e Seguros",
            Self::FoodServices => "Serviços de Alimentação",
            Self::Lumber => "Madeireiras",
            Self::HeavyMachinery => "Maquinário Pesado",
            Self::HotelLodging => "Hotel e Hospedagem",
            Self::IndustrialWarehouse => "Armazém Industrial",
            Self::MilitaryEquipment => "Equipamentos Militares",
            Self::Manufacturing => "Manufatura",
            Self::MaterialHandling => "Movimentação de Material",
            Self::Medicine => "Medicina",
            Self::Mining => "Mineração",
            Self::PiercingTattoo => "Piercing e tatuagem",
            Self::Retail => "Varejo",
            Self::ScienceLaboratory => "Ciência e Laboratórios",
            Self::SignsSignage => "Placas e Sinais",
            Self::WorkSafetyEquipment => "Equipamentos de Segurança do Trabalho",
            Self::BusinessOther => "Negócios - Outros",

            // Câmeras e Óticas
            Self::Cameras => "Câmeras",
            Self::CameraAccessories => "Acessórios de câmeras",
            Self::Photography => "Fotografia",
            Self::OpticsOther => "Câmeras e Óticas - Outros",

            // Eletrônicos
            Self::Printers3D => "Impressoras 3D",
            Self::Audio => "Áudio",
            Self::CircuitComponents => "Componentes de Circuito",
            Self::Communication => "Comunicação",
            Self::Components => "Componentes",
            Self::Computers => "Computadores",
            Self::ElectronicAccessories => "Acessórios Eletrônicos",
            Self::GPSDevice => "Aparelho GPS",
            Self::GPSAccessories => "Acessórios de GPS",
            Self::Networks => "Redes",
            Self::PrintCopyScanFax => "Impressão, Cópia, Scanner e Fax",
            Self::PrintCopyScanFaxAccessories => "Acessórios de Impressão, Cópia, Scanner e Fax",
            Self::Video => "Vídeo",
            Self::VideoGameConsoles => "Consoles de Vídeo Game",
            Self::VideoGameAccessories => "Acessórios de Vídeo Game",
            Self::ElectronicsOther => "Eletrônicos - Outros",

            // Comidas, Bebidas e Cigarro
            Self::FoodBeveragesTobacco => "Comidas, Bebidas e Cigarro",

            // Móveis
            Self::Furniture => "Móveis",

            // Ferramentas
            Self::Tools => "Ferramentas",

            // Saúde e Beleza
            Self::HealthBeauty => "Saúde e Beleza",

            // Casa e Jardim
            Self::HomeGarden => "Casa e Jardim",

            // Malas e Bagagens
            Self::LuggageBags => "Malas e Bagagens",

            // Adulto
            Self::Adult => "Adulto",

            // Armas e Munição
            Self::WeaponsAmmunition => "Armas e Munição",

            // Materiais de Escritório
            Self::OfficeSupplies => "Materiais de Escritório",

            // Religião e Cerimoniais
            Self::ReligionCeremonial => "Religião e Cerimoniais",

            // Software
            Self::ComputerSoftware => "Software de Computador",
            Self::DigitalGoodsCurrency => "Bens e Moedas Digitais",
            Self::DigitalServices => "Serviços Digitais",
            Self::VideoGames => "Jogos de Vídeo Games",
            Self::SoftwareOther => "Software - Outros",

            // Equipamento de Esporte
            Self::SportsEquipment => "Equipamento de Esporte",

            // Brinquedos e Jogos
            Self::ToysGames => "Brinquedos e Jogos",

            // Veículos e Peças
            Self::VehiclesParts => "Veículos e Peças",

            // Livros
            Self::Books => "Livros",

            // DVDs e Vídeos
            Self::DVDsVideos => "DVDs e Vídeos",

            // Revistas e Jornais
            Self::MagazinesNewspapers => "Revistas e Jornais",

            // Música
            Self::CDsVinyl => "CDs e Vinil",
            Self::MusicalInstruments => "Instrumentos Musicais",
            Self::DigitalMusic => "Música Digital",
            Self::MusicOther => "Música - Outros",

            // Outras categorias não especificadas
            Self::Unspecified => "Outras categorias não especificadas",

            // Código customizado
            Self::Other(_) => "Outro",
        }
    }

    /// Cria uma categoria a partir de um código
    fn from_code(code: u32) -> Result<Self, ValidationError> {
        if code == 0 {
            return Err(ValidationError::InvalidFormat {
                field: "category".to_string(),
                message: "category code must be greater than 0".to_string(),
            });
        }

        Ok(match code {
            // Animais & Bichos de Estimação
            100 => Self::AnimalsAndPets,

            // Roupas e Acessórios
            201 => Self::ClothingGeneral,
            202 => Self::AccessoriesGeneral,
            203 => Self::CostumesAndAccessories,
            204 => Self::BagWalletAccessories,
            205 => Self::BagsWalletsSuitcases,
            206 => Self::Jewelry,
            207 => Self::ShoeAccessories,
            208 => Self::Shoes,
            299 => Self::ClothingOther,

            // Arte e Entretenimento
            300 => Self::ArtAndEntertainment,

            // Bebês e Recém-nascidos
            400 => Self::BabiesAndNewborns,

            // Negócios e Indústria
            501 => Self::AdvertisingMarketing,
            502 => Self::Agriculture,
            503 => Self::Construction,
            504 => Self::FilmTV,
            505 => Self::FinanceInsurance,
            506 => Self::FoodServices,
            507 => Self::Lumber,
            508 => Self::HeavyMachinery,
            509 => Self::HotelLodging,
            510 => Self::IndustrialWarehouse,
            511 => Self::MilitaryEquipment,
            512 => Self::Manufacturing,
            513 => Self::MaterialHandling,
            514 => Self::Medicine,
            515 => Self::Mining,
            516 => Self::PiercingTattoo,
            517 => Self::Retail,
            518 => Self::ScienceLaboratory,
            519 => Self::SignsSignage,
            520 => Self::WorkSafetyEquipment,
            599 => Self::BusinessOther,

            // Câmeras e Óticas
            601 => Self::Cameras,
            602 => Self::CameraAccessories,
            603 => Self::Photography,
            604 => Self::OpticsOther,

            // Eletrônicos
            701 => Self::Printers3D,
            702 => Self::Audio,
            703 => Self::CircuitComponents,
            704 => Self::Communication,
            705 => Self::Components,
            706 => Self::Computers,
            707 => Self::ElectronicAccessories,
            708 => Self::GPSDevice,
            709 => Self::GPSAccessories,
            711 => Self::Networks,
            712 => Self::PrintCopyScanFax,
            713 => Self::PrintCopyScanFaxAccessories,
            715 => Self::Video,
            716 => Self::VideoGameConsoles,
            717 => Self::VideoGameAccessories,
            799 => Self::ElectronicsOther,

            // Comidas, Bebidas e Cigarro
            800 => Self::FoodBeveragesTobacco,

            // Móveis
            900 => Self::Furniture,

            // Ferramentas
            1000 => Self::Tools,

            // Saúde e Beleza
            1100 => Self::HealthBeauty,

            // Casa e Jardim
            1200 => Self::HomeGarden,

            // Malas e Bagagens
            1300 => Self::LuggageBags,

            // Adulto
            1400 => Self::Adult,

            // Armas e Munição
            1500 => Self::WeaponsAmmunition,

            // Materiais de Escritório
            1600 => Self::OfficeSupplies,

            // Religião e Cerimoniais
            1700 => Self::ReligionCeremonial,

            // Software
            1801 => Self::ComputerSoftware,
            1802 => Self::DigitalGoodsCurrency,
            1803 => Self::DigitalServices,
            1804 => Self::VideoGames,
            1899 => Self::SoftwareOther,

            // Equipamento de Esporte
            1900 => Self::SportsEquipment,

            // Brinquedos e Jogos
            2000 => Self::ToysGames,

            // Veículos e Peças
            2100 => Self::VehiclesParts,

            // Livros
            2300 => Self::Books,

            // DVDs e Vídeos
            2400 => Self::DVDsVideos,

            // Revistas e Jornais
            2500 => Self::MagazinesNewspapers,

            // Música
            2601 => Self::CDsVinyl,
            2602 => Self::MusicalInstruments,
            2603 => Self::DigitalMusic,
            2699 => Self::MusicOther,

            // Outras categorias não especificadas
            9999 => Self::Unspecified,

            // Código customizado
            other => Self::Other(other),
        })
    }

    /// Retorna o código da categoria (mantido para compatibilidade)
    pub fn value(&self) -> u32 {
        self.code()
    }
}

impl TryFrom<u32> for ProductCategory {
    type Error = ValidationError;

    fn try_from(value: u32) -> Result<Self, Self::Error> {
        Self::from_code(value)
    }
}

impl fmt::Display for ProductCategory {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.code())
    }
}

// Serialização: envia o código numérico
impl Serialize for ProductCategory {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_u32(self.code())
    }
}

// Deserialização: recebe o código numérico
impl<'de> Deserialize<'de> for ProductCategory {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let code = u32::deserialize(deserializer)?;
        ProductCategory::from_code(code).map_err(serde::de::Error::custom)
    }
}

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

    #[test]
    fn test_category_enum_code() {
        assert_eq!(ProductCategory::ClothingGeneral.code(), 201);
        assert_eq!(ProductCategory::Computers.code(), 706);
        assert_eq!(ProductCategory::Books.code(), 2300);
    }

    #[test]
    fn test_category_enum_name() {
        assert_eq!(ProductCategory::ClothingGeneral.name(), "Roupas em Geral");
        assert_eq!(ProductCategory::Computers.name(), "Computadores");
        assert_eq!(ProductCategory::Books.name(), "Livros");
    }

    #[test]
    fn test_category_from_code() {
        let cat = ProductCategory::from_code(201).unwrap();
        assert_eq!(cat, ProductCategory::ClothingGeneral);
        assert_eq!(cat.name(), "Roupas em Geral");
    }

    #[test]
    fn test_category_from_code_custom() {
        let cat = ProductCategory::from_code(99999).unwrap();
        assert_eq!(cat.code(), 99999);
        assert_eq!(cat.name(), "Outro");
    }

    #[test]
    fn test_category_zero() {
        let result = ProductCategory::from_code(0);
        assert!(result.is_err());
    }

    #[test]
    fn test_category_serialization() {
        let cat = ProductCategory::Computers;
        let json = serde_json::to_string(&cat).unwrap();
        assert_eq!(json, "706");
    }

    #[test]
    fn test_category_deserialization() {
        let json = "201";
        let cat: ProductCategory = serde_json::from_str(json).unwrap();
        assert_eq!(cat, ProductCategory::ClothingGeneral);
    }

    #[test]
    fn test_category_roundtrip() {
        let original = ProductCategory::VideoGames;
        let json = serde_json::to_string(&original).unwrap();
        let deserialized: ProductCategory = serde_json::from_str(&json).unwrap();
        assert_eq!(original, deserialized);
    }

    #[test]
    fn test_category_other_roundtrip() {
        let original = ProductCategory::Other(12345);
        let json = serde_json::to_string(&original).unwrap();
        let deserialized: ProductCategory = serde_json::from_str(&json).unwrap();
        assert_eq!(original, deserialized);
        assert_eq!(deserialized.code(), 12345);
    }

    #[test]
    fn test_all_clothing_categories() {
        let categories = vec![
            (ProductCategory::ClothingGeneral, 201),
            (ProductCategory::AccessoriesGeneral, 202),
            (ProductCategory::Shoes, 208),
        ];

        for (cat, expected_code) in categories {
            assert_eq!(cat.code(), expected_code);
        }
    }

    #[test]
    fn test_all_electronics_categories() {
        let categories = vec![
            ProductCategory::Computers,
            ProductCategory::Audio,
            ProductCategory::VideoGameConsoles,
        ];

        for cat in categories {
            assert!(cat.code() >= 701 && cat.code() <= 799);
        }
    }

    #[test]
    fn test_category_display() {
        let cat = ProductCategory::Books;
        assert_eq!(format!("{}", cat), "2300");
    }

    #[test]
    fn test_backward_compatibility_new() {
        let cat = ProductCategory::try_from(201).unwrap();
        assert_eq!(cat, ProductCategory::ClothingGeneral);
    }

    #[test]
    fn test_backward_compatibility_value() {
        let cat = ProductCategory::Computers;
        assert_eq!(cat.value(), 706);
    }
}
