import { execFile } from "node:child_process";
import { promisify } from "node:util";
import { z } from "zod";

const execFileAsync = promisify(execFile);
const helperPath = "/usr/local/sbin/pi-car-companion-bluetooth-control";

export const bluetoothActionSchema = z.enum(["on", "off", "discoverable"]);
export type BluetoothAction = z.infer<typeof bluetoothActionSchema>;

export const bluetoothStatusSchema = z.object({
  supported: z.boolean(),
  powered: z.boolean(),
  discoverable: z.boolean(),
  pairable: z.boolean(),
  message: z.string()
});
export type BluetoothStatus = z.infer<typeof bluetoothStatusSchema>;

function unavailableStatus(): BluetoothStatus {
  return {
    supported: false,
    powered: false,
    discoverable: false,
    pairable: false,
    message: "Bluetooth controls are available after installing the Pi system service."
  };
}

export function parseBluetoothStatus(output: string): BluetoothStatus {
  return bluetoothStatusSchema.parse(JSON.parse(output));
}

export function parseBluetoothctlStatus(output: string): BluetoothStatus {
  if (!/^Controller /m.test(output)) {
    return { ...unavailableStatus(), message: "No Bluetooth adapter was found." };
  }
  const property = (name: string) => new RegExp(`^\\s*${name}: yes$`, "m").test(output);
  const powered = property("Powered");
  const discoverable = property("Discoverable");
  return {
    supported: true,
    powered,
    discoverable,
    pairable: property("Pairable"),
    message: discoverable
      ? "The Pi is visible to nearby phones for three minutes."
      : powered
        ? "Bluetooth is on and the companion bridge is available."
        : "Bluetooth is off."
  };
}

async function runHelper(action: BluetoothAction): Promise<BluetoothStatus> {
  const { stdout } = await execFileAsync("/usr/bin/sudo", ["-n", helperPath, action], {
    timeout: 12_000,
    maxBuffer: 16 * 1024
  });
  return parseBluetoothStatus(stdout);
}

export async function readBluetoothStatus(): Promise<BluetoothStatus> {
  try {
    const { stdout } = await execFileAsync("/usr/bin/bluetoothctl", ["show"], {
      timeout: 5_000,
      maxBuffer: 16 * 1024
    });
    return parseBluetoothctlStatus(stdout);
  } catch {
    return unavailableStatus();
  }
}

export async function triggerBluetoothAction(action: BluetoothAction): Promise<BluetoothStatus> {
  return runHelper(action);
}
