suppressPackageStartupMessages(library(shiny))
suppressPackageStartupMessages(library(bslib))
suppressPackageStartupMessages(library(DT))
suppressPackageStartupMessages(library(ggplot2))

# Ensure finlabR is available when running from source (not installed)
project_root_env <- Sys.getenv("FINLABR_PROJECT_ROOT", "")
if (nzchar(project_root_env) && requireNamespace("devtools", quietly = TRUE)) {
  devtools::load_all(project_root_env, quiet = TRUE)
} else if (requireNamespace("finlabR", quietly = TRUE)) {
  suppressPackageStartupMessages(library(finlabR))
} else if (requireNamespace("devtools", quietly = TRUE)) {
  app_dir <- normalizePath(getwd(), mustWork = TRUE)
  project_root <- normalizePath(file.path(app_dir, "..", "..", ".."), mustWork = TRUE)
  devtools::load_all(project_root, quiet = TRUE)
} else {
  stop("Package 'finlabR' is not installed and 'devtools' is missing.")
}

theme <- bs_theme(
  version = 5,
  bg = "#f7f7f2",
  fg = "#111111",
  primary = "#1f6f8b",
  base_font = font_google("Space Grotesk"),
  heading_font = font_google("Space Grotesk")
)

ui <- fluidPage(
  theme = theme,
  titlePanel("finlabR Dashboard"),
  sidebarLayout(
    sidebarPanel(
      width = 3,
      h4("Data"),
      radioButtons("data_source", "Source",
                   choices = c("Example (built-in)", "Yahoo (symbols)"),
                   selected = "Example (built-in)"),
      conditionalPanel(
        condition = "input.data_source == 'Yahoo (symbols)'",
        textInput("symbols", "Symbols (comma-separated)", "AAPL,MSFT,GLD,BTC-USD"),
        dateInput("from", "From", value = Sys.Date() - 365),
        dateInput("to", "To", value = Sys.Date())
      ),
      hr(),
      h4("MVO"),
      numericInput("rf", "Risk-free rate", 0.02, step = 0.005),
      numericInput("frontier_n", "Frontier points", 40, min = 10, max = 200),
      checkboxInput("allow_short", "Allow shorting", FALSE),
      hr(),
      h4("Regime Clustering"),
      numericInput("k_regimes", "Clusters (k)", 3, min = 2, max = 8),
      numericInput("window", "Rolling window", 60, min = 20, max = 250)
    ),
    mainPanel(
      tabsetPanel(
        tabPanel(
          "Overview",
          fluidRow(
            column(6, h4("Efficient Frontier"), plotOutput("frontier_plot")),
            column(6, h4("Max Sharpe Weights"), DTOutput("max_sharpe_tbl"))
          ),
          fluidRow(
            column(6, h4("Min Variance Weights"), DTOutput("min_var_tbl")),
            column(6, h4("Risk Parity Weights"), DTOutput("rp_tbl"))
          )
        ),
        tabPanel(
          "Regimes",
          fluidRow(
            column(12, h4("Regime Clusters (k-means)"), plotOutput("regime_plot"))
          ),
          fluidRow(
            column(12, h4("Regime Feature Table"), DTOutput("regime_tbl"))
          )
        ),
        tabPanel(
          "Risk",
          fluidRow(
            column(6, h4("VaR / CVaR"), DTOutput("varcvar_tbl")),
            column(6, h4("Asset Correlation"), plotOutput("corr_plot"))
          )
        )
      )
    )
  )
)

server <- function(input, output, session) {
  prices_data <- reactive({
    if (input$data_source == "Example (built-in)") {
      get_example_prices()
    } else {
      syms <- trimws(unlist(strsplit(input$symbols, ",")))
      px <- fetch_yahoo_prices(syms, input$from, input$to)
      data.frame(date = zoo::index(px), zoo::coredata(px))
    }
  })

  returns_data <- reactive({
    px <- prices_data()
    rets <- calc_returns(px[, -1, drop = FALSE])
    rets
  })

  mvo_data <- reactive({
    rets <- returns_data()
    ef <- mvo_efficient_frontier(rets, n = input$frontier_n,
                                 rf = input$rf, allow_short = input$allow_short)
    min_var <- mvo_min_variance(rets, allow_short = input$allow_short)
    max_sharpe <- mvo_max_sharpe(rets, rf = input$rf, allow_short = input$allow_short,
                                 n = input$frontier_n)
    list(ef = ef, min_var = min_var, max_sharpe = max_sharpe)
  })

  output$frontier_plot <- renderPlot({
    plot_efficient_frontier(mvo_data()$ef)
  })

  output$max_sharpe_tbl <- renderDT({
    dt <- data.frame(asset = names(mvo_data()$max_sharpe$weights),
                     weight = mvo_data()$max_sharpe$weights)
    datatable(dt, rownames = FALSE)
  })

  output$min_var_tbl <- renderDT({
    dt <- data.frame(asset = names(mvo_data()$min_var$weights),
                     weight = mvo_data()$min_var$weights)
    datatable(dt, rownames = FALSE)
  })

  output$rp_tbl <- renderDT({
    rets <- returns_data()
    rp <- risk_parity_weights(stats::cov(rets))
    dt <- data.frame(asset = colnames(rets), weight = rp$weights)
    datatable(dt, rownames = FALSE)
  })

  output$regime_plot <- renderPlot({
    rets <- returns_data()
    regimes <- market_regime_kmeans(rets, k = input$k_regimes, window = input$window)
    df <- data.frame(idx = seq_len(nrow(regimes$features)),
                     regime = factor(regimes$labels),
                     regimes$features)
    ggplot(df, aes(x = idx, y = df[, 3], color = regime)) +
      geom_line() +
      labs(x = "Time", y = "Feature 1") +
      theme_minimal()
  })

  output$regime_tbl <- renderDT({
    rets <- returns_data()
    regimes <- market_regime_kmeans(rets, k = input$k_regimes, window = input$window)
    df <- data.frame(regimes$features, regime = regimes$labels)
    datatable(df, rownames = FALSE)
  })

  output$varcvar_tbl <- renderDT({
    rets <- returns_data()
    datatable(var_cvar(rets, alpha = 0.95), rownames = FALSE)
  })

  output$corr_plot <- renderPlot({
    rets <- returns_data()
    corr <- asset_correlation(rets)
    df <- as.data.frame(as.table(corr))
    ggplot(df, aes(Var1, Var2, fill = Freq)) +
      geom_tile() +
      scale_fill_gradient2(low = "#3b4cc0", mid = "#f7f7f2", high = "#b40426",
                           midpoint = 0) +
      theme_minimal() +
      theme(axis.text.x = element_text(angle = 45, hjust = 1))
  })
}

shinyApp(ui, server)
