
import numpy as np

def build_oracle(target_state: int, n_qubits: int) -> np.ndarray:
    """Phase oracle: flips the phase of the target basis state."""
    dim = 2 ** n_qubits
    oracle = np.eye(dim, dtype=complex)
    oracle[target_state, target_state] = -1.0
    return oracle

def _diffusion_operator(n_qubits: int) -> np.ndarray:
    dim = 2 ** n_qubits
    return (2.0 / dim) * np.ones((dim, dim), dtype=complex) - np.eye(dim, dtype=complex)

def amplitude_amplification(state, oracle, diffusion, iterations):
    for _ in range(iterations):
        state = oracle @ state
        state = diffusion @ state
    return state

def grover_search(n_qubits: int, target: int) -> dict:
    """Full Grover search. Returns probabilities, measured state, and success flag."""
    dim        = 2 ** n_qubits
    iterations = max(1, int(round(np.pi / 4 * np.sqrt(dim))))
    state      = np.ones(dim, dtype=complex) / np.sqrt(dim)
    oracle     = build_oracle(target, n_qubits)
    diffusion  = _diffusion_operator(n_qubits)
    state      = amplitude_amplification(state, oracle, diffusion, iterations)
    probs      = np.abs(state) ** 2
    measured   = int(np.argmax(probs))
    return {
        "probabilities":  probs,
        "measured_state": measured,
        "target":         target,
        "iterations":     iterations,
        "success":        measured == target,
        "n_qubits":       n_qubits,
    }
