//! gRPC Anti-Corruption Layer - Type System Migration
//!
//! This module provides conversion traits between the canonical unified types
//! and external gRPC protocol types. Implements the anti-corruption layer pattern
//! to isolate our clean business domain types from external protocol formats.
//!
//! # Architecture Pattern
//! - **Canonical Types**: `unified.rs` types represent our business domain
//! - **Protocol Types**: Generated gRPC types for wire protocol compatibility
//! - **Conversion Layer**: This module bridges the two type systems safely
//!
//! # Agent 245 Type System Migration
//! This addresses the critical issue of 50+ duplicate type definitions by
//! establishing a single conversion boundary for all external type interactions.

use super::*;
use crate::types::unified::{Order, OrderId, Price, Quantity, RequestId, Side, Symbol, Timestamp};
use rust_decimal::Decimal;
use std::str::FromStr;

// Import the gRPC types (these would come from your proto generation)
// For now, we'll define minimal types to make it compile
#[derive(Debug, Clone)]
pub struct GrpcOrder {
    pub id: String,
    pub symbol: String,
    pub side: i32,
    pub price: String,
    pub quantity: String,
    pub timestamp: i64,
}

#[derive(Debug, Clone)]
pub struct GrpcOrderRequest {
    pub request_id: String,
    pub order: Option<GrpcOrder>,
}

#[derive(Debug, Clone)]
pub struct RequestWithOrder {
    pub request_id: RequestId,
    pub order: Order,
}

// Conversion implementations
impl From<GrpcOrder> for Order {
    fn from(grpc: GrpcOrder) -> Self {
        Order {
            id: OrderId(grpc.id),
            symbol: Symbol::new(grpc.symbol),
            side: match grpc.side {
                0 => Side::Buy,
                1 => Side::Sell,
                _ => Side::Buy, // Default
            },
            price: Price(Decimal::from_str(&grpc.price).unwrap_or(Decimal::ZERO)),
            quantity: Quantity(Decimal::from_str(&grpc.quantity).unwrap_or(Decimal::ZERO)),
            timestamp: Timestamp::from_micros(grpc.timestamp as u64),
        }
    }
}

impl From<Order> for GrpcOrder {
    fn from(order: Order) -> Self {
        GrpcOrder {
            id: order.id.0,
            symbol: order.symbol.as_str().to_string(),
            side: match order.side {
                Side::Buy => 0,
                Side::Sell => 1,
            },
            price: order.price.0.to_string(),
            quantity: order.quantity.0.to_string(),
            timestamp: order.timestamp.as_micros() as i64,
        }
    }
}

impl From<GrpcOrderRequest> for RequestWithOrder {
    fn from(grpc: GrpcOrderRequest) -> Self {
        RequestWithOrder {
            request_id: RequestId(grpc.request_id),
            order: grpc.order.map(Order::from).unwrap_or_else(|| Order {
                id: OrderId("default".to_string()),
                symbol: Symbol::new("UNKNOWN"),
                side: Side::Buy,
                price: Price(Decimal::ZERO),
                quantity: Quantity(Decimal::ZERO),
                timestamp: Timestamp::now(),
            }),
        }
    }
}

impl From<RequestWithOrder> for GrpcOrderRequest {
    fn from(req: RequestWithOrder) -> Self {
        GrpcOrderRequest {
            request_id: req.request_id.0,
            order: Some(GrpcOrder::from(req.order)),
        }
    }
}

// Additional conversion traits for other types as needed
// These would normally be generated from protobuf definitions

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

    #[test]
    fn test_order_conversion_roundtrip() {
        let order = Order {
            id: OrderId("test123".to_string()),
            symbol: Symbol::new("AAPL"),
            side: Side::Buy,
            price: Price(Decimal::from_str("150.50").unwrap()),
            quantity: Quantity(Decimal::from_str("100").unwrap()),
            timestamp: Timestamp::now(),
        };

        let grpc = GrpcOrder::from(order.clone());
        let back = Order::from(grpc);

        assert_eq!(order.id, back.id);
        assert_eq!(order.symbol, back.symbol);
        assert_eq!(order.side, back.side);
    }

    #[test]
    fn test_request_with_order_conversion() {
        let req = RequestWithOrder {
            request_id: RequestId("req123".to_string()),
            order: Order {
                id: OrderId("ord456".to_string()),
                symbol: Symbol::new("GOOGL"),
                side: Side::Sell,
                price: Price(Decimal::from_str("2500.00").unwrap()),
                quantity: Quantity(Decimal::from_str("50").unwrap()),
                timestamp: Timestamp::now(),
            },
        };

        let grpc = GrpcOrderRequest::from(req.clone());
        let back = RequestWithOrder::from(grpc);

        assert_eq!(req.request_id, back.request_id);
        assert_eq!(req.order.id, back.order.id);
    }
}