import { LotusQualityPayload } from '../plugins/call/CallControl';
import { CallAudioBitrate, ScreenshareBitrate, ScreenshareFramerate } from '../state/settings';

/**
 * [P5-31] Room-level quality caps, stored in the `io.lotus.room_quality` state
 * event. Admins set a ceiling every client must stay under. Values mirror the
 * user-setting units (kbps / fps); `undefined`/absent = no cap.
 *
 * NOTE: the client applies these as a best-effort UX cap. Hard enforcement for
 * ALL Matrix clients is a server-side follow-up (a `voice-limit-guard`-style
 * sidecar on LXC 151 that reads this event) — see LOTUS_TODO.md P5-31.
 */
export type RoomQualityContent = {
  // Numeric caps: client-cooperative only (our fork honors them; the SFU cannot
  // enforce publisher bitrate/fps — LiveKit forwards, never transcodes).
  audio_max_kbps?: number;
  screenshare_max_kbps?: number;
  screenshare_max_fps?: number;
  // Publish-source policy: HARD-enforced server-side for ALL clients by the
  // voice-limit-guard (it re-signs the LiveKit JWT's canPublishSources).
  // Absent/true = allowed; only an explicit false forbids.
  allow_screenshare?: boolean;
  allow_camera?: boolean;
};

// Selectable options (kbps / fps), shared by the settings UI and the room-admin
// UI so they stay in sync. Values are strings so they satisfy SettingsSelect's
// `T extends string` constraint; parsed to numbers in buildQualityPayload.
export const AUDIO_BITRATE_OPTIONS: { value: CallAudioBitrate; label: string }[] = [
  { value: 'auto', label: 'Auto' },
  { value: '32', label: '32 kbps' },
  { value: '64', label: '64 kbps' },
  { value: '96', label: '96 kbps' },
  { value: '128', label: '128 kbps' },
  { value: '256', label: '256 kbps' },
];

export const SCREENSHARE_BITRATE_OPTIONS: { value: ScreenshareBitrate; label: string }[] = [
  { value: 'auto', label: 'Auto' },
  { value: '500', label: '0.5 Mbps' },
  { value: '1500', label: '1.5 Mbps' },
  { value: '3000', label: '3 Mbps' },
  { value: '8000', label: '8 Mbps' },
];

export const SCREENSHARE_FRAMERATE_OPTIONS: { value: ScreenshareFramerate; label: string }[] = [
  { value: 'auto', label: 'Auto' },
  { value: '15', label: '15 fps' },
  { value: '30', label: '30 fps' },
  { value: '60', label: '60 fps' },
];

/** Lower of two caps, treating `undefined` as "no cap on that side". */
const minCap = (a: number | undefined, b: number | undefined): number | undefined => {
  if (a === undefined) return b;
  if (b === undefined) return a;
  return Math.min(a, b);
};

/** Parse a setting value ('auto' | numeric string) to a number or undefined. */
const num = (v: string): number | undefined => {
  if (v === 'auto') return undefined;
  const n = parseInt(v, 10);
  return Number.isFinite(n) ? n : undefined;
};

type QualitySettings = {
  callAudioBitrate: CallAudioBitrate;
  screenshareBitrate: ScreenshareBitrate;
  screenshareFramerate: ScreenshareFramerate;
};

/**
 * Build the `io.lotus.set_quality` payload from the user's settings, clamped by
 * any room-level cap. Every field is always present so clearing a setting back
 * to 'auto' sends an explicit `null` that resets the fork-side cap (otherwise a
 * previously-applied cap would stick for the rest of the call).
 */
export const buildQualityPayload = (
  settings: QualitySettings,
  roomCaps?: RoomQualityContent,
): LotusQualityPayload => {
  const userAudio = num(settings.callAudioBitrate);
  const userSsBitrate = num(settings.screenshareBitrate);
  const userSsFps = num(settings.screenshareFramerate);

  const audioKbps = minCap(userAudio, roomCaps?.audio_max_kbps);
  const ssKbps = minCap(userSsBitrate, roomCaps?.screenshare_max_kbps);
  const ssFps = minCap(userSsFps, roomCaps?.screenshare_max_fps);

  return {
    audioMaxBitrate: audioKbps === undefined ? null : audioKbps * 1000,
    screenshareMaxBitrate: ssKbps === undefined ? null : ssKbps * 1000,
    screenshareMaxFramerate: ssFps === undefined ? null : ssFps,
  };
};
