package ru.yandex.qe.dispenser.ws.admin;

import java.net.URISyntaxException;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

import com.google.common.base.Stopwatch;
import io.swagger.annotations.Api;
import io.swagger.annotations.Authorization;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import ru.yandex.qe.dispenser.application.startup.InitialState;
import ru.yandex.qe.dispenser.domain.dao.base_resources.BaseResourceCache;
import ru.yandex.qe.dispenser.domain.dao.base_resources.BaseResourceChangeDao;
import ru.yandex.qe.dispenser.domain.dao.base_resources.BaseResourceDao;
import ru.yandex.qe.dispenser.domain.dao.base_resources.BaseResourceLimitDao;
import ru.yandex.qe.dispenser.domain.dao.base_resources.BaseResourceMappingDao;
import ru.yandex.qe.dispenser.domain.dao.base_resources.BaseResourceTypeCache;
import ru.yandex.qe.dispenser.domain.dao.base_resources.BaseResourceTypeDao;
import ru.yandex.qe.dispenser.domain.dao.base_resources.PerCampaignLimitsCache;
import ru.yandex.qe.dispenser.domain.dao.base_resources.PerCampaignMappingsCache;
import ru.yandex.qe.dispenser.domain.dao.bot.bigorder.BigOrderCache;
import ru.yandex.qe.dispenser.domain.dao.bot.remainder.ServersRemainderDao;
import ru.yandex.qe.dispenser.domain.dao.bot.settings.BotCampaignGroupDao;
import ru.yandex.qe.dispenser.domain.dao.campaign.CampaignCache;
import ru.yandex.qe.dispenser.domain.dao.campaign.CampaignDao;
import ru.yandex.qe.dispenser.domain.dao.campaign.CampaignOwningCostCache;
import ru.yandex.qe.dispenser.domain.dao.campaign.CampaignOwningCostDao;
import ru.yandex.qe.dispenser.domain.dao.campaign.CampaignResourceDao;
import ru.yandex.qe.dispenser.domain.dao.delivery.DeliveryDao;
import ru.yandex.qe.dispenser.domain.dao.entity.EntityDao;
import ru.yandex.qe.dispenser.domain.dao.entity.spec.EntitySpecDao;
import ru.yandex.qe.dispenser.domain.dao.group.GroupDao;
import ru.yandex.qe.dispenser.domain.dao.history.quota.QuotaHistoryDao;
import ru.yandex.qe.dispenser.domain.dao.history.request.QuotaChangeRequestHistoryDao;
import ru.yandex.qe.dispenser.domain.dao.person.PersonDao;
import ru.yandex.qe.dispenser.domain.dao.person.PersonGroupMembershipDao;
import ru.yandex.qe.dispenser.domain.dao.person.StaffCache;
import ru.yandex.qe.dispenser.domain.dao.project.ProjectDao;
import ru.yandex.qe.dispenser.domain.dao.project.role.ProjectRoleCache;
import ru.yandex.qe.dispenser.domain.dao.project.role.ProjectRoleCacheImpl;
import ru.yandex.qe.dispenser.domain.dao.project.role.ProjectRoleDao;
import ru.yandex.qe.dispenser.domain.dao.property.PropertyDao;
import ru.yandex.qe.dispenser.domain.dao.quota.QuotaDao;
import ru.yandex.qe.dispenser.domain.dao.quota.request.QuotaChangeRequestDao;
import ru.yandex.qe.dispenser.domain.dao.quota.spec.QuotaSpecDao;
import ru.yandex.qe.dispenser.domain.dao.resource.ResourceDao;
import ru.yandex.qe.dispenser.domain.dao.resource.group.ResourceGroupDao;
import ru.yandex.qe.dispenser.domain.dao.resource.segmentation.ResourceSegmentationDao;
import ru.yandex.qe.dispenser.domain.dao.resources_model.ResourcesModelMappingDao;
import ru.yandex.qe.dispenser.domain.dao.segment.SegmentDao;
import ru.yandex.qe.dispenser.domain.dao.segmentation.SegmentationDao;
import ru.yandex.qe.dispenser.domain.dao.service.ServiceDao;
import ru.yandex.qe.dispenser.domain.hierarchy.PermissionsCache;
import ru.yandex.qe.dispenser.domain.request.RequestManager;
import ru.yandex.qe.dispenser.swagger.DispenserSecurityDefinition;
import ru.yandex.qe.dispenser.swagger.SwaggerTags;
import ru.yandex.qe.dispenser.ws.ServiceBase;


@Service("init-state")
@Path("/admin/reinitialize")
@Api(tags = {SwaggerTags.DISPENSER_API}, authorizations = {@Authorization(value = DispenserSecurityDefinition.AUTHORIZATION_SCHEME_NAME)})
public class ReinitializeStateService extends ServiceBase {
    private static final Logger LOG = LoggerFactory.getLogger(ReinitializeStateService.class);

    @Nullable
    @Autowired(required = false)
    private InitialState startupInitialState;

