package com.pmease.quickbuild.plugin.artifact;

import java.io.File;
import java.util.Date;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.pmease.quickbuild.CacheManager;
import com.pmease.quickbuild.Context;
import com.pmease.quickbuild.ScriptEngine;
import com.pmease.quickbuild.entitymanager.ConfigurationManager;
import com.pmease.quickbuild.extensionpoint.MaintenanceTask;
import com.pmease.quickbuild.model.Build;
import com.pmease.quickbuild.model.Configuration;
import com.pmease.quickbuild.persistence.SessionManager;
import com.pmease.quickbuild.setting.configuration.artifactcleanup.ArtifactCleanupStrategy;
import com.pmease.quickbuild.setting.configuration.artifactcleanup.ReserveArtifactsByBuilds;
import com.pmease.quickbuild.setting.configuration.artifactstorage.ArtifactStorage;
import com.pmease.quickbuild.util.FileUtils;

public class ArtifactCleanupTask implements MaintenanceTask {

	private static final Logger logger = LoggerFactory.getLogger(ArtifactCleanupTask.class);
	
	@SuppressWarnings("unchecked")
	public void execute() {
		for (Long configurationId: CacheManager.instance.getConfigurations().keySet()) {
			Configuration configuration = ConfigurationManager.instance.load(configurationId);
			Context.push(configuration);
			try {
				ArtifactCleanupStrategy strategy = configuration.findArtifactCleanupStrategy();
				strategy = (ArtifactCleanupStrategy) ScriptEngine.instance.installInterpolator(strategy);
				
				if (strategy.getCount() != 0) {
					logger.info("Cleaning up artifacts for configuration '{}'...", configuration.getPathName());
					File configurationArtifactsDir = new File(configuration.getPublishDir(), Build.ARTIFACT_DIR);
					File lastCleanupBuildFile = new File(configurationArtifactsDir, "last_cleanup_build");
					long lastCleanupId = 0;
					if (lastCleanupBuildFile.exists()) {
						try {
							lastCleanupId = Long.parseLong(FileUtils.readFileAsString(lastCleanupBuildFile));

							Build latestBuild = CacheManager.instance.getLatestBuild(configuration.getId());
							if (latestBuild != null && latestBuild.getId() < lastCleanupId)
								lastCleanupId = 0;
							
						} catch (Exception e) {
							logger.warn("Error reading last cleanup file, will use 0 as last cleanup build id.", e);
						}
					}
					
					ArtifactStorage artifactStorage = configuration.findArtifactStorage();
					
					if (strategy instanceof ReserveArtifactsByBuilds) {
						List<Build> builds;
						try {
							Session session = SessionManager.openSession();
							Query query = session.createQuery("from Build where configuration=:configuration " +
									"and id>:lastCleanupId order by id");
							query.setParameter("configuration", configuration);
							query.setParameter("lastCleanupId", lastCleanupId);
							builds = query.list();
						} finally {
							SessionManager.closeSession();
						}
						int size = builds.size();
						int index = 0;
						for (Build build: builds) {
							if (index < size - strategy.getCount()) {
								Context.getLogger().info("Removing artifacts of build '{}'...", build.getVersion());
								artifactStorage.cleanupArtifacts(build, Build.ARTIFACT_DIR);
								lastCleanupId = build.getId();
							}
							index++;
						}
					} else {
						List<Build> builds;
						try {
							Session session = SessionManager.openSession();
					        Query query = session.createQuery("from Build where configuration=:configuration " +
					        		"and beginDate<:date and id>:lastCleanupId order by id");
					        query.setParameter("configuration", configuration);
							long reserveMillis = 24L * 3600 * 1000 * strategy.getCount();
					        query.setParameter("date", new Date(System.currentTimeMillis()- reserveMillis));
							query.setParameter("lastCleanupId", lastCleanupId);
							builds = query.list();
						} finally {
							SessionManager.closeSession();
						}
		
						for (Build build: builds) {
							Context.getLogger().info("Removing artifacts of build '{}'...", build.getVersion());
							artifactStorage.cleanupArtifacts(build, Build.ARTIFACT_DIR);
							lastCleanupId = build.getId();
						}
						
					}
					FileUtils.writeFile(lastCleanupBuildFile, String.valueOf(lastCleanupId));
				}
				Thread.yield();
			} catch (Exception e) {
				logger.error("Error cleaning up artifacts of configuration '" + configuration.getPathName() + "'.", e);
			} finally {
				Context.pop();
			}
		}
	}

}
