#' Simulate a Two-Group Functional Dataset
#'
#' Generates a labelled functional dataset from two Gaussian processes,
#' useful for illustrating and testing the classifiers in `fdclassify`.
#' The two groups differ in their mean function:
#' \deqn{
#'   x_i(t) = \mu_g(t) + \varepsilon_i(t), \quad
#'   \varepsilon_i(t) \sim \mathcal{GP}(0, \sigma^2),
#' }
#' where \eqn{\mu_0(t) = A_0 \sin(2\pi f_0 t)} and
#' \eqn{\mu_1(t) = A_1 \cos(2\pi f_1 t)} by default.
#'
#' @param n0 Number of curves in group 0.  Default 50.
#' @param n1 Number of curves in group 1.  Default 50.
#' @param M  Number of time points.  Default 100.
#' @param sigma Standard deviation of the noise.  Default 0.4.
#' @param A0,A1 Amplitudes of the mean functions.  Both default to 1.
#' @param f0,f1 Frequencies of the mean functions.  Both default to 1.
#' @param seed Optional integer seed.
#'
#' @return A list with:
#'   \describe{
#'     \item{`X`}{Numeric matrix \eqn{(n_0+n_1) \times M}.}
#'     \item{`y`}{Integer vector of labels (0 or 1).}
#'     \item{`grid`}{Numeric vector of length \eqn{M} on \eqn{[0,1]}.}
#'   }
#'
#' @examples
#' dat <- simulate_fd(n0 = 40, n1 = 40, seed = 1)
#' matplot(t(dat$X[dat$y == 0, ]), type = "l", col = "steelblue",
#'         lty = 1, xlab = "t", ylab = "x(t)", main = "Simulated curves")
#' matlines(t(dat$X[dat$y == 1, ]), col = "firebrick", lty = 1)
#' legend("topright", legend = c("Group 0", "Group 1"),
#'        col = c("steelblue","firebrick"), lty = 1)
#'
#' @export
simulate_fd <- function(n0    = 50L,
                        n1    = 50L,
                        M     = 100L,
                        sigma = 0.4,
                        A0    = 1,
                        A1    = 1,
                        f0    = 1,
                        f1    = 1,
                        seed  = NULL) {
  if (!is.null(seed)) set.seed(seed)
  grid <- seq(0, 1, length.out = M)
  mu0  <- A0 * sin(2 * pi * f0 * grid)
  mu1  <- A1 * cos(2 * pi * f1 * grid)
  X0   <- t(replicate(n0, mu0 + stats::rnorm(M, sd = sigma)))
  X1   <- t(replicate(n1, mu1 + stats::rnorm(M, sd = sigma)))
  list(
    X    = rbind(X0, X1),
    y    = rep(0:1, c(n0, n1)),
    grid = grid
  )
}
