"""Tests for CircuitKnitting package."""  # noqa: N999

from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator

#import QCut as ck
import tests.solutions_automatic_cuts as sq
from QCut import find_cuts
from QCut.circuit_knitting import run_cut_circuit


def test_find_cuts() -> None:
    """Test find_cuts function.

    This function tests whether the find_cuts method correctly identifies the cut
    locations in the provided test circuits by comparing the result to the
    pre-defined solutions.
    """
    for solution_index, circ in enumerate(sq.test_circuits):

        cut_circuit = find_cuts(circ.copy(), 
                                sq.cut_sizes[solution_index], 
                                cuts="both")

        assert len(cut_circuit.subcircuits) == sq.cut_sizes[solution_index]

circuit  =  QuantumCircuit(4)

mult = 1.635
circuit.r(mult*0.46262, mult*0.1446, 0)
circuit.cx(0,1)
circuit.cx(1,2)
circuit.cx(2,3)

def test_find_gate_cuts():
    """Test find_cuts function on a circuit with a cut gate.

    This function tests whether the find_cuts method correctly identifies the cut
    locations in a circuit containing a cut gate by comparing the result to the
    expected number of subcircuits.
    """
    cut_circuit = find_cuts(circuit.copy(), 2, cuts="both")

    assert len(cut_circuit.subcircuits) == 2

    for circ in cut_circuit.subcircuits:
        for op in circ.data:
            assert "meas" not in op.operation.name.lower()
            assert "init" not in op.operation.name.lower()

def test_expectation_values() -> None:
    """Test the expectation values of the test circuits.

    This function tests whether the run method correctly calculates the expectation
    values for each test circuit and its corresponding observable by comparing the
    results to the pre-defined solutions within a specified error tolerance.

    The test runs each circuit on the AerSimulator backend without error mitigation.
    """
    # Initialize the simulator
    sim = AerSimulator()

    # Iterate over each test circuit and its corresponding expected solutions
    for solution_index, circ in enumerate(sq.test_circuits):
        print(solution_index)

        cut_circuit = find_cuts(circ.copy(), 
                                                          sq.cut_sizes[solution_index], 
                                                          cuts="both")

        # Calculate expectation values using the run method
        estimated_expectation_values = run_cut_circuit(cut_circuit, 
                                                          sq.test_observables[solution_index], 
                                                          sim)
        # Check each calculated expectation value against the corresponding
        # expected value
        tolerance = 0.1
        print(estimated_expectation_values)
        print(sq.exp_val_solutions[solution_index])
        for check in [
            abs(a - b) <= tolerance
            for a, b in zip(estimated_expectation_values, 
                            sq.exp_val_solutions[solution_index])
        ]:
            assert check  # noqa: S101
