/*
 * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Marcel Valovy - 2.6 - initial implementation
package org.eclipse.persistence.testing.jaxb.beanvalidation;

import org.eclipse.persistence.exceptions.BeanValidationException;
import org.eclipse.persistence.jaxb.BeanValidationHelper;
import org.eclipse.persistence.jaxb.ConstraintViolationWrapper;
import org.eclipse.persistence.jaxb.JAXBContext;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
import org.eclipse.persistence.jaxb.JAXBMarshaller;
import org.eclipse.persistence.testing.jaxb.beanvalidation.dom.Employee;
import org.eclipse.persistence.testing.jaxb.beanvalidation.special.ConstructorAnnotatedEmployee;
import org.eclipse.persistence.testing.jaxb.beanvalidation.special.CustomAnnotatedEmployee;
import org.eclipse.persistence.testing.jaxb.beanvalidation.special.InheritanceAnnotatedEmployee;
import org.eclipse.persistence.testing.jaxb.beanvalidation.special.MethodAnnotatedEmployee;
import org.eclipse.persistence.testing.jaxb.beanvalidation.special.NonConstrainedClass;

import jakarta.validation.ClockProvider;
import jakarta.validation.ConstraintValidatorFactory;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.MessageInterpolator;
import jakarta.validation.ParameterNameProvider;
import jakarta.validation.Path;
import jakarta.validation.TraversableResolver;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorContext;
import jakarta.validation.ValidatorFactory;
import jakarta.validation.executable.ExecutableValidator;
import jakarta.validation.metadata.BeanDescriptor;
import jakarta.validation.metadata.ConstraintDescriptor;
import jakarta.xml.bind.SchemaOutputResolver;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.time.Clock;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import static org.eclipse.persistence.testing.jaxb.beanvalidation.ContentComparator.equalsXML;

/**
 * Test case storing non-standard tests, i.e. those that didn't fit neither in
 * {@link org.eclipse.persistence.testing.jaxb.beanvalidation.BeanValidationRuntimeTestCase} nor in
 * {@link org.eclipse.persistence.testing.jaxb.beanvalidation.BeanValidationBindingsTestCase}.
 *
 * @author Marcel Valovy - marcel.valovy@oracle.com
 */
public class BeanValidationSpecialtiesTestCase extends junit.framework.TestCase {

    private static final String NOT_NULL_MESSAGE = "{jakarta.validation.constraints.NotNull.message}";
    private static final String CUSTOM_ANNOTATION_MESSAGE = "{org.eclipse.persistence.moxy.CustomAnnotation.message}";

    private static final String GENERATOR_SCHEMA_WITH_FACETS =
            "org/eclipse/persistence/testing/jaxb/beanvalidation/generator/schema_with_facets.xsd";
    private static final String GENERATOR_SCHEMA_SUFFIX = "schema.xsd";
    private static String GENERATOR_SCHEMA;

    public void testGenerator() throws Exception {

        try {

            Map<String, Object> props = new HashMap<>();
            props.put(JAXBContextProperties.BEAN_VALIDATION_FACETS, true);
            jakarta.xml.bind.JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] {Employee.class}, props);

            String generatorSchemaWithFacetsPath = Thread.currentThread().getContextClassLoader().getResource(GENERATOR_SCHEMA_WITH_FACETS).getPath();
            GENERATOR_SCHEMA = generatorSchemaWithFacetsPath.substring(0, generatorSchemaWithFacetsPath.lastIndexOf('/') + 1) + GENERATOR_SCHEMA_SUFFIX;

