from __future__ import annotations
from typing import List
from ..ir.types import Instruction

# Conventions
# - Qubits are rendered top (q0) → bottom (q{n-1}) for readability.
# - Columns advance in time, one column per instruction (simple MVP).
# - Supported ops: x, sx, rz(theta), cx, measure.
# - For measure, we annotate the destination classical bit as M[c].
# - Little-endian execution still applies (this is only visualization).

CELL_W = 5  # width per column (room for labels like "rz(π/2)" short form later)


def _empty_canvas(n_qubits: int, n_cols: int) -> List[List[str]]:
    rows = []
    for _ in range(n_qubits):
        row = ["─" * CELL_W for _ in range(n_cols)]
        rows.append(row)
    return rows


def _place_label(cell: str, label: str) -> str:
    # Center label within CELL_W using monospaced assumptions
    pad = max(0, CELL_W - len(label))
    left = pad // 2
    right = pad - left
    return " " * left + label + " " * right


def _rz_label(theta: float) -> str:
    # Keep it compact; 3 significant digits
    return f"rz({theta:.3g})"


def draw_ascii(n_qubits: int, instructions: List[Instruction]) -> str:
    n_cols = max(1, len(instructions))
    canvas = _empty_canvas(n_qubits, n_cols)

    # Helper to map logical qubit index to row (q0 at top)
    def row_of(q: int) -> int:
        return q  # q0 at row 0, q1 at row 1, ...

    for col, inst in enumerate(instructions):
        name, qs, ps, cs = inst.name, inst.qubits, inst.params, inst.clbits

        if name in ("x", "sx", "rz", "measure"):
            q = qs[0]
            r = row_of(q)
            if name == "x":
                canvas[r][col] = _place_label(canvas[r][col], "X")
            elif name == "sx":
                canvas[r][col] = _place_label(canvas[r][col], "SX")
            elif name == "rz":
                canvas[r][col] = _place_label(canvas[r][col], _rz_label(float(ps[0])))
            elif name == "measure":
                lbl = "M" if cs is None or len(cs) == 0 else f"M[{cs[0]}]"
                canvas[r][col] = _place_label(canvas[r][col], lbl)
            # leave other rows in this column as wires
            continue

        if name == "cx":
            c, t = qs
            rc = row_of(c)
            rt = row_of(t)
            top, bot = sorted((rc, rt))
            # Place control and target symbols
            canvas[rc][col] = _place_label(canvas[rc][col], "●")  # control
            canvas[rt][col] = _place_label(
                canvas[rt][col], "X"
            )  # target (CNOT symbolized as X)
            # Draw vertical wire between them in this column
            for r in range(top + 1, bot):
                canvas[r][col] = _place_label(canvas[r][col], "│")
            continue

        # Unknown op: show as name
        for q in qs:
            r = row_of(q)
            canvas[r][col] = _place_label(canvas[r][col], name.upper())

    # Build header with qubit labels
    lines: List[str] = []
    for q in range(n_qubits):
        label = f"q{q}: "
        line = label + "".join(canvas[q])
        lines.append(line)

    return "\n".join(lines)
