#!/usr/bin/env python3
"""Generate hardcoded testbench vectors for problem 046.

This helper is kept in the problem folder for auditability, but the
generated values are intended to be pasted directly into testbench.v.
"""

from dataclasses import dataclass


@dataclass(frozen=True)
class Step:
    tag: str
    rst: int
    capacity: int
    period: int
    req: int


def model_step(tokens: int, countdown: int, step: Step):
    if step.rst:
        return step.capacity, step.period, 0, 0

    refill_event = countdown == 1
    visible_tokens = tokens
    if refill_event and visible_tokens < step.capacity:
        visible_tokens += 1

    accept = 1 if (step.req and visible_tokens > 0) else 0
    reject = 1 if (step.req and visible_tokens == 0) else 0

    next_tokens = visible_tokens - 1 if accept else visible_tokens
    next_countdown = step.period if refill_event else countdown - 1
    return next_tokens, next_countdown, accept, reject


def build_steps():
    steps: list[Step] = []

    steps.extend(
        [
            Step("rst_boot_0", 1, 4, 3, 0),
            Step("rst_boot_1", 1, 4, 3, 1),
            Step("post_rst_idle", 0, 4, 3, 0),
            Step("drain_0", 0, 4, 3, 1),
            Step("drain_1", 0, 4, 3, 1),
            Step("drain_2", 0, 4, 3, 1),
            Step("refill_then_take", 0, 4, 3, 1),
            Step("drain_last", 0, 4, 3, 1),
            Step("same_empty_refill_accept", 0, 4, 3, 1),
            Step("empty_reject_after_refill", 0, 4, 3, 1),
            Step("idle_refill", 0, 4, 3, 0),
            Step("consume_after_idle", 0, 4, 3, 1),
            Step("idle_to_full_0", 0, 4, 3, 0),
            Step("idle_to_full_1", 0, 4, 3, 0),
            Step("idle_to_full_2", 0, 4, 3, 0),
            Step("idle_to_full_3", 0, 4, 3, 0),
            Step("idle_to_full_4", 0, 4, 3, 0),
            Step("cap_refill_and_req", 0, 4, 3, 1),
            Step("rst_midstream", 1, 4, 3, 1),
            Step("post_midrst_req", 0, 4, 3, 1),
        ]
    )

    steps.extend(
        [
            Step("minp_rst", 1, 1, 1, 0),
            Step("minp_req_0", 0, 1, 1, 1),
            Step("minp_req_1", 0, 1, 1, 1),
            Step("minp_idle", 0, 1, 1, 0),
            Step("minp_req_2", 0, 1, 1, 1),
            Step("minp_req_3", 0, 1, 1, 1),
        ]
    )

    steps.extend(
        [
            Step("same_partial_rst", 1, 3, 4, 0),
            Step("same_partial_take0", 0, 3, 4, 1),
            Step("same_partial_take1", 0, 3, 4, 1),
            Step("same_partial_idle0", 0, 3, 4, 0),
            Step("same_partial_refillreq", 0, 3, 4, 1),
            Step("same_partial_follow", 0, 3, 4, 1),
        ]
    )

    steps.extend(
        [
            Step("maxp_rst", 1, 16, 256, 0),
            Step("maxp_req_0", 0, 16, 256, 1),
            Step("maxp_req_1", 0, 16, 256, 1),
            Step("maxp_req_2", 0, 16, 256, 1),
            Step("maxp_req_3", 0, 16, 256, 1),
            Step("maxp_req_4", 0, 16, 256, 1),
            Step("maxp_req_5", 0, 16, 256, 1),
            Step("maxp_req_6", 0, 16, 256, 1),
            Step("maxp_req_7", 0, 16, 256, 1),
            Step("maxp_req_8", 0, 16, 256, 1),
            Step("maxp_req_9", 0, 16, 256, 1),
            Step("maxp_req_10", 0, 16, 256, 1),
            Step("maxp_req_11", 0, 16, 256, 1),
            Step("maxp_req_12", 0, 16, 256, 1),
            Step("maxp_req_13", 0, 16, 256, 1),
            Step("maxp_req_14", 0, 16, 256, 1),
            Step("maxp_req_15", 0, 16, 256, 1),
            Step("maxp_req_16_reject", 0, 16, 256, 1),
        ]
    )

    for idx in range(238):
        steps.append(Step(f"maxp_idle_{idx:03d}", 0, 16, 256, 0))

    steps.extend(
        [
            Step("maxp_refill_accept", 0, 16, 256, 1),
            Step("maxp_post_refill_reject", 0, 16, 256, 1),
            Step("maxp_idle_final", 0, 16, 256, 0),
        ]
    )

    return steps


def main():
    steps = build_steps()

    tokens = 0
    countdown = 1
    out_lines = []
    for step in steps:
        tokens, countdown, accept, reject = model_step(tokens, countdown, step)
        out_lines.append(
            f'        step_cycle("{step.tag}", 1\'b{step.rst}, 5\'d{step.capacity}, '
            f"9'd{step.period}, 1'b{step.req}, 1'b{accept}, 1'b{reject});"
        )

    print("\n".join(out_lines))


if __name__ == "__main__":
    main()
