package project.web.job;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.logging.log4j.LogManager;

import batch.status.Job;
import batch.status.JobFile;
import batch.status.JobFileStatus;
import batch.status.JobStatus;
import common.db.JdbcSource;
import core.config.Env;
import core.config.Factory;
import online.context.check.InputCheck;
import online.struts.action.RestAction;
import online.struts.action.UniForm;
import project.check.attribute.NumeralCheck;
import project.web.DownloadAction;
import project.web.InstanceFactory;

/**
 * ジョブファイルダウンロード
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
interface DownloadJobFile extends RestAction, DownloadAction {

	/** ジョブ連番 */
	String TAG_JOB_SEQ = "JobSeq";
	/** バッチ連番 */
	String TAG_DTL_SEQ = "BatSeq";
	/** ファイル連番 */
	String TAG_FILE_SEQ = "FileSeq";

	/**
	 * ダウンロード処理
	 *
	 * @param uf 汎用フォーオム
	 * @param response HttpServletResponseオブジェクト
	 * @param request HttpServletRequestオブジェクト
	 * @return 処理結果
	 */
	default String get(final UniForm uf,
			final HttpServletResponse response, final HttpServletRequest request) {

		final var ic = InstanceFactory.create(InputCheck.class, uf);
		ic.add(TAG_JOB_SEQ, new NumeralCheck());
		ic.add(TAG_DTL_SEQ, new NumeralCheck());
		ic.add(TAG_FILE_SEQ, new NumeralCheck());
		ic.populate();

		try {
			// ジョブ情報取得
			final var job = getJobInfo(uf.getNumber(TAG_JOB_SEQ));
			// ファイル情報取得
			final var finfo = getFileInfo(uf.getNumber(TAG_JOB_SEQ),
					uf.getNumber(TAG_DTL_SEQ), uf.getNumber(TAG_FILE_SEQ));
			if (job == null || finfo == null || !canDownload(uf, job)) {
				if (!response.isCommitted()) {
					response.sendError(HttpServletResponse.SC_NOT_FOUND);
					response.flushBuffer();
				}
				return null;
			}

			// ダウンロード名作成
			setHttpHeader(finfo.getFileName(), finfo.getDownloadName(), request, response);

			response.setContentLength(Long.valueOf(finfo.getFileSize()).intValue());

			// ダウンロード
			fileDownload(job, finfo, request, response);

		} catch (final IOException ex) {
			LogManager.getLogger().info(ex.getMessage());
		}

		return null;
	}

	/**
	 * ファイルダウンロード判断
	 *
	 * @param model 汎用モデル
	 * @param job ジョブ情報
	 * @return ダウンロード可能の場合 true を返す。
	 */
	boolean canDownload(UniForm model, Job job);

	/**
	 * ファイルダウンロード処理
	 *
	 * @param job ジョブ情報
	 * @param finfo ダウンロードファイル情報
	 * @param request HttpServletRequestオブジェクト
	 * @param response HttpServletResponseオブジェクト
	 */
	void fileDownload(Job job, JobFile finfo,
			HttpServletRequest request, HttpServletResponse response);

	/**
	 * ジョブ情報取得
	 *
	 * @param jobseq ジョブ連番
	 * @return ジョブ情報
	 */
	static Job getJobInfo(final Number jobseq) {
		if (jobseq != null) {
			try (var conn = JdbcSource.getConnection()) {
				final var js = Factory.create(JobStatus.class);
				return js.getJob(conn, jobseq.longValue());
			}
		}
		return null;
	}

	/**
	 * ファイル取得
	 *
	 * @param jobseq ジョブ連番
	 * @param dtlseq ジョブ詳細連番
	 * @param fileseq ファイル連番
	 * @return ファイル情報
	 */
	static JobFile getFileInfo(
			final Number jobseq, final Number dtlseq, final Number fileseq) {
		if (jobseq == null) {
			return null;
		}

		// 指定無し時先頭
		var dseq = Env.getEnv("Download.DefaultDtlSeq", 1);
		if (dtlseq != null) {
			dseq = dtlseq.intValue();
		}
		// 指定無し時先頭
		var fseq = Env.getEnv("Download.DefaultFileSeq", 1);
		if (fileseq != null) {
			fseq = fileseq.intValue();
		}

		final var jfs = Factory.create(JobFileStatus.class);

		try (var conn = JdbcSource.getConnection()) {
			return jfs.countUpDownload(conn, jobseq.longValue(), dseq, fseq);
		}
	}
}
