import java.util.*;
import java.lang.*;
import java.io.*;
import java.math.*;
import java.util.function.*;

// The main method must be in a class named "Main".
class Main {
    public static void main(String[] args) {
        UserValidationExample.run();
        OrderProcessingExample.run();
    }
}

class UserValidationExample {

    public static void run() {
        User user = new User("", "invalid-email", -5);
        
        Result<User> validationResult = validateUser(user);
        
        validationResult
            .onSuccess(u -> System.out.println("User is valid: " + u))
            .onFailure(error -> System.err.println("Validation failed: " + error));
    }
    
    public static Result<User> validateUser(User user) {
        return validateName(user)
            .flatMap(UserValidationExample::validateEmail)
            .flatMap(UserValidationExample::validateAge);
    }
    
    private static Result<User> validateName(User user) {
        return Result.ensure(
            user, 
            u -> u.name() != null && !u.name().isBlank(), 
            "Name cannot be empty"
        );
    }
    
    private static Result<User> validateEmail(User user) {
        return Result.ensure(
            user, 
            u -> u.email() != null && u.email().contains("@"), 
            "Email must be valid"
        );
    }
    
    private static Result<User> validateAge(User user) {
        return Result.ensure(
            user, 
            u -> u.age() >= 0, 
            "Age cannot be negative"
        );
    }
}

record User(String name, String email, int age) {}


class OrderProcessingExample {
    public static void run() {
        Order order = new Order(
            List.of(
                new OrderItem("Book", new BigDecimal("29.99"), 2),
                new OrderItem("Pen", new BigDecimal("5.99"), 5)
            ),
            "john@example.com"
        );
        
        Result<Receipt> receiptResult = processOrder(order);
        
        receiptResult
            .onSuccess(receipt -> System.out.println("Order processed successfully: " + receipt))
            .onFailure(error -> System.err.println("Failed to process order: " + error));
    }
    
    public static Result<Receipt> processOrder(Order order) {
        return validateOrder(order)
            .flatMap(OrderProcessingExample::calculateTotal)
            .flatMap(OrderProcessingExample::applyDiscounts)
            .flatMap(OrderProcessingExample::processPayment)
            .map(OrderProcessingExample::generateReceipt);
    }
    
    private static Result<Order> validateOrder(Order order) {
        if (order == null) {
            return Result.failure("Order cannot be null");
        }
        
        if (order.items().isEmpty()) {
            return Result.failure("Order must have at least one item");
        }
        
        if (order.customerEmail() == null || !order.customerEmail().contains("@")) {
            return Result.failure("Valid customer email is required");
        }
        
        return Result.success(order);
    }
    
    private static Result<Order> calculateTotal(Order order) {
        try {
            BigDecimal total = order.items().stream()
                .map(item -> item.price().multiply(BigDecimal.valueOf(item.quantity())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);
            
            return Result.success(new Order(order.items(), order.customerEmail(), total));
        } catch (Exception e) {
            return Result.failure("Failed to calculate total: " + e.getMessage());
        }
    }
    
    private static Result<Order> applyDiscounts(Order order) {
        // Aplicar un 10% de descuento si el total es mayor a 100
        if (order.total().compareTo(new BigDecimal("100")) > 0) {
            BigDecimal discount = order.total().multiply(new BigDecimal("0.1"));
            BigDecimal discountedTotal = order.total().subtract(discount);
            return Result.success(new Order(
                order.items(), 
                order.customerEmail(), 
                discountedTotal,
                discount
            ));
        }
        return Result.success(order);
    }
    
    private static Result<Order> processPayment(Order order) {
        // Simulación de procesamiento de pago
        if (order.total().compareTo(new BigDecimal("1000")) > 0) {
            return Result.failure("Amount exceeds maximum allowed for online payment");
        }
        
        // Simular éxito del pago
        return Result.success(order);
    }
    
    private static Receipt generateReceipt(Order order) {
        return new Receipt(
            UUID.randomUUID().toString(),
            order.items(),
            order.total(),
            order.discount(),
            System.currentTimeMillis()
        );
    }
}

record Order(
    List<OrderItem> items, 
    String customerEmail, 
    BigDecimal total, 
    BigDecimal discount
) {
    public Order(List<OrderItem> items, String customerEmail) {
        this(items, customerEmail, BigDecimal.ZERO, BigDecimal.ZERO);
    }
    
    public Order(List<OrderItem> items, String customerEmail, BigDecimal total) {
        this(items, customerEmail, total, BigDecimal.ZERO);
    }
}

record OrderItem(String name, BigDecimal price, int quantity) {}

record Receipt(
    String id, 
    List<OrderItem> items, 
    BigDecimal total, 
    BigDecimal discount, 
    long timestamp
) {}

interface Result<T> {
    static <T> Result<T> success(T value) {
        return new Success<>(value);
    }
    
