/** Operaciones sobre figuras, escritas con switch sobre el tipo sealed Shape. */
public final class Shapes {
    private Shapes() {
    }

    /** Área de la figura. Sin default: si falta un subtipo, no compila. */
    public static double area(Shape s) {
        return switch (s) {
            case Circle(double r) -> Math.PI * r * r;
            case Square(double side) -> side * side;
            case Triangle(double b, double h) -> b * h / 2;
        };
    }

    /** Una descripción corta. Muestra guards (when) y case null. */
    public static String describe(Shape s) {
        return switch (s) {
            case null -> "sin figura";
            case Circle c when c.radius() >= 10 -> "círculo grande";
            case Circle c -> "círculo de radio " + c.radius();
            case Square(double side) when side == 1 -> "cuadrado unitario";
            case Square sq -> "cuadrado de lado " + sq.side();
            case Triangle t -> "triángulo de base " + t.base();
        };
    }

    /** Lo mismo que area, con instanceof: compila aunque falte un caso. */
    public static double areaWithInstanceof(Shape s) {
        if (s instanceof Circle c) {
            return Math.PI * c.radius() * c.radius();
        } else if (s instanceof Square sq) {
            return sq.side() * sq.side();
        }
        throw new IllegalArgumentException("figura desconocida: " + s);
    }
}
