package jp.co.y_net.amm.service;

import java.util.Map;
import java.util.TreeMap;

import jp.co.y_net.amm.common.AppLogger;
import jp.co.y_net.amm.common.AppUtils;
import jp.co.y_net.amm.common.CalcHash;
import jp.co.y_net.amm.common.ResourceReader;
import jp.co.y_net.amm.dao.AppDef;
import jp.co.y_net.amm.dao.Org;
import jp.co.y_net.amm.dao.OrgDao;
import jp.co.y_net.amm.dao.Usr;
import jp.co.y_net.amm.dao.UsrDao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component("logincheck")
public class Logincheck {

    public static Map<Integer, String> errorMemo;
    public static Map<Integer, String> errorMessage;
    static {
        /* システム内で使用する補足メッセージ */
        errorMemo = new TreeMap<Integer, String>();
        errorMemo.put(0, "エラーなし");
        errorMemo.put(1, "ログインIDに該当するデータなし");
        errorMemo.put(2, "退会しているユーザー（パスワードは正しい）");
        //        errorMemo.put(3, "仮登録のユーザーです");
        errorMemo.put(4, "ログイン停止のユーザー（パスワードは正しい）");
        errorMemo.put(5, "現在、使用期間外（パスワードは正しい）");
        errorMemo.put(10, "ログインIDかパスワードが正しくない");
        errorMemo.put(999, "その他のエラー");

        /* 利用者へ表示するメッセージ */
        errorMessage = new TreeMap<Integer, String>();
        errorMessage.put(0, "");
        errorMessage.put(1, "アカウントかパスワードが正しくありません。"); // アカウント自体がないことはセキュリティ上、明らかにしない
        errorMessage.put(2, "退会しています。ログインできません。");
        errorMessage.put(4, "ログイン停止中です。ログインできません。");
        errorMessage.put(5, "使用期間外です。ログインできません。");
        errorMessage.put(10, "アカウントかパスワードが正しくありません。");
        errorMessage.put(999, "ログインできません。");
    }

    @Autowired(required = true)
    @Qualifier("usrDao")
    private UsrDao usrDao;

    @Autowired(required = true)
    @Qualifier("orgDao")
    private OrgDao orgDao;

    public LogincheckResult executeFromAmm(String loginidB, String cresE, String challengeA) {
        return execute(loginidB, cresE, challengeA, false);
    }

    public LogincheckResult executeFromApi(String loginidB, String cresE, String challengeA) {
        /* 2016/02/22 戻り値にuseridを追加 */
        //return execute(loginidB, cresE, challengeA, true);
        return execute(loginidB, cresE, challengeA, true); // 認証実施

    }

    private LogincheckResult execute(String loginidB, String cresE, String challengeA, boolean チャレンジレスポンスの保存を行う) {

        LogincheckResult logincheckResult = new LogincheckResult();

        Usr usr = usrDao.getByLoginid(loginidB);
        if (usr == null) {

            logincheckResult.errorCode = 1;
            return logincheckResult; // ログインIDが登録されていません
        }

        String チャレンジレスポンス正解値 = CalcHash.challengeResponse(usr.getPwhash(), challengeA);

        if (cresE.equals(チャレンジレスポンス正解値)) {

            if (usr.getStatus() == Usr.STATUS_退会) {

                logincheckResult.errorCode = 2;
                return logincheckResult; // 退会
            }
            //            if(usr.getStatus() == Usr.STATUS_仮登録) { 仮登録はパスワードを持っていないため、このブロックは取り下げ
            //                return 3; // 仮登録
            //            }
            if (usr.isログイン停止()) {
                logincheckResult.errorCode = 4;
                return logincheckResult;
            }
            Integer orgId = usr.getOrgid();
            Org org = orgDao.getByOrgid(orgId);
            if (org == null) {
                AppLogger.error(usr.getLoginid() + "に組織情報が紐づいていません。");
                logincheckResult.errorCode = 999;
                return logincheckResult;
            }
            if (org != null && org.is利用可能期間内() == false) {
                logincheckResult.errorCode = 5;
                return logincheckResult;
            }

            /* 認証成功 */

            /* チャレンジレスポンスの有効期限を算出 */
            Long cresdate = -1L;
            int offset = ResourceReader.getIntegerQuick("cresdate");
            cresdate = AppUtils.createNowLong(offset);

            /* データアクセス アカウント認証結果登録 */
            usr.setLastlogindate(AppUtils.createNowLong()); // 最終ログイン日付
            usr.setLastlogintrydate(AppUtils.createNowLong()); // 最終ログイン試行日付
            usr.setLoginerrorcount(0); // ログイン失敗回数

            if (チャレンジレスポンスの保存を行う) {
                usr.setCres(cresE); // チャレンジレスポンス
                usr.setCresdate(cresdate); // チャレンジレスポンス有効期限    
            }

            /* 2016/03/30 ログアウト要求日時をクリアする */
            usr.setRequestlogoutdate(-1L);
            
            usrDao.update(usr, AppDef.USERID_NONE); // 【更新処理】

            logincheckResult.errorCode = 0;
            logincheckResult.usrid = usr.getUsrid();
            return logincheckResult;

        } else {
            /* 認証失敗 */

            /* データアクセス アカウント認証結果登録 */
            usr.setLastlogintrydate(AppUtils.createNowLong()); // 最終ログイン試行日付
            if (usr.getLoginerrorcount() == null) {
                usr.setLoginerrorcount(1); // ログイン失敗回数                
            } else {
                usr.setLoginerrorcount(usr.getLoginerrorcount() + 1); // ログイン失敗回数
            }
            usr.setCres(null); // チャレンジレスポンス をクリア
            usr.setCresdate(-1L); // チャレンジレスポンス有効期限 を無効化

            /* 2016/03/30 ログアウト要求日時をクリアする */
            usr.setRequestlogoutdate(-1L);
            
            usrDao.update(usr, AppDef.USERID_NONE); // 【更新処理】

            logincheckResult.errorCode = 10;

            return logincheckResult;
        }
    }

    public class LogincheckResult {
        public Integer errorCode;
        public Integer usrid; /* 2016/02/22 戻り値にuseridを追加 */
    }
}
