/*
 * Copyright 2009 Inspire-Software.com
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package org.yes.cart.web.service.rest;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.context.WebApplicationContext;
import org.yes.cart.constants.AttributeNamesKeys;
import org.yes.cart.dao.GenericFTSCapableDAO;
import org.yes.cart.dao.constants.DaoServiceBeanKeys;
import org.yes.cart.dao.impl.AbstractTestDAO;
import org.yes.cart.domain.entity.Mail;
import org.yes.cart.domain.entity.Product;
import org.yes.cart.domain.ro.AddressUpdateRO;
import org.yes.cart.domain.ro.CustomerUpdateRO;
import org.yes.cart.domain.ro.RegisterRO;
import org.yes.cart.service.domain.MailService;
import org.yes.cart.utils.HQLUtils;
import org.yes.cart.utils.RuntimeConstants;

import javax.annotation.Resource;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * User: denispavlov
 * Date: 30/03/2015
 * Time: 11:41
 */
public abstract class AbstractSuiteTest extends AbstractTestDAO {

    static String X_CW_TOKEN = "X-CW-TOKEN";
    static final Locale LOCALE = Locale.ENGLISH;

    @Resource(name = "shopResolverFilter")
    private Filter shopResolverFilter;

    @Resource(name = "shoppingCartFilter")
    private Filter shoppingCartFilter;

    @Resource(name = "requestLocaleResolverFilter")
    private Filter requestLocaleResolverFilter;


    @Autowired
    private MailService mailService;

    @Autowired
    private RuntimeConstants runtimeConstants;


    @Resource
    private WebApplicationContext webApplicationContext;

    protected MockMvc mockMvc;

    @Override
    protected ApplicationContext createContext() {
        return webApplicationContext;
    }

    @Override
    @Before
    public void setUp() {

        super.setUp();

        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
                .addFilter(shopResolverFilter)
                .addFilter(shoppingCartFilter)
                .addFilter(requestLocaleResolverFilter)
                .build();

        X_CW_TOKEN = runtimeConstants.getConstant("webapp.token.name");
    }


    /**
     * Perform reindex.
     */
    protected void reindex() {
        PlatformTransactionManager transactionManager =   ctx().getBean("transactionManager", PlatformTransactionManager.class);
        TransactionTemplate tx = new TransactionTemplate(transactionManager);


        tx.execute(new TransactionCallbackWithoutResult() {
            @Override
            public void doInTransactionWithoutResult(TransactionStatus status) {

                ((GenericFTSCapableDAO<Product, Long, Object>) ctx().getBean(DaoServiceBeanKeys.PRODUCT_DAO)).fullTextSearchReindex(false, 1000);
                ((GenericFTSCapableDAO<Product, Long, Object>) ctx().getBean(DaoServiceBeanKeys.PRODUCT_SKU_DAO)).fullTextSearchReindex(false, 1000);

            }
        });
    }

