// Importa las clases necesarias para el manejo de formatos numéricos.
using System.Globalization;

// Define el espacio de nombres para clases compartidas del proyecto.
namespace Areas.Compartido;

// Clase estática que contiene métodos reutilizables para todas las ventanas de figuras.
// "Estática" significa que no necesitas crear una copia de la clase para usarla.
public static class CajasDeTextoAutoCalcular
{
  // Límite máximo de dígitos enteros (antes del punto decimal).
  private const int MaximoEnteros = 7;
  // Límite máximo de decimales permitidos después del punto.
  private const int MaximoDecimales = 2;

  // Método que se ejecuta cuando cambia el texto en una caja de texto.
  // Calcula el área automáticamente cuando el usuario escribe.
  // Parámetros:
  //   - cajasTexto: Las cajas de texto que contienen los valores (ej: base, altura).
  //   - etiquetaResultado: Donde se mostrará el resultado del cálculo.
  //   - calcular: La fórmula matemática a usar (diferente para cada figura).
  public static void CajaTexto_CambioTexto(TextBox[] cajasTexto, Label etiquetaResultado, Func<double[], double?> calcular)
  {
    // Recorre cada caja de texto para verificar si alguna está vacía.
    foreach (TextBox cajaTexto in cajasTexto)
    {
      // Si el texto está vacío o solo tiene espacios, limpia el resultado y termina.
      if (String.IsNullOrWhiteSpace(cajaTexto.Text))
      {
        etiquetaResultado.Text = "Área: ";
        return;
      }
    }

    // Crea un arreglo para guardar los números convertidos.
    double[] valores = new double[cajasTexto.Length];

    // Recorre cada caja de texto para convertir el texto a número.
    for (int indice = 0; indice < cajasTexto.Length; indice++)
    {
      // Intenta convertir el texto a número y verifica que sea mayor que cero.
      if (!IntentarAnalizar(cajasTexto[indice].Text, out double valor) || (valor <= 0))
      {
        // Si falla la conversión o el valor no es positivo, limpia el resultado y termina.
        etiquetaResultado.Text = "Área: ";
        return;
      }

      // Guarda el valor convertido en el arreglo.
      valores[indice] = valor;
    }

    // Ejecuta la fórmula de cálculo con los valores obtenidos.
    double? area = calcular(valores);

    // Si el cálculo fue exitoso, muestra el área con 2 decimales.
    if (area.HasValue)
    {
      etiquetaResultado.Text = $"Área: {area.Value:F2} u²";
    }
    // Si no se pudo calcular (la fórmula devolvió null), no limpia el resultado.
    // Esto permite que la fórmula muestre su propio mensaje de error.
  }

  // Método que intenta convertir un texto a número.
  // Solo acepta punto (.) como separador decimal.
  // Parámetros:
  //   - entrada: El texto a convertir a número.
  //   - valor: Donde se guardará el número si la conversión fue exitosa.
  // Devuelve: true si se pudo convertir, false si no.
  public static bool IntentarAnalizar(string entrada, out double valor)
  {
    // Inicializa el valor en cero.
    valor = 0;
    // Si el texto está vacío o solo tiene espacios, devuelve falso.
    if (String.IsNullOrWhiteSpace(entrada)) return false;

    // Elimina espacios al inicio y al final del texto.
    entrada = entrada.Trim();

    // Intenta convertir el texto a número (usando punto como separador decimal).
    return Double.TryParse(entrada, NumberStyles.Float, CultureInfo.InvariantCulture, out valor);
  }

  // Método que valida las teclas presionadas en una caja de texto.
  // Solo permite: números (0-9), punto decimal (.), y teclas especiales (Borrar, etc.).
  // Límites: máximo 7 dígitos enteros y 2 decimales.
  // Parámetros:
  //   - sender: La caja de texto donde se presionó la tecla. Puede ser null.
  //   - e: Información de la tecla presionada:
  //        - e.KeyChar: La tecla que se presionó.
  //        - e.Handled: Si es true, la tecla se ignora (no se escribe).
  public static void ValidarEntradaNumerica(object? sender, KeyPressEventArgs e)
  {
    // Obtiene la caja de texto donde se presionó la tecla.
    TextBox? cajaTexto = sender as TextBox;

    // Permite teclas especiales como Borrar (Backspace), Suprimir (Delete), etc.
    if (Char.IsControl(e.KeyChar))
    {
      return;
    }

    // Si no hay caja de texto, bloquea la tecla por seguridad.
    if (cajaTexto == null)
    {
      e.Handled = true;
      return;
    }

    // Obtiene el texto que quedará después de reemplazar la selección (si hay alguna).
    // Esto es importante cuando el usuario selecciona texto y escribe encima.
    string textoActual = cajaTexto.Text;
    int inicioSeleccion = cajaTexto.SelectionStart;
    int longitudSeleccion = cajaTexto.SelectionLength;

    // Simula cómo quedará el texto después de escribir el nuevo carácter.
    string textoResultante = textoActual.Substring(0, inicioSeleccion)
                           + e.KeyChar
                           + textoActual.Substring(inicioSeleccion + longitudSeleccion);

    // Busca la posición del punto decimal en el texto resultante.
    int posicionPunto = textoResultante.IndexOf('.');

    // Permite números del 0 al 9.
    if (Char.IsDigit(e.KeyChar))
    {
      // Si hay un punto decimal, verifica los límites de enteros y decimales.
      if (posicionPunto >= 0)
      {
        // Cuenta cuántos enteros hay antes del punto.
        int enterosResultantes = posicionPunto;
        // Cuenta cuántos decimales hay después del punto.
        int decimalesResultantes = textoResultante.Length - posicionPunto - 1;

        // Bloquea si se excede el límite de enteros o decimales.
        if (enterosResultantes > MaximoEnteros || decimalesResultantes > MaximoDecimales)
        {
          e.Handled = true;
        }
      }
      else
      {
        // No hay punto, verifica el límite de enteros.
        if (textoResultante.Length > MaximoEnteros)
        {
          e.Handled = true;
        }
      }
      return;
    }

    // Permite un solo punto decimal.
    if (e.KeyChar == '.')
    {
      // Solo permite el punto si no hay otro punto en el texto resultante.
      int cantidadPuntos = textoResultante.Count(c => c == '.');
      if (cantidadPuntos == 1)
      {
        // Verifica que la parte entera no exceda el límite.
        int posicionNuevoPunto = textoResultante.IndexOf('.');
        if (posicionNuevoPunto <= MaximoEnteros)
        {
          return;
        }
      }
    }

    // Bloquea cualquier otra tecla (letras, comas, símbolos, etc.).
    // e.Handled = true significa "ignora esta tecla, no la escribas".
    e.Handled = true;
  }
}
