//! Placeholder component for JSON deserialization
//!
//! When a component type cannot be fully reconstructed (e.g., requires a
//! FluidBackend), this placeholder preserves the topology and parameters
//! so the system graph structure is maintained.

use entropyk_components::{
    Component, ComponentError, ComponentParams, ConnectedPort, JacobianBuilder, ResidualVector,
    StateSlice,
};

/// A placeholder component that preserves serialized parameters.
///
/// Used during JSON deserialization when the original component type
/// requires a FluidBackend or other runtime context that isn't available
/// during reconstruction.
///
/// The placeholder preserves:
/// - Component parameters (for later reconstruction)
/// - Topology position (correct number of equations)
/// - Port count
pub struct ParamsPlaceholder {
    params: ComponentParams,
    n_eq: usize,
    n_ports: usize,
}

impl ParamsPlaceholder {
    /// Creates a new placeholder from the given parameters.
    pub fn new(params: ComponentParams) -> Self {
        // Infer equation count from component type heuristics
        let n_eq = Self::infer_equations(&params.component_type);
        let n_ports = Self::infer_ports(&params.component_type);
        Self {
            params,
            n_eq,
            n_ports,
        }
    }

    fn infer_equations(type_name: &str) -> usize {
        match type_name {
            "Compressor" => 2,
            "ExpansionValve" => 2,
            "Pipe" => 2,
            "Pump" => 2,
            "Fan" => 2,
            "Evaporator" | "Condenser" | "Economizer" => 2,
            "EvaporatorCoil" | "CondenserCoil" => 2,
            "FloodedCondenser" => 3,
            "FloodedEvaporator" => 2,
            "Node" => 2,
            "Drum" => 8,
            "ScrewEconomizerCompressor" | "ScrewCompressor" => 6,
            "RefrigerantSource" | "RefrigerantSink" => 2,
            "AirSource" | "AirSink" => 2,
            "BrineSource" | "BrineSink" => 2,
            _ => 2,
        }
    }

    fn infer_ports(type_name: &str) -> usize {
        match type_name {
            "ScrewEconomizerCompressor" | "ScrewCompressor" => 3,
            _ => 2, // Most components have 2 ports
        }
    }

    /// Returns the stored parameters.
    pub fn params(&self) -> &ComponentParams {
        &self.params
    }

    /// Returns the inferred port count preserved for topology sizing.
    pub fn n_ports(&self) -> usize {
        self.n_ports
    }
}

impl Component for ParamsPlaceholder {
    fn compute_residuals(
        &self,
        _state: &StateSlice,
        residuals: &mut ResidualVector,
    ) -> Result<(), ComponentError> {
        // Zero residuals — placeholder doesn't contribute to solving
        residuals.fill(0.0);
        Ok(())
    }

    fn jacobian_entries(
        &self,
        _state: &StateSlice,
        _jacobian: &mut JacobianBuilder,
    ) -> Result<(), ComponentError> {
        Ok(())
    }

    fn n_equations(&self) -> usize {
        self.n_eq
    }

    fn get_ports(&self) -> &[ConnectedPort] {
        // Placeholder does not maintain real port references.
        // The port count is tracked via n_ports for topology sizing only.
        &[]
    }

    fn signature(&self) -> String {
        format!("Placeholder({})", self.params.component_type)
    }

    fn to_params(&self) -> ComponentParams {
        self.params.clone()
    }
}
