# quickgen_chart_ui.R
library(shinyjs)
library(shinyAce)

## ==================== 右下角浮框 ====================
ui_chart_progress <- tags$div(
  id = "chart_progress_box",
  style = "display:none;
           position:fixed;
           bottom:15px; right:15px;
           width:220px; z-index:9999;
           background:#f5f5f5; color:#333;
           border:1px solid #337ab7; border-radius:4px;
           padding:10px 15px; box-shadow:0 2px 8px rgba(0,0,0,.25);",
  tags$strong(i18n$t("AI generating...")),
  tags$div(class = "progress",
           tags$div(class = "progress-bar progress-bar-striped active",
                    style = "width:100%"))
)

## ======== 警告弹窗========
ui_chart_warn <- tags$div(
  id = "chart_warn_box",
  style = "display:none;
           position:fixed;
           bottom:15px; right:15px;
           width:220px; z-index:9999;
           background:#fff3cd; color:#856404;
           border:1px solid #ffeaa7; border-radius:4px;
           padding:10px 15px; box-shadow:0 2px 8px rgba(0,0,0,.25);",
  tags$strong(i18n$t("Warning:Please enter a request related to descriptive statistics or visualization."))
)

## ==================== 统一入口 ====================
output$quickgen_chart <- renderUI({
  stat_tab_panel(
    menu      = i18n$t("Oneclick generation > AI assistance"),
    tool      = i18n$t("AI generates descriptive statistics(chart)"),
    tool_ui   = "chart_main_ui",
    output_panels = tabPanel(
      title = i18n$t("Chart Assistant"),
      value = "chart_panel",
      uiOutput("chart_result_area")
    )
  )
})

## ==================== 右侧 Chart 面板 ====================
output$chart_main_ui <- renderUI({
  tagList(
    useShinyjs(),
    ui_chart_progress,
    ui_chart_warn,
    wellPanel(
      i18n$t("Describe your analysis request"),
      returnTextAreaInput("chart_prompt",
                          label   = NULL,
                          placeholder = i18n$t("e. g. Please help me generate a cross frequency histogram of sex and smoker"),
                          rows    = 4,
                          value   = state_init("chart_prompt", "")),
      fluidRow(
        column(6, uiOutput("ui_chart_submit")),
        column(6, uiOutput("chart_loading"))
      )
    ),
    
    wellPanel(
      i18n$t("Generated R code"),
      uiOutput("chart_r_code_block"),
      fluidRow(
        column(6, actionButton("chart_run_code", i18n$t("Run code"), icon = icon("play"), class = "btn-success")),
        column(6, actionButton("chart_edit_code", i18n$t("Edit code"), icon = icon("edit"), class = "btn-default"))
      )
    ),
    
    help_and_report(
      modal_title = i18n$t("AI generates descriptive statistics(chart)"),
      fun_name    = "quickgen_chart",
      help_file   = inclMD(file.path(getOption("radiant.path.quickgen"), "app/tools/help/quickgen_chart.md")),
      lic = "by-sa"
    )
  )
})

## ==================== 控件渲染 ====================
output$ui_chart_submit <- renderUI({
  req(input$dataset)
  actionButton("chart_submit", i18n$t("Send"), icon = icon("magic"), class = "btn-primary")
})
output$chart_loading <- renderUI({
  if (isTRUE(r_values$chart_loading))
    tags$div(class = "progress",
             tags$div(class = "progress-bar progress-bar-striped active",
                      style = "width:100%",
                      i18n$t("Calling chart generation model...")))
})

## ==================== reactiveValues ====================
r_values <- reactiveValues(
  chart_r_code      = "",
  chart_result_type = "text",
  chart_result_ready = FALSE,
  chart_loading     = FALSE
)

## ==================== 生成代码 ====================
observeEvent(input$chart_submit, {
  if (is.empty(input$chart_prompt))
    return(showNotification(i18n$t("Please enter an analysis request"), type = "error"))
  
  r_values$chart_loading <- TRUE
  shinyjs::show("chart_progress_box")          # 显示右下角进度框
  on.exit({
    r_values$chart_loading <- FALSE
    shinyjs::hide("chart_progress_box")        # 无论成功失败都隐藏
  })
  
  res <- try(do.call(chart_generate,
                     list(prompt  = input$chart_prompt,
                          dataset = input$dataset,
                          envir   = r_data)),
             silent = TRUE)
  if (inherits(res, "try-error")) {
    showNotification(paste(i18n$t("Chart API error:"), res), type = "error")
    return()
  }
  
  r_values$chart_r_code      <- res$r_code
  r_values$chart_result_type <- res$type
  r_values$chart_result_ready <- FALSE
  r_values$auto_run       <- res$auto_run
  
  if (res$type == "empty") {
    shinyjs::show("chart_warn_box")
    shinyjs::delay(3000, shinyjs::hide("chart_warn_box"))
    return()
  }
  
  if (isTRUE(r_values$auto_run))
    shinyjs::click("chart_run_code")
})

