package ru.yandex.wmtools.common.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.transaction.TransactionStatus;

import ru.yandex.common.framework.pager.Pager;
import ru.yandex.wmtools.common.data.HistoryActionEnum;
import ru.yandex.wmtools.common.data.HistoryObjectTypeEnum;
import ru.yandex.wmtools.common.data.info.SupportUserInfo;
import ru.yandex.wmtools.common.data.info.WMUserInfo;
import ru.yandex.wmtools.common.data.partition.IPartition;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.error.UserException;
import ru.yandex.wmtools.common.error.UserProblem;
import ru.yandex.wmtools.common.util.ServiceTransactionCallback;
import ru.yandex.wmtools.common.util.ServiceTransactionCallbackWithoutResult;

/**
 * Created by IntelliJ IDEA.
 * User: senin
 * Date: 20.03.2007
 * Time: 10:09:24
 */
abstract public class SupportUsersService extends AbstractDbService {
    private UserService userService;

    protected UserService getUserService() {
        return userService;
    }
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    private ISupportService supportService;
    public void setSupportService(ISupportService supportService) {
        this.supportService = supportService;
    }

    private IUserInfoService userInfoService;
    public void setUserInfoService(IUserInfoService userInfoService) {
        this.userInfoService = userInfoService;
    }

    private IViewerUserIdService viewerUserIdService;
    public void setViewerUserIdService(IViewerUserIdService viewerUserIdService) {
        this.viewerUserIdService = viewerUserIdService;
    }

    private HistoryService historyService;
    public void setHistoryService(HistoryService historyService) {
        this.historyService = historyService;
    }

    public List<WMUserInfo> getUserInfoListForSupportUsers(Pager pager) throws UserException, InternalException {
        Collection<Long> userIds = getSupportUsersList(pager);

        List<WMUserInfo> result = new ArrayList<WMUserInfo>();
        for (long userId : userIds) {
            result.add(userInfoService.getUserInfo(userId));
        }
        return result;
    }

    public void addSupportUser(final Long realUserId, final long supportId) throws UserException, InternalException {
        if (isSupportUserMustBeInUsersList()) {
            viewerUserIdService.assureUserIsInUsersList(supportId);
        }

        if (supportService.isSupportUser(supportId)) {
            throw new UserException(UserProblem.USER_IS_ALREADY_IN_LIST, "User " + supportId + " is already in list of support!");
        }

        getServiceTransactionTemplate(addSupportUserPartition(supportId)).executeInService(new ServiceTransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) throws InternalException {
                if (addSupportUserQuery(supportId) == 0) {
                    throw new RuntimeException("No rows updated while adding support user into DB.");
                }
                historyService.addEvents(realUserId, realUserId, HistoryActionEnum.ADD, HistoryObjectTypeEnum.SUPPORT_USER, supportId);
            }
        });
    }

    public int removeSupportUsers(final Long realUserId, final Long... supportIds) throws UserException, InternalException {
        String inParamsStr = "";
        final Object[] queryParams = new Object[supportIds.length];
        for (int i = 0; i < supportIds.length; i++) {
            if (i != 0) {
                inParamsStr += ", ";
            }
            inParamsStr += "?";
            queryParams[i] = supportIds[i];
        }
        final String inParamsFinalStr = inParamsStr;

        return getServiceTransactionTemplate(removeSupportUsersPartition(supportIds)).executeInService(new ServiceTransactionCallback<Integer>() {
            @Override
            public Integer doInTransaction(TransactionStatus transactionStatus) throws InternalException {
                int res = removeSupportUsersQuery(inParamsFinalStr, queryParams);
                historyService.addEvents(realUserId, realUserId, HistoryActionEnum.REMOVE, HistoryObjectTypeEnum.SUPPORT_USER, supportIds);
                return res;
            }
        });
    }

    abstract public List<SupportUserInfo> getSupportsList(Pager pager) throws InternalException;

    abstract protected int removeSupportUsersQuery(final String inParamsStr, Object[] queryParams) throws InternalException;

    abstract protected List<Long> getSupportUsersList(Pager pager) throws InternalException;

    abstract protected int addSupportUserQuery(long supportId) throws InternalException;

    abstract protected IPartition addSupportUserPartition(long supportId);

    abstract protected IPartition removeSupportUsersPartition(Long ... supportIds);

    abstract protected boolean isSupportUserMustBeInUsersList();
}
