//! Temporary debug test — will be deleted.
#![allow(clippy::needless_range_loop)]
use entropyk_components::{Component, ComponentError, JacobianBuilder, ResidualVector, StateSlice};
use entropyk_solver::solver::{NewtonConfig, Solver};
use entropyk_solver::system::System;
use entropyk_solver::system::DEFAULT_MASS_FLOW_SEED_KG_S;

struct LinearSystem {
    a: Vec<Vec<f64>>,
    b: Vec<f64>,
    n: usize,
}

impl Component for LinearSystem {
    fn compute_residuals(
        &self,
        state: &StateSlice,
        residuals: &mut ResidualVector,
    ) -> Result<(), ComponentError> {
        for i in 0..self.n {
            let mut ax_i = 0.0;
            for j in 0..self.n {
                ax_i += self.a[i][j] * state[1 + j];
            }
            residuals[i] = ax_i - self.b[i];
        }
        residuals[self.n] = state[0] - DEFAULT_MASS_FLOW_SEED_KG_S;
        Ok(())
    }

    fn jacobian_entries(
        &self,
        _state: &StateSlice,
        jacobian: &mut JacobianBuilder,
    ) -> Result<(), ComponentError> {
        for i in 0..self.n {
            for j in 0..self.n {
                jacobian.add_entry(i, 1 + j, self.a[i][j]);
            }
        }
        jacobian.add_entry(self.n, 0, 1.0);
        Ok(())
    }

    fn n_equations(&self) -> usize {
        self.n + 1
    }

    fn get_ports(&self) -> &[entropyk_components::ConnectedPort] {
        &[]
    }
}

#[test]
fn debug_newton_linear() {
    let mut system = System::new();
    let n0 = system.add_component(Box::new(LinearSystem {
        a: vec![vec![2.0, 1.0], vec![1.0, 2.0]],
        b: vec![3.0, 3.0],
        n: 2,
    }));
    system.add_edge(n0, n0).unwrap();
    system.finalize().unwrap();

    println!("state_vector_len = {}", system.state_vector_len());
    println!("full_state_vector_len = {}", system.full_state_vector_len());

    // CM1.4: seed at the analytical solution to avoid zero-seed conditioning issues
    // on the constant Jacobian.
    let mut newton =
        NewtonConfig::default().with_initial_state(vec![DEFAULT_MASS_FLOW_SEED_KG_S, 1.0, 1.0]);
    let result = newton.solve(&mut system);
    match &result {
        Ok(c) => println!(
            "OK: converged={} iters={} residual={}",
            c.is_converged(),
            c.iterations,
            c.final_residual
        ),
        Err(e) => println!("ERR: {:?}", e),
    }
    assert!(result.is_ok());
}
