﻿unit funciones;

interface

// --- INTERFAZ PÚBLICA ---
// Lo que pongas aquí será visible para otros formularios y unidades
// que añadan 'uGestionClaves' a su cláusula 'uses'.

// Genera una contraseña aleatoria de 8 caracteres que cumple las reglas.
function GenerarContraseñaSegura: string;

// Valida si una contraseña dada cumple las reglas (8 chars, 1 mayús, 1 num, 1 especial).
function ValidarContraseña(const AContraseña: string): Boolean;


implementation

// --- IMPLEMENTACIÓN PRIVADA ---
// Aquí va el código "real" y las variables o constantes
// que no necesitan ser vistas desde fuera.

uses
  System.SysUtils,  // Para Random, Length, Pos
  System.Character; // Para TCharacter, TArray<Char>

// Constantes privadas de la unidad.
// Ambas funciones usarán estas mismas constantes.
const
  cLongitud = 8;
  cMayusculas = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  cMinusculas = 'abcdefghijklmnopqrstuvwxyz';
  cNumeros    = '0123456789';
  cEspeciales = '!@#$%^&*()-_+=[]{}<>,.?';

// --- Implementación de las funciones ---

function GenerarContraseñaSegura: string;
var
  CAll: string;
  Chars: TArray<Char>;
  i, j: Integer;
  Temp: Char;
begin
  // NOTA: Randomize; se llama automáticamente en la sección 'initialization'
  // de esta unidad, por lo que no necesitas llamarlo en tus formularios.

  // 1. Crear el pool completo de caracteres
  CAll := cMayusculas + cMinusculas + cNumeros + cEspeciales;

  // 2. Ajustar el tamaño del array
  SetLength(Chars, cLongitud);

  // 3. Garantizar los requisitos mínimos (uno de cada)
  Chars[0] := cMayusculas[Random(Length(cMayusculas)) + 1];
  Chars[1] := cNumeros[Random(Length(cNumeros)) + 1];
  Chars[2] := cEspeciales[Random(Length(cEspeciales)) + 1];

  // 4. Rellenar el resto de caracteres aleatoriamente
  for i := 3 to cLongitud - 1 do
  begin
    Chars[i] := CAll[Random(Length(CAll)) + 1];
  end;

  // 5. Barajar (Mezclar) el array (Algoritmo Fisher-Yates)
  //    Para que los caracteres garantizados no estén siempre al inicio.
  for i := cLongitud - 1 downto 1 do
  begin
    j := Random(i + 1); // Índice aleatorio entre 0 e i
    // Intercambiar Chars[i] y Chars[j]
    Temp := Chars[i];
    Chars[i] := Chars[j];
    Chars[j] := Temp;
  end;

  // 6. Convertir el TArray<Char> de nuevo a un string
  Result := string(Chars);
end;

function ValidarContraseña(const AContraseña: string): Boolean;
var
  TieneMayus: Boolean;
  TieneNum: Boolean;
  TieneEspecial: Boolean;
  C: Char;
begin
  // Regla 1: Longitud exacta (usa la constante)
  if Length(AContraseña) < cLongitud then
  begin
    Result := False;
    Exit;
  end;

  // Inicializamos las banderas de comprobación
  TieneMayus := False;
  TieneNum := False;
  TieneEspecial := False;

  // Regla 2, 3 y 4: Comprobar el contenido
  for C in AContraseña do
  begin
    if TCharacter.IsUpper(C) then
      TieneMayus := True
    else if TCharacter.IsDigit(C) then
      TieneNum := True
    else if Pos(C, cEspeciales) > 0 then // Usa la constante de la unidad
      TieneEspecial := True;

    // Optimización: Si ya cumplimos todo, salimos del bucle
    if TieneMayus and TieneNum and TieneEspecial then
      Break;
  end;

  // El resultado final es verdadero SÓLO si las tres banderas son verdaderas
  Result := TieneMayus and TieneNum and TieneEspecial;
end;


// --- SECCIÓN DE INICIALIZACIÓN ---
// Este código se ejecuta UNA SOLA VEZ cuando la aplicación carga esta unidad.
initialization
  // Inicializa el generador de números aleatorios para toda la aplicación.
  // Es el lugar perfecto para ponerlo.
  Randomize;

end.
