package project.web.auth;

import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;

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

import core.config.Factory;
import online.context.check.InputCheck;
import online.context.session.SessionScope;
import online.context.session.SessionUser;
import online.struts.action.UniForm;
import online.struts.mapping.RequestMapping;
import project.check.range.LengthRangeCheck;
import project.master.MsgUtil;
import project.svc.auth.Authentication;
import project.svc.auth.SessionInfo.LogoffType;
import project.web.InstanceFactory;


/**
 * ログオンアクション
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public final class LogonActionImpl implements LogonAction {

	/** タグ ユーザID */
	private static final String TAG_UID = "Uid";
	/** ユーザー情報　パスワード*/
	private static final String TAG_PWD = "Pwd";

	/** ユーザID、パスワードエラーメッセージ */
	private static final String MSGID_NOT_USER = "ZZ000000001";

	/**
	 * ログオン主処理
	 *
	 * @param mapping ActionMappingオブジェクト
	 * @param uf 汎用フォーム
	 * @param request HttpServletRequestオブジェクト
	 * @param response HttpServletResponseオブジェクト
	 * @return 処理結果
	 */
	@Override
	public String perform(final RequestMapping mapping, final UniForm uf,
			final HttpServletRequest request, final HttpServletResponse response) {

		if (uf.getSessionUser() != null) {
			return "LOGONED";
		}

		final var ic = InstanceFactory.create(InputCheck.class, uf);
		ic.add(TAG_UID, new LengthRangeCheck(0, 64));
		ic.add(TAG_PWD, new LengthRangeCheck(0, 64));
		ic.populate();

		// 初期表示
		if (!uf.containsKey(TAG_UID) || !uf.containsKey(TAG_PWD)) {
			return ID_VIEW;
		}

		// ログオン処理
		final var auth = Factory.create(Authentication.class);
		if (!auth.logon(uf.getString(TAG_UID), uf.getString(TAG_PWD))) {
			MsgUtil.putTopMessage(uf, MSGID_NOT_USER);
			MsgUtil.putMessage(uf, TAG_UID, MSGID_NOT_USER);
			MsgUtil.putMessage(uf, TAG_PWD, MSGID_NOT_USER);
			return ID_VIEW;
		}

		// セション取得
		final var map = invalidateSession(request.getSession(false));
		final var session = request.getSession();
		map.forEach(session::setAttribute);

		// ログオン情報設定
		final var li = auth.updateStatus(uf.getString(TAG_UID),
				uf.getPresent(), session.getId(), session.getMaxInactiveInterval());

		// 強制ログアウト時
		if (LogoffType.TYPE_FORCE.equals(li.getLogoffType())) {
			// 別セションログオンメッセージ設定
			MsgUtil.putTopMessage(uf, "ZZ000000004");
		}

		// セションに情報設定
		// モデル作成
		final var m = new SessionUser(uf.getString(TAG_UID));
		// セション情報保存
		SessionScope.setSessionUser(request, m);
		uf.setSessionUser(m);

		// ログオン情報設定
		setLogonInfoToSession(li, uf, session);

		return ID_OK;
	}

	/**
	 * セション無効化
	 * @param session HttpSession
	 * @return セション保存オブジェクト
	 */
	private Map<String, Object> invalidateSession(final HttpSession session) {
		if (session != null) {
			final Map<String, Object> map = Collections.list(session.getAttributeNames()).stream().
							collect(Collectors.toMap(v -> v, session::getAttribute));
			session.invalidate();
			return map;
		}
		return Collections.emptyMap();
	}

}
