import OBSWebSocket from 'obs-websocket-js';

export type OBSControlOptions = {
  url?: string;
  password?: string;
  sceneName?: string;
  textInputName?: string;
};

export class OBSControlClient {
  private readonly obs = new OBSWebSocket();
  private readonly url: string;
  private readonly password?: string;
  private readonly sceneName?: string;
  private readonly textInputName?: string;
  private connected = false;

  constructor(options: OBSControlOptions = {}) {
    this.url = options.url ?? process.env.OBS_WS_URL ?? 'ws://127.0.0.1:4455';
    this.password = options.password ?? process.env.OBS_WS_PASSWORD;
    this.sceneName = options.sceneName ?? process.env.OBS_SCENE_NAME;
    this.textInputName = options.textInputName ?? process.env.OBS_TEXT_INPUT_NAME;
  }

  async connect() {
    if (this.connected) return;
    await this.obs.connect(this.url, this.password, { rpcVersion: 1 });
    this.connected = true;
  }

  async setProgramScene(sceneName = this.sceneName) {
    if (!sceneName) return;
    await this.connect();
    await this.obs.call('SetCurrentProgramScene', { sceneName });
  }

  async ensureTextInput(inputName = this.textInputName, sceneName = this.sceneName) {
    if (!inputName || !sceneName) return;
    await this.connect();

    try {
      await this.obs.call('GetInputSettings', { inputName });
      return;
    } catch {
      await this.obs.call('CreateInput', {
        sceneName,
        inputName,
        inputKind: 'text_ft2_source',
        inputSettings: {
          text: '',
        },
        sceneItemEnabled: true,
      });
    }
  }

  async setText(text: string, inputName = this.textInputName) {
    if (!inputName) return;
    await this.connect();
    await this.ensureTextInput(inputName, this.sceneName);
    await this.obs.call('SetInputSettings', {
      inputName,
      inputSettings: {
        text,
      },
      overlay: true,
    });
  }

  async disconnect() {
    if (!this.connected) return;
    await this.obs.disconnect();
    this.connected = false;
  }
}
