from pathlib import Path
from typing import cast

import grpc
import matplotlib.pyplot as plt
import numpy as np
import typer

from ..generated import figure_pb2, figure_pb2_grpc

app = typer.Typer()


@app.command()
def list() -> None:
    """
    List all figures from the gRPC service.
    """
    print("Connecting to the server...")
    with grpc.insecure_channel("localhost:50051") as channel:
        stub = figure_pb2_grpc.FigureServiceStub(channel)
        print("Retrieving available figures...\n")
        figures = [x for x in stub.GetFigure(figure_pb2.FigureRequest())]

        if not figures:
            print("No figures found.")
        else:
            for i, figure in enumerate(figures, 1):
                print(f"{i}. Figure: {figure.title} (ID: {figure.uuid})")

            choice = typer.prompt("Which figure to extract?", type=int)
            assert isinstance(choice, int)
            if 1 <= choice <= len(figures):
                selected_figure = figures[choice - 1]
                print(f"You selected: {selected_figure.title}")
                extract(selected_figure.uuid)
            else:
                print("Invalid selection. Exiting.")


def get_figure(uuid: str) -> tuple[figure_pb2.Figure, figure_pb2.FigureData]:
    """
    Get the figure data for a specific UUID.
    """
    print(f"Connecting to the server to extract data for UUID: {uuid}...")
    with grpc.insecure_channel("localhost:50051") as channel:
        stub = figure_pb2_grpc.FigureServiceStub(channel)
        all_figures = {x.uuid: x for x in stub.GetFigure(figure_pb2.FigureRequest())}
        figure_data = stub.GetFigureUpdate(figure_pb2.FigureDataRequest(uuid=uuid))
        for data in figure_data:
            return (all_figures[uuid], data)
    raise ValueError(f"Figure with UUID {uuid} not found.")


@app.command()
def extract(uuid: str, output: Path | None = None) -> None:
    """
    Extract data for a specific figure identified by its UUID.
    """
    _, figure = get_figure(uuid)
    if not output:
        output = cast(Path, typer.prompt("Enter output file path:", type=Path))
    with open(output, "wb") as f:
        f.write(figure.SerializeToString())


@app.command()
def plot(uuid: str) -> None:
    """
    Plot the figure data for a specific UUID.
    """
    figure, data = get_figure(uuid)
    if data.line:
        for line in data.line.lines:
            plt.plot(
                line.x if line.x else np.arange(len(line.y)), line.y, label=line.label
            )
        plt.xlabel(figure.x_label)
        plt.ylabel(figure.y_label)
        plt.title(figure.title)
    elif figure.heatmap:
        plt.imshow(figure.heatmap.data, cmap="hot", interpolation="nearest")
    elif figure.histogram:
        plt.hist(figure.histogram.data, bins=figure.histogram.bins)
    plt.show()


if __name__ == "__main__":
    app()