    @Autowired
    protected PersonDao personDao;

    @Autowired
    protected GroupDao groupDao;

    @Autowired
    protected ProjectDao projectDao;

    @Autowired
    protected ServiceDao serviceDao;

    @Autowired
    protected ResourceDao resourceDao;

    @Autowired
    protected QuotaSpecDao quotaSpecDao;

    @Autowired
    protected QuotaDao quotaDao;

    @Autowired
    protected EntitySpecDao entitySpecDao;

    @Autowired
    protected EntityDao entityDao;

    @Autowired
    protected SegmentationDao segmentationDao;

    @Autowired
    protected SegmentDao segmentDao;

    @Autowired
    protected ResourceSegmentationDao resourceSegmentationDao;

    @Autowired
    protected ResourceGroupDao resourceGroupDao;

    @Autowired
    protected QuotaChangeRequestDao quotaChangeRequestDao;

    @Autowired
    protected PropertyDao propertyDao;

    @Autowired
    protected CampaignDao campaignDao;

    @Autowired
    protected CampaignResourceDao campaignResourceDao;


    @Autowired
    private RequestManager requestManager;

    @Autowired
    private StaffCache staffCache;

    @Autowired
    private PersonGroupMembershipDao groupMembershipDao;

    @Autowired
    private QuotaHistoryDao quotaHistoryDao;

    @Autowired
    private QuotaChangeRequestHistoryDao quotaChangeRequestHistoryDao;

    @Autowired
    private ProjectRoleDao projectRoleDao;

    @Autowired
    private ProjectRoleCache roleCache;

    @Autowired
    private BotCampaignGroupDao botCampaignGroupDao;

    @Autowired
    private ServersRemainderDao serversRemainderDao;

    @Autowired
    private ResourcesModelMappingDao resourcesModelMappingDao;

    @Autowired
    private BaseResourceDao baseResourceDao;

    @Autowired
    private BaseResourceTypeDao baseResourceTypeDao;

    @Autowired
    private BaseResourceMappingDao baseResourceMappingDao;

    @Autowired
    private BaseResourceLimitDao baseResourceLimitDao;

    @Autowired
    private BaseResourceChangeDao baseResourceChangeDao;

    @Autowired
    private BaseResourceCache baseResourceCache;

    @Autowired
    private BaseResourceTypeCache baseResourceTypeCache;

    @Autowired
    private CampaignCache campaignCache;

    @Autowired
    private BigOrderCache botBigOrderCache;

    @Autowired
    private PerCampaignMappingsCache perCampaignMappingsCache;

    @Autowired
    private PerCampaignLimitsCache perCampaignLimitsCache;

    @Autowired
    private CampaignOwningCostDao campaignOwningCostDao;

    @Autowired
    private CampaignOwningCostCache campaignOwningCostCache;

    @Autowired
    private DeliveryDao deliveryDao;

    @Autowired
    private PermissionsCache permissionsCache;

    @GET
    public Response reinitialize() throws URISyntaxException {
        if (startupInitialState == null) {
            return Response.notAcceptable(Collections.emptyList()).entity("Not Acceptable").build();
        }
        clear();
        startupInitialState.configureWithLogging();
        return Response.ok("OK").build();
    }

    private void clear() {
        LOG.info("Database clearing started");
        final Stopwatch stopwatch = Stopwatch.createStarted();
        requestManager.clear();
        entityDao.clear();
        entitySpecDao.clear();
        quotaDao.clear();
        quotaSpecDao.clear();
        resourceSegmentationDao.clear();
        resourceDao.clear();
        serviceDao.clear();
        projectDao.clear();
        groupDao.clear();
        personDao.clear();
        segmentDao.clear();
        segmentationDao.clear();
        resourceGroupDao.clear();
        quotaChangeRequestDao.clear();
        propertyDao.clear();
        campaignResourceDao.clear();
        campaignDao.clear();
        groupMembershipDao.clear();
        staffCache.clear();
        quotaHistoryDao.clear();
        quotaChangeRequestHistoryDao.clear();
        projectRoleDao.clear();
        botCampaignGroupDao.clear();
        serversRemainderDao.clear();
        resourcesModelMappingDao.clear();
        if (roleCache instanceof ProjectRoleCacheImpl) {
            ((ProjectRoleCacheImpl) roleCache).invalidate();
        }
        baseResourceChangeDao.clear();
        baseResourceLimitDao.clear();
        baseResourceMappingDao.clear();
        baseResourceDao.clear();
        baseResourceTypeDao.clear();
        baseResourceCache.clear();
        baseResourceTypeCache.clear();
        campaignCache.clear();
        botBigOrderCache.clear();
        perCampaignMappingsCache.clear();
        perCampaignLimitsCache.clear();
        campaignOwningCostDao.clear();
        campaignOwningCostCache.clear();
        deliveryDao.clear();
        permissionsCache.invalidateCaches();

        LOG.info("Database cleared in {} ms", stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }
}
