# Copyright (C) 2024 qBraid
#
# This file is part of the qBraid-SDK
#
# The qBraid-SDK is free software released under the GNU General Public License v3
# or later. You can redistribute and/or modify it under the terms of the GPL v3.
# See the LICENSE file in the project root or <https://www.gnu.org/licenses/gpl-3.0.html>.
#
# THERE IS NO WARRANTY for the qBraid-SDK, as per Section 15 of the GPL v3.

"""
Unit tests for qasm2 to qasm3 transpilation

"""
import pyqasm
import pytest
from qiskit.circuit import QuantumCircuit
from qiskit.qasm2 import dumps as qasm2_dumps
from qiskit.qasm3 import loads as qasm3_loads

from qbraid._logging import logger
from qbraid.interface import circuits_allclose
from qbraid.interface.random import random_circuit
from qbraid.transpiler.conversions.qasm2.qasm2_to_qasm3 import qasm2_to_qasm3


def _generate_valid_qasm_strings(seed=42, gates_to_skip=None, num_circuits=100):
    """Returns a list of 100 random qasm2 strings
    which do not contain any of the gates in gates_to_skip

    Current list of invalid gates is ["u", "cu1", "cu2", "cu3", "rxx", "xx_minus_yy"]
    For the motivation, see discussion
    - https://github.com/Qiskit/qiskit-qasm3-import/issues/12
    - https://github.com/Qiskit/qiskit-qasm3-import/issues/11#issuecomment-1568505732
    """
    if gates_to_skip is None:
        gates_to_skip = []

    qasm_strings = []
    while len(qasm_strings) < num_circuits:
        try:
            circuit_random = random_circuit("qiskit", seed=seed)
            qasm_str = qasm2_dumps(circuit_random)
            circuit_from_qasm = QuantumCircuit.from_qasm_str(qasm_str)
        except Exception as e:  # pylint: disable=broad-exception-caught
            logger.error("Invalid QASM generated by random_circuit: %s", e)
            continue

        for gate in gates_to_skip:
            if len(circuit_from_qasm.get_instructions(gate)) > 0:
                break
        else:
            qasm_strings.append(qasm_str)

    return qasm_strings


@pytest.mark.parametrize(
    "qasm2_str", _generate_valid_qasm_strings(gates_to_skip=["r", "rccx", "xx_minus_yy"])
)
def test_random_conversion_to_qasm3(qasm2_str):
    """test random gates conversion"""
    qasm3_str = pyqasm.loads(qasm2_str).to_qasm3(as_str=True)
    circuit_orig = QuantumCircuit.from_qasm_str(qasm2_str)
    circuit_test = qasm3_loads(qasm3_str)

    # ensure that the conversion is correct
    assert circuits_allclose(circuit_orig, circuit_test)


def test_invalid_conversion():
    """Test invalid conversion inputs"""
    with pytest.raises(ValueError):
        qasm2_to_qasm3(1)
