/**************************************************************************
 * Copyright (C) 2012-2021  Unisound
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 **************************************************************************
 *
 * Description : uni_app_ivm.c
 * Author      : yzs.unisound.com
 * Date        : 2021.03.01
 *
 **************************************************************************/
#include <autoconf.h>
#include <lvp_app.h>
#include <lvp_buffer.h>
#include <lvp_board.h>

#ifndef USE_MP3
#include "lvp_voice_player.h"
#else
#include "lvp_mp3_player.h"
#include "decoder/mp3_decoder.h"
#endif
#include "uni_vui_interface.h"
#include "fakelibc.h"
#include <base_addr.h>
#include <driver/uni_gpio.h>
#include <driver/uni_watchdog.h>
#include <driver/pwm_buzzer.h>
#include <driver/uni_pmu_ctrl.h>

#ifdef CONFIG_UNI_UART_RECORD
#include "uni_uart_record.h"
#endif
#include "uni_auto_control.h"

#ifdef CONFIG_HW_EXT_FLASH
#include <driver/uni_flash.h>
#include <driver/uni_clock.h>
#endif

#include "uni_cust_config.h"
#include "user_player.h"
#include "user_flash.h"

#define LOG_TAG "[IVM_APP]"

#define LIST_COUNT_MAX            10
#define RECOG_TIMEOUT_MS          (UNI_ASR_TIMEOUT * 1000)
#define SLEEP_TIMEOUT_MS          (60 * 1000)
#define VAD_WAKEUP_TIMEOUT_MS     (10 * 1000)

static VuiRecognModel g_cur_model = UNI_LP_WAKEUP;

static int _UniKwsRecognRelanch(VuiRecognModel model) {
  switch (model) {
    case UNI_LP_WAKEUP:
      ArptPrint("enter wakeup_normal\n");
      break;
    case UNI_LP_LASR:
      ArptPrint("enter asr_normal\n");
      break;
  }
  VuiRecognStop();
  g_cur_model = model;
  return VuiRecognStart(model, RECOG_TIMEOUT_MS);
}

//=================================================================================================
#if UNI_REPLY_TYPE == UNI_REPLY_TYPE_SPEAKER
static void PlayerEventCallback(int player_event_id, void *data) {
  if (player_event_id == EVENT_PLAYER_FINISH) {
    APP_EVENT event = {
      .event_id = UNI_REPLAY_END_EVENT_ID,
      .ctx_index = 0,
      .attach = NULL
    };
    #ifdef USE_MP3
    lvp_mp3_decoder_deinit();
    #endif
    LvpTriggerAppEvent(&event);
  }
}
#endif

#if UNI_REPLY_TYPE == UNI_REPLY_TYPE_BUZZER
static void BuzzerEventCallback(int buzzer_event_id, void *data) {
  if (buzzer_event_id == EVENT_BUZZER_FINISH) {
    APP_EVENT event = {
      .event_id = UNI_REPLAY_END_EVENT_ID,
      .ctx_index = 0,
      .attach = NULL
    };
    LvpTriggerAppEvent(&event);
  }
}
#endif

static int IvmAppSuspend(void *priv) {
  printf(LOG_TAG"ivm app suspend\n");
  //VuiRecognStop();
  VuiRecognDone();
#if UNI_REPLY_TYPE == UNI_REPLY_TYPE_SPEAKER
  #ifndef USE_MP3
  LvpVoicePlayerSuspend();
  #else
  LvpMp3PlayerSuspend();
  #endif
#endif
#ifdef CONFIG_UNI_AUTO_GPIO
  user_gpio_suspend();
#endif
  BoardSetPowerSavePinMux();
  return 0;
}

static int IvmAppResume(void *priv) {
#ifdef CONFIG_UNI_AUTO_GPIO
  user_gpio_resume();
#else
  BoardSetUserPinMux();
#endif
#if UNI_REPLY_TYPE == UNI_REPLY_TYPE_SPEAKER
  #ifndef USE_MP3
  LvpVoicePlayerResume();
  #else
  LvpMp3PlayerResume();
  #endif
#endif

  printf(LOG_TAG"ivm app resume\n");
  return 0;
}

