package jp.agentec.abook.abv.bl.logic;

import org.json.adf.JSONObject;

import java.util.Date;

import jp.agentec.abook.abv.bl.acms.client.AcmsClient;
import jp.agentec.abook.abv.bl.acms.client.json.LockReportJSON;
import jp.agentec.abook.abv.bl.acms.client.parameters.LockReportParameters;
import jp.agentec.abook.abv.bl.data.dao.AbstractDao;
import jp.agentec.abook.abv.bl.data.dao.TaskReportDao;
import jp.agentec.abook.abv.bl.dto.MemberInfoDto;
import jp.agentec.adf.util.DateTimeFormat;
import jp.agentec.adf.util.DateTimeUtil;

import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
import static java.net.HttpURLConnection.HTTP_OK;
import static jp.agentec.abook.abv.bl.acms.client.json.OperationDataJSON.ReportLockTime;
import static jp.agentec.abook.abv.bl.acms.client.json.OperationDataJSON.ReportLockUserId;
import static jp.agentec.abook.abv.bl.acms.client.json.OperationDataJSON.ReportLockUserName;
import static jp.agentec.abook.abv.bl.acms.client.json.OperationDataJSON.ReportStartDate;
import static jp.agentec.abook.abv.bl.acms.client.json.OperationDataJSON.ReportStatus;
import static jp.agentec.abook.abv.bl.acms.client.json.OperationDataJSON.TaskReportId;

public class LockReportLogic extends AbstractLogic {

    public static LockReportLogic newInstance() {
        return new LockReportLogic();
    }

    public Result lock(String taskKey, Long taskReportId, Date reportStartDate) {
        Result r = sendLockReport(taskKey, taskReportId, reportStartDate);
        if (r.result == 0) {
            updateLocalDB(taskKey, taskReportId, reportStartDate, r.getExtParam());
        }
        return r;
    }

    private Result sendLockReport(
            String taskKey,
            Long taskReportId,
            Date reportStartDate
    ) {
        AcmsClient client = AcmsClient.getInstance(cache.getUrlPath(), networkAdapter);
        MemberInfoDto member = cache.getMemberInfo();
        LockReportParameters param = new LockReportParameters(
                member.sid,
                taskKey,
                taskReportId,
                reportStartDate,
                member.loginId,
                member.memberName
        );

        if (!networkAdapter.isNetworkConnected()) {
            // オフラインだったら、ロック成功扱い
            return Result.offLine(taskReportId, reportStartDate);
        }

        try {
            LockReportJSON reportJSON = client.sendLockReport(param);
            return Result.succsess(reportJSON, taskReportId, reportStartDate);
        } catch (Throwable e) {
            return Result.failure(e, taskReportId, reportStartDate);
        }
    }

    private void updateLocalDB(
            String taskKey,
            Long taskReportId,
            Date reportStartDate,
            ExtParam extParam
    ) {
        TaskReportDao dao = AbstractDao.getDao(TaskReportDao.class);
        dao.updateReportLock(
                taskKey,
                taskReportId,
                reportStartDate,
                extParam.reportStatus,
                extParam.reportLockUserId,
                extParam.reportLockUserName,
                extParam.reportLockTime
        );
    }

    // コールバック用のパラメータ
    public static class Result {
        public static final int BAD_STATUS = 999;
        int result;
        String message;
        ExtParam extParam;

        static Result succsess(LockReportJSON reportJSON, Long taskReportId, Date reportStartDate) {
            // 成功したとき
            Result result = new Result();
            if (reportJSON.httpStatus == HTTP_OK) {
                result.result = 0;
                result.message = "";
                result.extParam = new ExtParam(
                        reportJSON.getReportStatus(),
                        reportJSON.getReportLockUserId(),
                        reportJSON.getReportLockUserName(),
                        reportJSON.getReportLockTime(),
                        taskReportId,
                        reportStartDate
                );
            } else if (reportJSON.httpStatus == HTTP_NOT_FOUND) {
                result.result = 0;
                result.message = "";
                result.extParam = new ExtParam(
                        0,
                        null,
                        null,
                        null,
                        taskReportId,
                        reportStartDate
                );
            } else {
                result.result = 1;
                result.message = "";
                result.extParam = new ExtParam(
                        0,
                        null,
                        null,
                        null,
                        taskReportId,
                        reportStartDate
                );
            }
            return result;
        }

        @SuppressWarnings("magic_number")
        static Result failure(Throwable e, Long taskReportId, Date reportStartDate) {
            // 例外がでたとき
            Result result = new Result();
            result.result = 1;
            result.message = e.getLocalizedMessage();
            result.extParam = new ExtParam(
                    BAD_STATUS,
                    null,
                    null,
                    null,
                    taskReportId,
                    reportStartDate
            );
            return result;
        }

        static Result offLine(Long taskReportId, Date reportStartDate) {
            // オフラインは成功扱い
            Result result = new Result();
            result.result = 0;
            result.message = "";
            result.extParam = new ExtParam(
                    3,
                    null,
                    null,
                    null,
                    taskReportId,
                    reportStartDate
            );
            return result;
        }

        public int getResult() {
            return result;
        }

        public String getMessage() {
            return message;
        }

        public ExtParam getExtParam() {
            return extParam;
        }
    }

    static public class ExtParam {
        int reportStatus;
        String reportLockUserId;
        String reportLockUserName;
        Date reportLockTime;
        Long taskReportId;
        Date reportStartDate;

        ExtParam(
                int reportStatus,
                String reportLockUserId,
                String reportLockUserName,
                Date reportLockTime,
                Long taskReportId,
                Date reportStartDate
        ) {
            this.reportStatus = reportStatus;
            this.reportLockUserId = reportLockUserId;
            this.reportLockUserName = reportLockUserName;
            this.reportLockTime = reportLockTime;
            this.taskReportId = taskReportId;
            this.reportStartDate = reportStartDate;
        }

        @SuppressWarnings("unused")
        public int getReportStatus() {
            return reportStatus;
        }

        @SuppressWarnings("unused")
        public String getReportLockUserId() {
            return reportLockUserId;
        }

        @SuppressWarnings("unused")
        public String getReportLockUserName() {
            return reportLockUserName;
        }

        @SuppressWarnings("unused")
        public Date getReportLockTime() {
            return reportLockTime;
        }

        @SuppressWarnings("unused")
        public String json() {
            JSONObject extParam = new JSONObject();
            extParam.put(ReportStatus, String.valueOf(reportStatus));
            extParam.put(ReportLockUserId, reportLockUserId);
            extParam.put(ReportLockUserName, reportLockUserName);
            extParam.put(ReportLockTime, DateTimeUtil.toStringInTimeZone(reportLockTime, DateTimeFormat.yyyyMMddHHmmss_hyphen, "UTC"));

            if (taskReportId != null && taskReportId != 0) {
                extParam.put(TaskReportId, taskReportId);
            }
            if (reportStartDate != null) {
                extParam.put(ReportStartDate, DateTimeUtil.toStringInTimeZone(reportStartDate, DateTimeFormat.yyyyMMddHHmmss_hyphen, "UTC"));
            }
            return extParam.toString();
        }
    }
}