    static <T> Result<T> failure(String error) {
        return new Failure<>(error);
    }
    
    static <T> Result<T> of(Supplier<T> supplier) {
        try {
            return Result.success(supplier.get());
        } catch (Exception e) {
            return Result.failure(e.getMessage());
        }
    }
    
    static <T> Result<T> ensure(T value, Predicate<T> predicate, String errorMessage) {
        return predicate.test(value) 
            ? Result.success(value) 
            : Result.failure(errorMessage);
    }
    
    boolean isSuccess();
    boolean isFailure();
    T getValue();
    String getError();
    <U> Result<U> map(Function<T, U> mapper);
    <U> Result<U> flatMap(Function<T, Result<U>> mapper);
    Result<T> onSuccess(Consumer<T> consumer);
    Result<T> onFailure(Consumer<String> consumer);
    T orElse(T defaultValue);
    T orElseThrow();
    T orElseThrow(Function<String, ? extends RuntimeException> exceptionMapper);
}

record Success<T>(T value) implements Result<T> {
    public Success {
        Objects.requireNonNull(value, "Value cannot be null");
    }
    
    @Override
    public boolean isSuccess() {
        return true;
    }
    
    @Override
    public boolean isFailure() {
        return false;
    }
    
    @Override
    public T getValue() {
        return value;
    }
    
    @Override
    public String getError() {
        throw new IllegalStateException("Cannot get error from Success");
    }
    
    @Override
    public <U> Result<U> map(Function<T, U> mapper) {
        try {
            return Result.success(mapper.apply(value));
        } catch (Exception e) {
            return Result.failure("Error during mapping: " + e.getMessage());
        }
    }
    
    @Override
    public <U> Result<U> flatMap(Function<T, Result<U>> mapper) {
        try {
            return mapper.apply(value);
        } catch (Exception e) {
            return Result.failure("Error during flatMapping: " + e.getMessage());
        }
    }
    
    @Override
    public Result<T> onSuccess(Consumer<T> consumer) {
        consumer.accept(value);
        return this;
    }
    
    @Override
    public Result<T> onFailure(Consumer<String> consumer) {
        return this;
    }
    
    @Override
    public T orElse(T defaultValue) {
        return value;
    }
    
    @Override
    public T orElseThrow() {
        return value;
    }
    
    @Override
    public T orElseThrow(Function<String, ? extends RuntimeException> exceptionMapper) {
        return value;
    }
}

record Failure<T>(String error) implements Result<T> {
    public Failure {
        Objects.requireNonNull(error, "Error cannot be null");
    }
    
    @Override
    public boolean isSuccess() {
        return false;
    }
    
    @Override
    public boolean isFailure() {
        return true;
    }
    
    @Override
    public T getValue() {
        throw new IllegalStateException("Cannot get value from Failure");
    }
    
    @Override
    public String getError() {
        return error;
    }
    
    @Override
    public <U> Result<U> map(Function<T, U> mapper) {
        return Result.failure(error);
    }
    
    @Override
    public <U> Result<U> flatMap(Function<T, Result<U>> mapper) {
        return Result.failure(error);
    }
    
    @Override
    public Result<T> onSuccess(Consumer<T> consumer) {
        return this;
    }
    
    @Override
    public Result<T> onFailure(Consumer<String> consumer) {
        consumer.accept(error);
        return this;
    }
    
    @Override
    public T orElse(T defaultValue) {
        return defaultValue;
    }
    
    @Override
    public T orElseThrow() {
        throw new RuntimeException(error);
    }
    
    @Override
    public T orElseThrow(Function<String, ? extends RuntimeException> exceptionMapper) {
        throw exceptionMapper.apply(error);
    }
}

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: