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

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import jp.agentec.abook.abv.bl.acms.client.AcmsClient;
import jp.agentec.abook.abv.bl.acms.client.json.OperationGroupMasterJSON;
import jp.agentec.abook.abv.bl.acms.client.parameters.AcmsParameters;
import jp.agentec.abook.abv.bl.acms.type.OperationSortingType;
import jp.agentec.abook.abv.bl.common.ABVEnvironment;
import jp.agentec.abook.abv.bl.common.exception.AcmsException;
import jp.agentec.abook.abv.bl.common.exception.NetworkDisconnectedException;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.bl.data.dao.AbstractDao;
import jp.agentec.abook.abv.bl.data.dao.OperationDao;
import jp.agentec.abook.abv.bl.data.dao.OperationGroupMasterDao;
import jp.agentec.abook.abv.bl.dto.OperationDto;
import jp.agentec.abook.abv.bl.dto.OperationGroupMasterDto;
import jp.agentec.abook.abv.bl.dto.comparator.OperationGroupMasterLevelComparator;

/**
 * Created by leej on 2019/06/26.
 */

public class OperationGroupMasterLogic extends AbstractLogic {
    private static final String TAG = "OperationGroupMasterLogic";

    private OperationGroupMasterDao mOperationGroupMasterDao = AbstractDao.getDao(OperationGroupMasterDao.class);
    private OperationDao mOperationDao = AbstractDao.getDao(OperationDao.class);

    /**
     * 作業種別・作業種別に紐づいた作業IDを取得して
     * DBに登録する
     */
    public List<OperationGroupMasterDto> fetchOperationGroupMasterOnly() throws NetworkDisconnectedException, AcmsException {
        return getOperationGroupMasterServerData();
    }

    public void applyFetchedOperationGroupMaster(List<OperationGroupMasterDto> serverOperationGroupMasterDtos) {
        try {
            if (serverOperationGroupMasterDtos == null) {
                return;
            }
            // ローカルDBに存在する作業種別情報をDto配列でセット
            List<OperationGroupMasterDto> localOperationGroupMasterDtos = mOperationGroupMasterDao.getAllOperationGroupMaster();
            List<Integer> localOperationGroupMasterIds = new ArrayList<Integer>();
            boolean updateFlg = false;
            for (OperationGroupMasterDto serverOperationGroupMasterDto : serverOperationGroupMasterDtos) {
                // DB登録フラグ
                boolean insertFlg = true;
                for (OperationGroupMasterDto localOperationGroupMasterDto : localOperationGroupMasterDtos) {
                    // サーバーで取得したIDでローカルに存在するか比較して、更新・登録を判定
                    if (serverOperationGroupMasterDto.operationGroupMasterId == localOperationGroupMasterDto.operationGroupMasterId) {
                        // DB更新処理(作業種別の親階層が変更されたか、作業種別名が変更されたときのみ）
                        if (serverOperationGroupMasterDto.parentOperationGroupMasterId != localOperationGroupMasterDto.parentOperationGroupMasterId || !serverOperationGroupMasterDto.operationGroupMasterName.equals(localOperationGroupMasterDto.operationGroupMasterName)) {
                            Logger.d(TAG, "[UPDATE] OperationGroupMaster operationGroupMasterId=" + serverOperationGroupMasterDto.operationGroupMasterId + "  operationGroupMasterName=" + serverOperationGroupMasterDto.operationGroupMasterName);
                            mOperationGroupMasterDao.updateOperationGroupMaster(serverOperationGroupMasterDto);
                            updateFlg = true;
                        }

                        // 更新処理が終わったら登録フラグをfalseにしてlocalOperationGroupMasterDtosから除外する
                        insertFlg = false;
                        localOperationGroupMasterDtos.remove(localOperationGroupMasterDto);
                        break;
                    }
                }

                // 更新されたら以下の処理は行わない
                if (insertFlg) {
                    Logger.d(TAG, "[INSERT] OperationGroupMaster operationGroupMasterId=" + serverOperationGroupMasterDto.operationGroupMasterId + "  operationGroupMasterName=" + serverOperationGroupMasterDto.operationGroupMasterName);
                    // DB登録処理
                    mOperationGroupMasterDao.insertOperationGroupMaster(serverOperationGroupMasterDto);
                }
            }

            // 作業種別関連テーブルの削除処理
            for (OperationGroupMasterDto deleteOperationGroupMasterDto : localOperationGroupMasterDtos) {
                updateFlg = true;
                mOperationGroupMasterDao.delete(deleteOperationGroupMasterDto);
            }

            // 作業種別のクリアフラグをセット
            ABVEnvironment.getInstance().setOperationGroupMasterClearFlg(updateFlg);
        } catch (Exception e) {
            Logger.e(e.getMessage());
        }
    }

