from enum import auto, StrEnum
from json import loads
from subprocess import run
from typing import TypedDict, cast

from rofi_menu import FLAG_STYLE_URGENT, Menu, ShellItem


class NodeType(StrEnum):
	SINK = auto()
	SOURCE = auto()


def _pactl(*args: str) -> str:
	return run(["pactl", "--format=json", *args], capture_output=True).stdout.decode()


class Volume(TypedDict):
	value: int
	value_percent: str
	db: str
class Latency(TypedDict):
	actual: float
	configured: float
class Port(TypedDict):
	name: str
	description: str
	type: str
	priority: int
	availability_group: str
	availability: str
class Node(TypedDict):
	index: int
	state: str
	name: str
	description: str
	driver: str
	sample_specification: str
	channel_map: str
	owner_module: int
	mute: bool
	volume: dict[str, Volume]
	balance: float
	base_volume: Volume
	monitor_source: str
	latency: Latency
	flags: list[str]
	properties: dict[str, str]
	ports: list[Port]
	active_port: str
	formats: list[str]


def list_nodes(node_type: NodeType) -> list[Node]:
	return cast(list[Node], loads(_pactl("list", f"{node_type}s")))


def get_default(node_type: NodeType) -> str:
	return _pactl(f"get-default-{node_type}").strip()


def create_item(node_type: NodeType, node: Node, default: str) -> ShellItem:
	return ShellItem(
		node["description"],
		f"pactl set-default-{node_type} {node["name"]}",
		flags=FLAG_STYLE_URGENT if node["name"] == default else None,
		show_output=True
	)


def create_menu(node_type: NodeType) -> Menu:
	default = get_default(node_type)
	return Menu(
		prompt=f"Select {node_type}",
		items=[create_item(node_type, node, default) for node in list_nodes(node_type)]
	)