    /**
     * Map object to JSON bytes
     *
     * @param object object to map
     * @return bytes for request body
     *
     * @throws Exception
     */
    protected byte[] toJsonBytes(final Object object) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        return mapper.writeValueAsBytes(object);
    }


    /**
     * JSON bytes for registration request object
     *
     * @param email customer email
     * @return bytes for request body
     *
     * @throws Exception
     */
    protected byte[] toJsonBytesRegistrationDetails(final String email) throws Exception {

        final RegisterRO register = new RegisterRO();
        register.setCustomerType(AttributeNamesKeys.Cart.CUSTOMER_TYPE_REGULAR);
        register.setCustom(new HashMap<String, String>());
        register.getCustom().put("CUSTOMER_EMAIL", email);
        register.getCustom().put("firstname", "Bob");
        register.getCustom().put("lastname", "Doe");
        register.getCustom().put("CUSTOMER_PHONE", "123123123");

        return toJsonBytes(register);

    }

    /**
     * JSON bytes for profile update object
     *
     * @param email customer email
     * @return bytes for request body
     *
     * @throws Exception
     */
    protected byte[] toJsonBytesProfileUpdatesDetails(final String email) throws Exception {

        final CustomerUpdateRO register = new CustomerUpdateRO();
        register.setCustomerType(AttributeNamesKeys.Cart.CUSTOMER_TYPE_REGULAR);
        register.setCustom(new HashMap<String, String>());
        register.getCustom().put("CUSTOMER_EMAIL", email);
        register.getCustom().put("firstname", "John");
        register.getCustom().put("lastname", "Doe");
        register.getCustom().put("CUSTOMER_PHONE", "4444444444");

        return toJsonBytes(register);

    }

    /**
     * JSON bytes for profile update object
     *
     * @param newLogin customer new username
     * @param password password to confirm the change
     *
     * @return bytes for request body
     *
     * @throws Exception
     */
    protected byte[] toJsonBytesChangeUsername(final String newLogin, final String password) throws Exception {

        final CustomerUpdateRO register = new CustomerUpdateRO();
        register.setCustomerType(AttributeNamesKeys.Cart.CUSTOMER_TYPE_REGULAR);
        register.setCustomerLogin(newLogin);
        register.setPassword(password);

        return toJsonBytes(register);

    }

    /**
     * JSON bytes for registration request object
     *
     * @param email customer email
     * @return bytes for request body
     *
     * @throws Exception
     */
    protected byte[] toJsonBytesSubRegistrationDetails(final String email) throws Exception {

        final RegisterRO register = new RegisterRO();
        register.setCustomerType(AttributeNamesKeys.Cart.CUSTOMER_TYPE_REGULAR);
        register.setOrganisation("Sub Gadget universe");
        register.setCustom(new HashMap<String, String>());
        register.getCustom().put("CUSTOMER_EMAIL", email);
        register.getCustom().put("firstname", "Bob");
        register.getCustom().put("lastname", "Doe");
        register.getCustom().put("CUSTOMER_PHONE", "123123123");

        return toJsonBytes(register);

    }

    /**
     * JSON bytes for registration request object
     *
     * @param email customer email
     * @return bytes for request body
     *
     * @throws Exception
     */
    protected byte[] toJsonBytesGuestDetails(final String email) throws Exception {

        final RegisterRO register = new RegisterRO();
        register.setCustomerType(AttributeNamesKeys.Cart.CUSTOMER_TYPE_GUEST);
        register.setCustom(new HashMap<String, String>());
        register.getCustom().put("CUSTOMER_EMAIL", email);
        register.getCustom().put("firstname", "Bob");
        register.getCustom().put("lastname", "Doe");

        return toJsonBytes(register);

    }


    /**
     * JSON bytes for address request object
     *
     * @param state state code
     * @param country country code
     * @return bytes for request body
     *
     * @throws Exception
     */
    protected byte[] toJsonBytesAddressDetails(final String type, final String state, final String country) throws Exception {

        final AddressUpdateRO address = new AddressUpdateRO();
        address.setAddressType(type);
        address.setDefaultAddress(true);

        final Map<String, String> custom = new HashMap<>();
        custom.put("addrline1", "In the middle of");
        custom.put("city", "Nowhere");
        custom.put("postcode", "0001");
        custom.put("stateCode", state);
        custom.put("countryCode", country);

        address.setCustom(custom);

        return toJsonBytes(address);

    }


    protected boolean hasEmails(final String recipient) {

        return !this.mailService.findByCriteria(" where e.recipients = ?1", recipient).isEmpty();

    }

    protected Mail getEmailBySubject(final String subject, final String recipient) {

        return this.mailService.findSingleByCriteria(" where e.recipients = ?1 and e.subject = ?2", recipient, subject);

    }

    protected Mail getEmailBySubjectLike(final String subject, final String recipient) {

        return this.mailService.findSingleByCriteria(" where e.recipients = ?1 and lower(e.subject) like ?2", recipient, HQLUtils.criteriaIlikeAnywhere(subject));

    }



}
