#!/usr/bin/env python
"""Application under test.

One app with several named endpoints, so most functional checks share a single
server start instead of paying launch cost per test. Endpoint names are pinned
with api_name= so they are stable across gradio majors (gradio 4 and 5+ derive
default names differently).

    python kitchen_sink.py --port 7860
"""
import argparse
import hashlib
import os
import pathlib
import sys
import time

import gradio as gr

GRADIO_MAJOR = int(gr.__version__.split(".")[0])


# --- endpoint implementations ------------------------------------------------
def echo(text):
    return f"echo:{text}"


def add(a, b):
    return float(a) + float(b)


def stream(n):
    """Generator endpoint; yields n incremental chunks."""
    acc = ""
    for i in range(int(n)):
        acc += f"{i}"
        yield acc


def checksum(path):
    if not path:
        return {}
    data = pathlib.Path(path).read_bytes()
    return {"bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()}


def make_plot(points):
    import matplotlib
    matplotlib.use("Agg")
    import matplotlib.pyplot as plt
    fig, ax = plt.subplots(figsize=(4, 2.5))
    ax.plot(range(int(points)), [i * i for i in range(int(points))])
    ax.set_title("t")
    return fig


def bump(state):
    """Per-session counter; proves gr.State is not shared between sessions."""
    state = (state or 0) + 1
    return state, state


def slow(seconds):
    time.sleep(float(seconds))
    return "done"


# --- layout ------------------------------------------------------------------
with gr.Blocks(title="testkit") as demo:
    gr.Markdown("# testkit")

    # Component coverage: these must all construct and serialise into /config
    # on both gradio majors. Kept to the set common to 4.x and 6.x.
    with gr.Tab("components"):
        gr.Textbox(label="textbox")
        gr.Number(label="number")
        gr.Slider(0, 10, label="slider")
        gr.Checkbox(label="checkbox")
        gr.Radio(["a", "b"], label="radio")
        gr.Dropdown(["a", "b"], label="dropdown")
        gr.DataFrame(label="dataframe")
        gr.JSON(label="json")
        gr.Image(label="image", type="filepath")
        gr.Gallery(label="gallery")
        gr.File(label="file")
        gr.Audio(label="audio")       # constructs without ffmpeg; ffmpeg is
        gr.Video(label="video")       # only needed to process real media
        gr.Label(label="label")
        gr.HTML("<b>html</b>")
        gr.Code(label="code")
        gr.ColorPicker(label="color")
        gr.Markdown("markdown")
        gr.Plot(label="plot")
        gr.Chatbot(label="chatbot")

    with gr.Tab("endpoints"):
        t_in = gr.Textbox(label="text")
        t_out = gr.Textbox(label="out")
        gr.Button("echo").click(echo, t_in, t_out, api_name="echo")

        n1 = gr.Number(value=1, label="a")
        n2 = gr.Number(value=2, label="b")
        n_out = gr.Number(label="sum")
        gr.Button("add").click(add, [n1, n2], n_out, api_name="add")

        s_n = gr.Number(value=5, label="chunks")
        s_out = gr.Textbox(label="streamed")
        gr.Button("stream").click(stream, s_n, s_out, api_name="stream")

        f_in = gr.File(label="upload", type="filepath")
        f_out = gr.JSON(label="checksum")
        gr.Button("checksum").click(checksum, f_in, f_out, api_name="checksum")

        p_n = gr.Number(value=10, label="points")
        p_out = gr.Plot(label="figure")
        gr.Button("plot").click(make_plot, p_n, p_out, api_name="plot")

        st = gr.State(0)
        st_out = gr.Number(label="count")
        gr.Button("bump").click(bump, st, [st, st_out], api_name="bump")

        d_in = gr.Number(value=0.2, label="seconds")
        d_out = gr.Textbox(label="slow")
        gr.Button("slow").click(slow, d_in, d_out, api_name="slow")


if __name__ == "__main__":
    ap = argparse.ArgumentParser()
    ap.add_argument("--port", type=int, default=7860)
    ap.add_argument("--host", default="127.0.0.1")
    args = ap.parse_args()

    # Queue settings differ between majors; default_concurrency_limit arrived
    # in gradio 4.32 and is still accepted in 6.x.
    demo.queue(default_concurrency_limit=8)
    print(f"READY_PORT={args.port}", flush=True)
    demo.launch(server_name=args.host, server_port=args.port, share=False,
                quiet=True)