static int IvmAppInit(void) {
  printf(LOG_TAG"ivm app init\n");

#ifdef CONFIG_HW_EXT_FLASH
  padmux_set(7, 4);
  padmux_set(8, 4);
  padmux_set(9, 4);
  padmux_set(10, 4);
  int ext_flash_spi_speed = uni_clock_get_module_frequence(CLOCK_MODULE_GENERAL_SPI)/CONFIG_SF_DEFAULT_CLKDIV;
  uni_ext_spi_flash_probe(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, ext_flash_spi_speed, CONFIG_SF_DEFAULT_MODE);
#endif

  UNI_WAKEUP_SOURCE start_mode = uni_pmu_get_wakeup_source();
  if (start_mode == UNI_WAKEUP_SOURCE_COLD || start_mode == UNI_WAKEUP_SOURCE_WDT) {
    user_flash_init();
    // user_flash_test();
#if UNI_REPLY_TYPE == UNI_REPLY_TYPE_BUZZER
    user_buzzer_init(9, BuzzerEventCallback);
#elif UNI_REPLY_TYPE == UNI_REPLY_TYPE_SPEAKER
    #ifndef USE_MP3
    LvpVoicePlayerInit(PlayerEventCallback);
    LvpVoicePlayerSetVolume(50);
    #else
    LvpMp3PlayerInit(PlayerEventCallback);
    LvpMp3PlayerSetVolume(50);
    #endif
#endif
#ifdef DEFAULT_PCM_WELCOME
    if (user_player_play(DEFAULT_PCM_WELCOME) < 0) {
      _UniKwsRecognRelanch(UNI_LP_WAKEUP);
    }
#else
    _UniKwsRecognRelanch(UNI_LP_WAKEUP);
#endif
#ifdef CONFIG_UNI_UART_RECORD
    UniUartRecordInit();
#endif
  } else {
    _UniKwsRecognRelanch(UNI_LP_WAKEUP);
  }
  VuiReloadStandby(1, VAD_WAKEUP_TIMEOUT_MS);
  if (start_mode == UNI_WAKEUP_SOURCE_COLD || start_mode == UNI_WAKEUP_SOURCE_WDT) {
  } else {
    printf(LOG_TAG"LvpAudioInResume...\n");
    LvpAudioInResume();
  }

  return 0;
}

static int _UniHandleKwsEvent(uni_kws_result_t *kws_result) {
  int ret = -1;
  uint8_t need_reply = 1;
#ifdef CONFIG_UNI_AUTO_GPIO
  user_gpio_handle_kws_event(kws_result, &need_reply);
#endif
  if (need_reply) {
    ret = user_player_reply_list_random(kws_result->replay);
  }
  return ret;
}

// App Event Process
static int IvmAppEventResponse(APP_EVENT *app_event) {
  uni_kws_result_t *kws_result = (uni_kws_result_t *)app_event->attach;
  if (app_event->event_id < 100) {
    goto _END;
  }
  switch (app_event->event_id) {
    case UNI_KWS_WAKEUP_EVENT_ID:
      VuiRecognStop();
      VuiReloadStandby(0, 0);
      if (0 == _UniHandleKwsEvent(kws_result)) {
        g_cur_model = UNI_LP_LASR;
      } else {
        _UniKwsRecognRelanch(UNI_LP_LASR);
      }

      break;
    case UNI_KWS_CMD_EVENT_ID:
      VuiRecognStop();
      if (0 == strcmp(kws_result->action, "exitUni")) {
        if (0 == _UniHandleKwsEvent(kws_result)) {
          g_cur_model = UNI_LP_WAKEUP;
        } else {
          _UniKwsRecognRelanch(UNI_LP_WAKEUP);
        }
        VuiReloadStandby(1, SLEEP_TIMEOUT_MS);
      } else {
        if (0 == _UniHandleKwsEvent(kws_result)) {
          g_cur_model = UNI_LP_LASR;
        } else {
          _UniKwsRecognRelanch(UNI_LP_LASR);
        }
      }
      break;
    case UNI_KWS_SLEEP_EVENT_ID:
      VuiRecognStop();
      if (0 == _UniHandleKwsEvent(kws_result)) {
        g_cur_model = UNI_LP_WAKEUP;
      } else {
        _UniKwsRecognRelanch(UNI_LP_WAKEUP);
      }
      VuiReloadStandby(1, SLEEP_TIMEOUT_MS);
      break;
    case UNI_REPLAY_END_EVENT_ID:
      ArptPrint("TTS END\n");
      _UniKwsRecognRelanch(g_cur_model);
      break;
    default:
      printf(LOG_TAG"unknown event: %d\n", app_event->event_id);
      break;
  }
_END:
  if (app_event->attach) {
    //tmp_free(app_event->attach);
    app_event->attach = NULL;
  }
  return 0;
}

// APP Main Loop
static int IvmAppTaskLoop(void) {
  uni_watchdog_ping();
#ifdef CONFIG_UNI_UART_RECORD
  UniUartRecordTaskLoop();
#endif
  return 0;
}

LVP_APP ivm_app = {
  .app_name = "ivm app",
  .AppInit = IvmAppInit,
  .AppEventResponse = IvmAppEventResponse,
  .AppTaskLoop = IvmAppTaskLoop,
  .AppSuspend = IvmAppSuspend,
  .suspend_priv = "IvmAppSuspend",
  .AppResume = IvmAppResume,
  .resume_priv = "IvmAppResume",
};

LVP_REGISTER_APP(ivm_app);
