#include "webrtcpush_run.h"

#include "webrtcpush_config.h"
#include "webrtcpush_log.h"
#include "runtime_deps.h"
#include "app_state.h"
#include "device_identity.h"
#include "rtc_client.h"
#include "ws_signaling.h"

#include <gst/gst.h>
#include <stdio.h>
#include <string.h>

static AppState s_app;
static gboolean s_running = FALSE;

gboolean webrtcpush_should_use_mpp(void)
{
  return runtime_deps_use_webrtc_push();
}

gboolean webrtcpush_is_running(void)
{
  return s_running;
}

void webrtcpush_request_stop(void)
{
  if (s_app.loop)
    g_main_loop_quit(s_app.loop);
}

void webrtcpush_request_refresh(void)
{
  if (!s_running || !s_app.loop) {
    my_zlog_warn("webrtcpush refresh skipped: push loop not running");
    return;
  }
  my_zlog_info("webrtcpush refresh: reset pipeline + signaling (hard)");
  ws_signaling_request_refresh(&s_app);
}

void webrtcpush_request_soft_refresh(void)
{
  if (!s_running || !s_app.loop) {
    my_zlog_warn("webrtcpush soft refresh skipped: push loop not running");
    return;
  }
  my_zlog_info("webrtcpush soft refresh: reset pipeline only, keep WS");
  ws_signaling_request_soft_refresh(&s_app);
}

void webrtcpush_notify_driver_switch(void)
{
  /* File-input validation stage has no camera driver to switch yet. */
}

/* 从 /proc/asound/pcm 选 capture；优先 USB 麦（板载 rk809 多为喇叭回路） */
static char *pick_alsa_capture_hw(void)
{
  FILE *f;
  char line[256];
  int usb_card = -1;
  int first_card = -1;
  int first_dev = -1;

  f = fopen("/proc/asound/cards", "r");
  if (f) {
    while (fgets(line, sizeof(line), f)) {
      int c = -1;
      if (sscanf(line, " %d [", &c) != 1)
        continue;
      if (strstr(line, "USB") || strstr(line, "usb"))
        usb_card = c;
    }
    fclose(f);
  }

  f = fopen("/proc/asound/pcm", "r");
  if (!f)
    return NULL;
  while (fgets(line, sizeof(line), f)) {
    int c = -1;
    int d = -1;
    if (sscanf(line, "%d-%d:", &c, &d) != 2)
      continue;
    if (!strstr(line, "capture"))
      continue;
    if (first_card < 0) {
      first_card = c;
      first_dev = d;
    }
    if (usb_card >= 0 && c == usb_card) {
      fclose(f);
      return g_strdup_printf("hw:%d,%d", c, d);
    }
  }
  fclose(f);
  if (first_card < 0 || first_dev < 0)
    return NULL;
  return g_strdup_printf("hw:%d,%d", first_card, first_dev);
}

static void setup_alsa_device(AppState *app)
{
  const char *dev = WEBRTCPUSH_ALSA_DEVICE;
  char *auto_hw = NULL;

  g_free(app->audio_alsa_device);
  app->audio_alsa_device = NULL;
  app->enable_audio = FALSE;

  if (!dev || !dev[0])
    return;

  if (!strcmp(dev, "test")) {
    app->audio_alsa_device = g_strdup("test");
    app->enable_audio = TRUE;
    return;
  }

  if (!strcmp(dev, "auto")) {
    auto_hw = pick_alsa_capture_hw();
    if (!auto_hw) {
      my_zlog_warn("webrtcpush: no ALSA capture in /proc/asound/pcm, audio off");
      return;
    }
    dev = auto_hw;
    my_zlog_info("webrtcpush: auto mic %s", dev);
  }

  if (!strncmp(dev, "hw:", 3)) {
    app->audio_alsa_device = g_strdup_printf("plughw:%s", dev + 3);
    my_zlog_info("webrtcpush ALSA: %s -> %s", dev, app->audio_alsa_device);
  } else {
    app->audio_alsa_device = g_strdup(dev);
  }
  app->enable_audio = TRUE;
  g_free(auto_hw);
}

static void app_state_clear(AppState *app)
{
  if (!app)
    return;
  g_free(app->dev_room);
  g_free(app->video_device);
  g_free(app->audio_alsa_device);
  g_free(app->member_id);
  memset(app, 0, sizeof(*app));
}

void webrtcpush_notify_fatal_failure(const char *reason)
{
  if (reason && reason[0])
    my_zlog_error("webrtcpush fatal: %s", reason);
  runtime_deps_disable_webrtc_push();
  webrtcpush_request_stop();
}

int webrtcpush_run_blocking(void)
{
  if (!webrtcpush_should_use_mpp())
    return -1;

  app_state_clear(&s_app);
  g_mutex_init(&s_app.lock);

  s_app.dev_room = g_strdup(mqtt_topic_pure_number());
  s_app.video_device = g_strdup(WEBRTCPUSH_VIDEO_DEVICE);
  s_app.prefer_mpp = TRUE;
  s_app.device_offerer = FALSE;
  s_app.verbose = WEBRTCPUSH_DEBUG ? TRUE : FALSE;
  setup_alsa_device(&s_app); /* enable_audio 由 ALSA 设备探测结果决定 */

  s_app.loop = g_main_loop_new(NULL, FALSE);

  if (rtc_client_start(&s_app) != 0) {
    my_zlog_error("webrtcpush: libdatachannel sender start failed");
    g_main_loop_unref(s_app.loop);
    s_app.loop = NULL;
    g_mutex_clear(&s_app.lock);
    app_state_clear(&s_app);
    webrtcpush_notify_fatal_failure("libdatachannel sender start failed");
    return -1;
  }

  if (ws_signaling_start(&s_app) != 0) {
    my_zlog_error("webrtcpush: signaling start failed");
    rtc_client_stop(&s_app);
    g_main_loop_unref(s_app.loop);
    s_app.loop = NULL;
    g_mutex_clear(&s_app.lock);
    app_state_clear(&s_app);
    webrtcpush_notify_fatal_failure("signaling start failed");
    return -1;
  }

  s_running = TRUE;
  my_zlog_info("webrtcpush libdatachannel started dev=%s device=%s fps=%d bitrate=%u..%u",
      s_app.dev_room ? s_app.dev_room : "?",
      s_app.video_device ? s_app.video_device : WEBRTCPUSH_VIDEO_DEVICE,
      WEBRTCPUSH_H264_FPS,
      WEBRTCPUSH_INITIAL_BITRATE, WEBRTCPUSH_MAX_BITRATE);

  g_main_loop_run(s_app.loop);

  s_running = FALSE;
  ws_signaling_stop(&s_app);
  rtc_client_stop(&s_app);

  if (s_app.loop) {
    g_main_loop_unref(s_app.loop);
    s_app.loop = NULL;
  }

  g_mutex_clear(&s_app.lock);
  app_state_clear(&s_app);
  my_zlog_info("webrtcpush exited");
  return 0;
}
