import { Player } from "./player.js"
import { Recorder } from "./recorder.js"
import {
  listDevices,
  calculateRMS,
  findDeviceByLabel,
  type AudioFormat,
  type Device,
} from "./utils.js"

const defaultPlayer = (format?: AudioFormat) => Player.create({ format })

const player = (label: string, format?: AudioFormat) => Player.create({ label, format })

const defaultRecorder = (format?: AudioFormat) => Recorder.create({ format })

const recorder = (label: string, format?: AudioFormat) => Recorder.create({ label, format })

const getVolumeControl = async (cardNumber?: number): Promise<string> => {
  const output = cardNumber
    ? await Bun.$`amixer -c ${cardNumber} scontrols`.text()
    : await Bun.$`amixer scontrols`.text()

  const controls = output
    .split("\n")
    .map((line) => {
      const match = line.match(/Simple mixer control '([^']+)'/)
      return match?.[1]
    })
    .filter(Boolean)

  const playbackControl = controls.find((c) => c !== "Capture")
  if (!playbackControl) {
    throw new Error("No playback mixer control found")
  }

  return playbackControl
}

const setVolume = async (volume: number, label?: string): Promise<void> => {
  const percent = Math.round(volume * 100)

  let cardNumber: number | undefined
  if (label) {
    const device = await findDeviceByLabel(label)
    cardNumber = device.card
  }

  const control = await getVolumeControl(cardNumber)

  const result = cardNumber
    ? await Bun.$`amixer -c ${cardNumber} sset ${control} ${percent}%`.quiet()
    : await Bun.$`amixer sset ${control} ${percent}%`.quiet()

  if (result.exitCode !== 0) {
    throw new Error(`Failed to set volume: ${result.stderr}`)
  }
}

const getVolume = async (label?: string): Promise<number> => {
  let cardNumber: number | undefined
  if (label) {
    const device = await findDeviceByLabel(label)
    cardNumber = device.card
  }

  const control = await getVolumeControl(cardNumber)

  const output = cardNumber
    ? await Bun.$`amixer -c ${cardNumber} sget ${control}`.text()
    : await Bun.$`amixer sget ${control}`.text()

  const match = output.match(/\[(\d+)%\]/)
  if (!match?.[1]) {
    throw new Error("Failed to parse volume from amixer output")
  }

  return parseInt(match[1]) / 100
}

const Buzz = {
  listDevices,
  defaultPlayer,
  player,
  defaultRecorder,
  recorder,
  setVolume,
  getVolume,
  calculateRMS,
}

export default Buzz
export type { Device, AudioFormat }
export { type Player } from "./player.js"
export { type Recorder } from "./recorder.js"