    public void setOperationGroupMaster() throws NetworkDisconnectedException, AcmsException {
        applyFetchedOperationGroupMaster(fetchOperationGroupMasterOnly());
    }

    /**
     * API通信で取得した作業種別情報のリストを返す
     * @return
     * @throws NetworkDisconnectedException
     * @throws AcmsException
     */
    private List<OperationGroupMasterDto> getOperationGroupMasterServerData() throws NetworkDisconnectedException, AcmsException {
        AcmsParameters param = new AcmsParameters(cache.getMemberInfo().sid);
        OperationGroupMasterJSON json = AcmsClient.getInstance(cache.getUrlPath(), networkAdapter).getOperationGroupMaster(param);
        return json.operationGroupMasterList;
    }

    /**
     * 作業種別毎に作業数（子グループの作業も含む）を
     * operationCountMapにセットする
     * @param level
     * @param operationCountMap
     */
    public void getAllOperationCount(int level, Map<Integer, Integer> operationCountMap) {
        List<OperationGroupMasterDto> operationGroupMasterDtoList;
        operationGroupMasterDtoList = mOperationGroupMasterDao.getOperationGroupMasterListBylevel(level);

        // ルート階層の場合は以下の処理しない
        if (level > 0 && operationGroupMasterDtoList != null) {
            for (OperationGroupMasterDto operationGroupMasterDto : operationGroupMasterDtoList) {
                if (operationCountMap.containsKey(operationGroupMasterDto.operationGroupMasterId)) {
                    operationCountMap.put(operationGroupMasterDto.operationGroupMasterId, operationCountMap.get(operationGroupMasterDto.operationGroupMasterId) + operationGroupMasterDto.operationCount);
                } else {
                    operationCountMap.put(operationGroupMasterDto.operationGroupMasterId, operationGroupMasterDto.operationCount);
                }

                // 値が存在する場合
                if (operationCountMap.get(operationGroupMasterDto.operationGroupMasterId) > 0) {
                    if (operationCountMap.containsKey(operationGroupMasterDto.parentOperationGroupMasterId)) {
                        // 更新
                        operationCountMap.put(operationGroupMasterDto.parentOperationGroupMasterId, operationCountMap.get(operationGroupMasterDto.parentOperationGroupMasterId) + operationCountMap.get(operationGroupMasterDto.operationGroupMasterId));
                    } else {
                        // 新規
                        operationCountMap.put(operationGroupMasterDto.parentOperationGroupMasterId, operationCountMap.get(operationGroupMasterDto.operationGroupMasterId));
                    }
                }
            }
            level--;
            getAllOperationCount(level, operationCountMap); // 再帰呼び出し
        }
    }

    /**
     * 最後の階層レベル取得
     * @return
     */
    public Integer getLastGroupLevel() {
        return mOperationGroupMasterDao.getLastGroupLevel();
    }

    /**
     * 親の階層パスをリストでセット
     * @param operationGroupMasterId カテゴリID
     * @return
     */
    public List<OperationGroupMasterDto> getParentOperationGroupMasterForPath (Integer operationGroupMasterId) {
        List<OperationGroupMasterDto> operationGroupMasterDtoList = new ArrayList<OperationGroupMasterDto>();
        // 作業種別DTO取得
        OperationGroupMasterDto dto = mOperationGroupMasterDao.getOperationGroupMaster(operationGroupMasterId);
        operationGroupMasterDtoList.add(dto);

        int parentId = dto.parentOperationGroupMasterId;
        for (int i = 0; i < dto.operationGroupMasterLevel; i++) {
            OperationGroupMasterDto parentOperationDto = mOperationGroupMasterDao.getOperationGroupMaster(parentId);
            parentId = parentOperationDto.parentOperationGroupMasterId;
            operationGroupMasterDtoList.add(parentOperationDto);
        }
        Collections.sort(operationGroupMasterDtoList, new OperationGroupMasterLevelComparator());
        return operationGroupMasterDtoList;
    }

    /**
     * 作業種別IDで関連する作業リストを取得
     * @param operationGroupMasterId カテゴリID
     * @param operationSortingType ソートタイプ
     * @return
     */
    public List<OperationDto> getOperationByOperationGroupMasterId(Integer operationGroupMasterId, String reportTypeStr, OperationSortingType operationSortingType) {
        return mOperationDao.getOperationsByGroupMasterId(operationGroupMasterId, reportTypeStr, operationSortingType);
    }
}