            SchemaOutputResolver sor = new MySchemaOutputResolver();
            jaxbContext.generateSchema(sor);
            assertTrue(equalsXML(new File(generatorSchemaWithFacetsPath), new File(GENERATOR_SCHEMA)));

        } finally {
            if(GENERATOR_SCHEMA!=null) {
                File generatorSchema = new File(GENERATOR_SCHEMA);
                if(generatorSchema.exists()) {
                    assertTrue("Generated schema '" + GENERATOR_SCHEMA + "' was not deleted properly. DO that manually.", generatorSchema.delete());
                }
            }
        }

    }

    /**
     * Tests that we do not skip validation on classes that do not have any bean validation annotations but have a
     * custom validation annotation.
     */
    public void testCustomAnnotations() throws Exception {
        JAXBMarshaller marshaller = (JAXBMarshaller) JAXBContextFactory.createContext(new
                Class[]{CustomAnnotatedEmployee.class}, null).createMarshaller();
        CustomAnnotatedEmployee employee = new CustomAnnotatedEmployee().withId(0xCAFEBABE);

        try {
            marshaller.marshal(employee, new StringWriter());
            assertFalse("Constraints-breaking class escaped validation -> fail.", true);
        } catch (BeanValidationException ignored) {
        }

        Set<ConstraintViolationWrapper<Object>> violations = marshaller.getConstraintViolations();

        assertFalse("Some constraints were not validated, even though they should have been.", violations.isEmpty());

        // For all, i.e. one constraintViolations.
        for (ConstraintViolationWrapper cv : violations) {
            assertEquals(CUSTOM_ANNOTATION_MESSAGE, cv.getMessage());
        }
    }

    /**
     * Tests that we do not skip validation on classes that do not have any bean validation annotations on fields but
     * have some on methods.
     */
    public void testMethodAnnotations() throws Exception {
        JAXBMarshaller marshaller = (JAXBMarshaller) JAXBContextFactory.createContext(new
                Class[]{MethodAnnotatedEmployee.class}, null).createMarshaller();
        MethodAnnotatedEmployee employee = new MethodAnnotatedEmployee().withId(null);

        try {
            marshaller.marshal(employee, new StringWriter());
            assertFalse("Constraints-breaking class escaped validation -> fail.", true);
        } catch (BeanValidationException ignored) {
        }

        Set<ConstraintViolationWrapper<Object>> violations = marshaller.getConstraintViolations();

        assertFalse(violations.isEmpty());

        // For all, i.e. one constraintViolations.
        for (ConstraintViolationWrapper cv : violations) {
            assertEquals(NOT_NULL_MESSAGE, cv.getMessageTemplate());
        }
    }

    /**
     * Tests that we detect inherited constraints.
     */
    public void testInheritedAnnotations() throws Exception {
        JAXBMarshaller marshaller = (JAXBMarshaller) JAXBContextFactory.createContext(new
                Class[]{InheritanceAnnotatedEmployee.class}, null).createMarshaller();

        InheritanceAnnotatedEmployee employee = (InheritanceAnnotatedEmployee) new InheritanceAnnotatedEmployee()
                .withId(null);

        try {
            marshaller.marshal(employee, new StringWriter());
            assertFalse("Constraints-breaking class escaped validation -> fail.", true);
        } catch (BeanValidationException ignored) {
        }

        Set<ConstraintViolationWrapper<Object>> violations = marshaller.getConstraintViolations();

        assertFalse(violations.isEmpty());

        // For all, i.e. one constraintViolations.
        for (ConstraintViolationWrapper cv : violations) {
            assertEquals(NOT_NULL_MESSAGE, cv.getMessageTemplate());
        }
    }

    /**
     * Tests that we do not skip validation on classes that do not have any bean validation annotations on fields or
     * methods but have some on constructors.
     */
    public void testConstructorAnnotations() throws Exception {
        JAXBContext context = (JAXBContext)JAXBContextFactory.createContext(new Class[]{ConstructorAnnotatedEmployee.class}, null);
        JAXBMarshaller marshaller = context.createMarshaller();

        ConstructorAnnotatedEmployee employee = new ConstructorAnnotatedEmployee(null);

        try {
            marshaller.marshal(employee, new StringWriter());
        } catch (BeanValidationException ignored) {
        }

        // Ok, HV is not picking up constraints on constructor. But that does not mean anything. Our job is to ensure
        // that we correctly identify that the class is constrained and pass the object to the underlying BV impl.
        BeanValidationHelper beanValidationHelper = context.getBeanValidationHelper();
        assertTrue(beanValidationHelper.getConstraintsMap().containsKey(ConstructorAnnotatedEmployee.class));

        // This will not detect the constraints violation on constructor (on HV 5.1), although it should.
//        Set<? extends ConstraintViolation<?>> violations = marshaller.getConstraintViolations();
//
//        assertFalse(violations.isEmpty());
//
//        // For all, i.e. one constraintViolations.
//        for (ConstraintViolation constraintViolation : violations) {
//            assertEquals(NOT_NULL_MESSAGE, constraintViolation.getMessageTemplate());
//        }
    }

    /**
     * Tests {@link org.eclipse.persistence.jaxb.JAXBContextProperties#BEAN_VALIDATION_NO_OPTIMISATION} property.
     */
    public void testNoOptimisationOption() throws Exception {
        JAXBMarshaller marshaller = (JAXBMarshaller) JAXBContextFactory.createContext(
                new Class[]{ NonConstrainedClass.class },
                new HashMap<String, Object>(){{
                    put(JAXBContextProperties.BEAN_VALIDATION_NO_OPTIMISATION, true);
                    put(JAXBContextProperties.BEAN_VALIDATION_FACTORY, new CustomValidatorFactory());
                }})
                .createMarshaller();

        try {
            marshaller.marshal( new NonConstrainedClass(), new StringWriter());
        } catch (BeanValidationException ignored) {
        }

        Set<ConstraintViolationWrapper<Object>> violations = marshaller.getConstraintViolations();

        assertFalse(violations.isEmpty());
    }

    private static class MySchemaOutputResolver extends SchemaOutputResolver {

        @Override
        public Result createOutput(String uri, String suggestedFileName) throws IOException {
            File file = new File(GENERATOR_SCHEMA);
            StreamResult result = new StreamResult(file);
            result.setSystemId(file.toURI().toURL().toString());
            return result;
        }

    }

    /**
     * Validator factory which returns {@code false} from method {@code validate()} in provided {@code Validator}.
     */
    private class CustomValidatorFactory implements ValidatorFactory {

        @Override
        public Validator getValidator() {
            return new Validator() {
                @Override
                public <T> Set<ConstraintViolation<T>> validate(T t, Class<?>... classes) {
                    return new HashSet<ConstraintViolation<T>>(){
                        { this.add(new ConstraintViolation<T>() {
                            @Override
                            public String getMessage() {
                                return "";
                            }

                            @Override
                            public String getMessageTemplate() {
                                return null;
                            }

                            @Override
                            public T getRootBean() {
                                //noinspection unchecked
                                return (T) new Object();
                            }

                            @Override
                            public Class<T> getRootBeanClass() {
                                return null;
                            }

                            @Override
                            public Object getLeafBean() {
                                return null;
                            }

                            @Override
                            public Object[] getExecutableParameters() {
                                return new Object[0];
                            }

                            @Override
                            public Object getExecutableReturnValue() {
                                return null;
                            }

                            @Override
                            public Path getPropertyPath() {
                                return new Path() {
                                    @Override
                                    public Iterator<Node> iterator() {
                                        return null;
                                    }
                                };
                            }

                            @Override
                            public Object getInvalidValue() {
                                return null;
                            }

                            @Override
                            public ConstraintDescriptor<?> getConstraintDescriptor() {
                                return null;
                            }

                            @Override
                            public <U> U unwrap(Class<U> type) {
                                return null;
                            }
                        }); }
                    };
                }

                @Override
                public <T> Set<ConstraintViolation<T>> validateProperty(T t, String s, Class<?>... classes) {
                    return null;
                }

                @Override
                public <T> Set<ConstraintViolation<T>> validateValue(Class<T> tClass, String s, Object o, Class<?>... classes) {
                    return null;
                }

                @Override
                public BeanDescriptor getConstraintsForClass(Class<?> aClass) {
                    return null;
                }

                @Override
                public <T> T unwrap(Class<T> tClass) {
                    return null;
                }

                @Override
                public ExecutableValidator forExecutables() {
                    return null;
                }
            };
        }

        @Override
        public ValidatorContext usingContext() {
            return null;
        }

        @Override
        public MessageInterpolator getMessageInterpolator() {
            return null;
        }

        @Override
        public TraversableResolver getTraversableResolver() {
            return null;
        }

        @Override
        public ConstraintValidatorFactory getConstraintValidatorFactory() {
            return null;
        }

        @Override
        public ParameterNameProvider getParameterNameProvider() {
            return null;
        }

        @Override
        public <T> T unwrap(Class<T> tClass) {
            return null;
        }

        @Override
        public void close() {

        }

        @Override
        public ClockProvider getClockProvider() {
            return new ClockProvider() {
                @Override
                public Clock getClock() {
                    return Clock.systemUTC();
                }
            };
        }
    }
}