## ==================== 显示 R 代码 ====================
output$chart_r_code_block <- renderUI({
  codes <- r_values$chart_r_code
  tags$pre(codes, style = "background:#f5f5f5; padding:10px; border-radius:4px;
                           font-family:monospace; white-space:pre-wrap; min-height:100px;")
})

## ==================== 运行代码 ====================
observeEvent(input$chart_run_code, {
  shinyjs::hide("chart_progress_box")   
  if (is.empty(r_values$chart_r_code)) return()
  
  if (trimws(r_values$chart_r_code) == "" || identical(r_values$chart_result_type, "empty")) {
    shinyjs::show("chart_warn_box")
    shinyjs::delay(3000, shinyjs::hide("chart_warn_box"))
    return()
  }
  
  tryCatch({
    result <- do.call(chart_run_code,
                      list(r_code = r_values$chart_r_code, envir = r_data))
    r_data$chart_temp_result <- result
    
    if (inherits(result, "gg") || inherits(result, "ggplot")) {
      r_values$chart_result_type <- "plot"
      output$chart_result_plot <- renderPlot(print(result))
    } else if (is.data.frame(result) || is.matrix(result)) {
      r_values$chart_result_type <- "table"
      output$chart_result_table <- DT::renderDataTable(
        DT::datatable(result, options = list(scrollX = TRUE, pageLength = 10)),
        server = FALSE
      )
    } else {
      r_values$chart_result_type <- "text"
      output$chart_result_text <- renderText(capture.output(print(result)))
    }
    r_values$chart_result_ready <- TRUE
  }, error = function(e) {
    r_values$chart_result_type <- "error"
    output$chart_result_error <- renderText(paste0(i18n$t("Error: "), e$message))
    r_values$chart_result_ready <- TRUE
    showNotification(paste0(i18n$t("Run code error: "), e$message),
                     type = "error", duration = NULL)
  })
}, ignoreInit = TRUE)

## ======== 结果展示区========
output$chart_result_area <- renderUI({
  req(r_values$chart_result_ready)
  tagList(
    conditionalPanel(
      condition = "output.chart_result_type == 'plot'",
      download_link("dlp_chart_plot"), br(),            
      plotOutput("chart_result_plot", width = "100%", height = "500px")
    ),
    conditionalPanel(
      condition = "output.chart_result_type == 'table'",
      download_link("dlp_chart_table"), br(),          
      DT::dataTableOutput("chart_result_table")
    ),
    conditionalPanel(
      condition = "output.chart_result_type == 'text' || output.chart_result_type == 'error'",
      verbatimTextOutput("chart_result_text")
    )
  )
})
output$chart_result_type <- reactive({
  r_values$chart_result_type 
})
outputOptions(output, "chart_result_type", suspendWhenHidden = FALSE)

## ==================== 编辑代码模态框 ====================
observeEvent(input$chart_edit_code, {
  showModal(
    modalDialog(
      title = i18n$t("Edit R Code"),
      size  = "l",
      footer = tagList(
        actionButton("chart_save_code", i18n$t("Save Changes"), class = "btn-primary"),
        modalButton(i18n$t("Cancel"))
      ),
      aceEditor(
        "chart_code_editor",
        mode = "r",
        theme = getOption("radiant.ace_theme", "tomorrow"),
        wordWrap = TRUE,
        value = r_values$chart_r_code,
        placeholder = i18n$t("Edit the generated R code here..."),
        vimKeyBinding = getOption("radiant.ace_vim.keys", FALSE),
        tabSize = getOption("radiant.ace_tabSize", 2),
        useSoftTabs = getOption("radiant.ace_useSoftTabs", TRUE),
        showInvisibles = getOption("radiant.ace_showInvisibles", FALSE),
        autoScrollEditorIntoView = TRUE,
        minLines = 15,
        maxLines = 30
      )
    )
  )
})

## ==================== 保存代码 ====================
observeEvent(input$chart_save_code, {
  r_values$chart_r_code <- input$chart_code_editor
  r_values$auto_run <- FALSE
  removeModal()
})

## ==================== PNG 下载处理器 ====================
dlp_chart_plot <- function(path) {
  result <- r_data$chart_temp_result
  if (inherits(result, "gg") || inherits(result, "ggplot")) {
    png(path, width = 800, height = 500, res = 96)
    print(result)
    dev.off()
  } else {
    png(path, width = 400, height = 400)
    plot(1, type = "n", axes = FALSE, xlab = "", ylab = "")
    text(1, 1, "No plot available", cex = 1.5)
    dev.off()
  }
}

download_handler(
  id = "dlp_chart_plot",
  fun = dlp_chart_plot,
  fn = function() paste0("plot_", Sys.Date()),
  type = "png",
  caption = i18n$t("Save chart-generated plot")
)

# ======== 表格 CSV 下载处理器 ========
dlp_chart_table <- function(path) {
  result <- r_data$chart_temp_result
  if (is.data.frame(result)) {
    df <- result
  } else if (is.table(result)) {
    df <- as.data.frame(result, stringsAsFactors = FALSE)
  } else if (is.matrix(result)) {
    df <- as.data.frame(result, stringsAsFactors = FALSE)
    if (!is.null(rownames(result))) {
      df <- cbind(row_name = rownames(result), df, row.names = NULL)
    }
  } else {
    df <- data.frame(msg = "No valid table available")
  }
  
  write.csv(df, file = path, row.names = FALSE, fileEncoding = "UTF-8")
}

download_handler(
  id      = "dlp_chart_table",
  fun     = dlp_chart_table,
  fn      = function() paste0("table_", Sys.Date()),
  type    = "csv",
  caption = i18n$t("Save chart-generated table")
)

## ==================== 报告 / 截图 ====================
chart_report <- function() {}
observeEvent(input$chart_report, chart_report())
observeEvent(input$chart_screenshot, radiant_screenshot_modal("modal_chart_screenshot"))
observeEvent(input$modal_chart_screenshot, { chart_report(); removeModal() })
