---
title: "Cálculo Actuarianos"
author: "JMdeL"
date: "`r Sys.Date()`"
output:
  html_document:
    toc: true
    toc_float: true
    theme: cosmo
    highlight: tango
runtime: shiny
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message = FALSE, warning = FALSE)
library(knitr)
library(kableExtra)

```

## Planteamiento

Dadas las probabilidades de supervivencia de $k$ individuos
$p_1, p_2, \ldots, p_k$, los **números actuarianos** se definen como:

$$
Z_j = \sum_{i_1 < i_2 < \cdots < i_j} p_{i_1} p_{i_2} \cdots p_{i_j},
\qquad j = 1, 2, \ldots, k
$$

Es decir:

- $Z_1 = \sum_i p_i$ (suma de las probabilidades)
- $Z_2 = \sum_{i<j} p_i p_j$ (suma de productos de 2 en 2)
- $\ldots$
- $Z_k = p_1 p_2 \cdots p_k$ (producto de todas)

---

## Caja de introducción de datos

Introduce las probabilidades separadas por comas (o por espacios). Por ejemplo: `0.98, 0.8, 0.7, 0.75, 0.6`. Todos los valores deben estar entre 0 y 1.

```{r caja-inputs, echo=FALSE}
fluidRow(
  column(8,
    textInput("probs", 
              label = "Probabilidades de supervivencia (p_i):", 
              value = "0.98, 0.8, 0.7, 0.75, 0.6",
              width = "100%")
  ),
  column(4,
    br(),
    actionButton("calcular", "Calcular", 
                 class = "btn-primary", 
                 style = "font-weight: bold; width: 100%; margin-top: 5px;")
  )
)
```

---

## Cálculo y Resultados

```{r logica-server, echo=FALSE}
# Función que calcula TODOS los números actuarianos de golpe
calc_Z <- function(p) {
  n <- length(p)
  Z <- numeric(n + 1)
  Z[1] <- 1
  for (i in 1:n) {
    for (j in i:1) {
      Z[j + 1] <- Z[j + 1] + p[i] * Z[j]
    }
  }
  Z[-1]   # quitar Z_0
}

# Reactivo que procesa la cadena de texto introducida
datos_reactivos <- reactive({
  req(input$probs)
  
  # Convertir el texto en vector numérico (limpiando espacios y comas)
  texto_limpio <- gsub("[;|]", ",", input$probs) # por si acaso ponen punto y coma
  p <- as.numeric(trimws(unlist(strsplit(texto_limpio, ","))))
  
  # Validaciones
  if (length(p) == 0 || any(is.na(p))) {
    return(list(error = "Error: asegúrate de introducir números separados por comas."))
  }
  if (any(p < 0) || any(p > 1)) {
    return(list(error = "Error: todas las probabilidades deben estar entre 0 y 1."))
  }
  
  # Calcular Z
  Z <- calc_Z(p)
  
  # Devolver resultados
  list(p = p, Z = Z, error = NULL)
})
```

### Tabla

```{r tabla-output, echo=FALSE}
renderUI({
  res <- datos_reactivos()
  
  if (!is.null(res$error)) {
    return(tags$div(style = "color:red; font-weight:bold; margin-bottom:20px;", res$error))
  }
  
  # Crear tabla de resultados
  resultados <- data.frame(
    Numero = paste0("Z", 1:length(res$Z)),
    Valor  = round(res$Z, 6)
  )
  
  # Renderizar kable en HTML
  HTML(
    kable(resultados,
          caption = "Números actuarianos",
          col.names = c("Número", "Valor"),
          format = "html") |>
      kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                    full_width = FALSE,
                    position = "center")
  )
})
```

### Comprobación

```{r comprobacion-output, echo=FALSE}
renderPrint({
  res <- datos_reactivos()
  if (!is.null(res$error)) return(invisible())
  
  p <- res$p
  Z <- res$Z
  
  cat("Z1 (suma de probabilidades):", round(sum(p), 6), "\n")
  cat("Z", length(Z), " (producto de todas):", round(prod(p), 6), "\n\n", sep = "")
  cat("¿Coinciden con la tabla?",
      isTRUE(all.equal(Z[1], sum(p))) &&
      isTRUE(all.equal(Z[length(Z)], prod(p))),
      "\n")
})
```

### Gráfico

```{r grafico-output, echo=FALSE}
renderPlot({
  res <- datos_reactivos()
  if (!is.null(res$error)) return(invisible())
  
  Z <- res$Z
  
  # Ajustar márgenes para que quepan las etiquetas
  par(mar = c(5, 4, 4, 2) + 0.1)
  
  barplot(Z,
          names.arg = paste0("Z", 1:length(Z)),
          col = "#2c7be0",
          border = "white",
          main = "Números actuarianos",
          ylab = "Valor",
          xlab = "Z_i",
          las = 2, cex.names = 0.9) # Rotar etiquetas por si hay muchas
})
```

---

## Cómo introducir los datos

Solo tienes que escribir en la caja de texto del principio, por ejemplo:

- `0.9, 0.8, 0.7` (tres individuos)
- `0.98 0.80 0.70 0.75 0.60` (separados por espacios también vale)
- `0.5; 0.5; 0.5` (separados por punto y coma también vale)

Y pulsar el botón **Calcular**. La tabla, la comprobación y el gráfico se actualizarán automáticamente al vuelo.