package com.neusoft.smart.pos.member.service;

import com.neusoft.smart.pos.framework.exception.BusinessCommonException;
import com.neusoft.smart.pos.member.dto.request.DeleteMemberLevelRequest;
import com.neusoft.smart.pos.member.persistent.domain.MemberWithCard;
import com.neusoft.smart.pos.utils.RequestHeaderUtil;
import com.neusoft.smart.pos.member.constants.MemberErrorCode;
import com.neusoft.smart.pos.dto.member.request.CreateMemberLevelRequest;
import com.neusoft.smart.pos.member.dto.request.GetMemberLevelRequest;
import com.neusoft.smart.pos.member.dto.request.UpdateMemberLevelRequest;
import com.neusoft.smart.pos.dto.member.response.MemberLevelResponse;
import com.neusoft.smart.pos.member.persistent.domain.MemberLevel;
import com.neusoft.smart.pos.member.persistent.domain.MemberLevelExample;
import com.neusoft.smart.pos.member.persistent.mapper.MemberLevelMapper;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

@Service("memberLevelService")
public class MemberLevelService {
    @Resource
    MemberLevelMapper memberLevelMapper;

    public List<MemberLevelResponse> selectMemberLevelList(GetMemberLevelRequest request) {
        MemberLevelExample example = new MemberLevelExample();
        MemberLevelExample.Criteria criteria = example.createCriteria();

        criteria.andIsActiveEqualTo(1);

        Integer org;
        Integer store = 0;
        switch (RequestHeaderUtil.getRole()) {
            case "sa":
                if (request.getOrg() == null) {
                    throw new BusinessCommonException(MemberErrorCode.NO_ORG_PROVIDED);
                }

                org = request.getOrg();
                criteria.andOrgIdEqualTo(org);
                if (request.getStore() != null) {
                    store = request.getStore();
                    criteria.andStoreIdEqualTo(store);

                }
                break;
            case "admin":
                org = RequestHeaderUtil.getOrgId();
                criteria.andOrgIdEqualTo(org);
                if (request.getStore() != null) {
                    store = request.getStore();
                    criteria.andStoreIdEqualTo(store);
                }
                break;
            case "user":
                if (request.getStore() == null) {
                    throw new BusinessCommonException(MemberErrorCode.NO_STORE_PROVIDED);
                }
                org = RequestHeaderUtil.getOrgId();
                store = request.getStore();
                criteria.andOrgIdEqualTo(org);
                criteria.andStoreIdEqualTo(store);
                break;
            default:
                throw new BusinessCommonException(MemberErrorCode.UNKNOWN_USER_ROLE);
        }

        checkAndBuildDefaultLevel(org, store);

        example.setOrderByClause("store_id, level asc");

        ArrayList<MemberLevelResponse> result = new ArrayList<>();
        for (MemberLevel memberLevel : memberLevelMapper.selectByExample(example)) {
            result.add(fillMemberLevelResponse(new MemberLevelResponse(), memberLevel));
        }

        return result;
    }

    private Integer checkAndBuildDefaultLevel(Integer org, Integer store) {
        MemberLevelExample example = new MemberLevelExample();
        MemberLevelExample.Criteria criteria = example.createCriteria();

        criteria.andOrgIdEqualTo(org);
        criteria.andStoreIdEqualTo(store);
        criteria.andLevelEqualTo((byte) 1);
        criteria.andIsActiveEqualTo(1);

        List<MemberLevel> result = memberLevelMapper.selectByExample(example);
        if (result.size() > 0) {
            return (result.get(0)).getMemberLevelId();
        }

        MemberLevel memberLevel = new MemberLevel();
        memberLevel.setLevelName("初级");
        memberLevel.setLevel((byte) 1);
        memberLevel.setRequiredRechargeAmount(new BigDecimal(0));
        memberLevel.setDiscountProportion(new BigDecimal(10));
        memberLevel.setOrgId(org);
        memberLevel.setStoreId(store);

        memberLevelMapper.insertSelective(memberLevel);

        return memberLevel.getMemberLevelId();
    }

    public MemberLevelResponse selectMemberLevelById(Integer id) {
        return fillMemberLevelResponse(new MemberLevelResponse(), memberLevelMapper.selectByPrimaryKey(id));
    }

    public MemberLevelResponse insertOrUpdateMemberLevel(CreateMemberLevelRequest request) {
        MemberLevel memberLevel = new MemberLevel();

        switch (RequestHeaderUtil.getRole()) {
            case "sa":
                if (request.getOrg() == null || request.getStore() == null) {
                    throw new BusinessCommonException(MemberErrorCode.NO_ORG_PROVIDED);
                }

                memberLevel.setOrgId(request.getOrg());
                memberLevel.setStoreId(request.getStore());
                break;
            case "admin":
                if (request.getStore() == null) {
                    throw new BusinessCommonException(MemberErrorCode.NO_ORG_PROVIDED);
                }
                memberLevel.setOrgId(RequestHeaderUtil.getOrgId());
                memberLevel.setStoreId(request.getStore());
                break;
            case "user":
                if (request.getStore() == null) {
                    throw new BusinessCommonException(MemberErrorCode.NO_STORE_PROVIDED);
                }
                memberLevel.setOrgId(RequestHeaderUtil.getOrgId());
                memberLevel.setStoreId(request.getStore());
                break;
            default:
                throw new BusinessCommonException(MemberErrorCode.UNKNOWN_USER_ROLE);
        }

        memberLevel.setLevelName(request.getName());
        memberLevel.setLevel(request.getLevel());
        memberLevel.setRequiredRechargeAmount(request.getRequiredRechargeAmount());
        memberLevel.setDiscountProportion(validateDiscount(request.getDiscount()));

        MemberLevelExample example = new MemberLevelExample();
        example.createCriteria().andLevelEqualTo(memberLevel.getLevel())
                .andOrgIdEqualTo(memberLevel.getOrgId())
                .andStoreIdEqualTo(memberLevel.getStoreId());

        if (memberLevelMapper.countByExample(example) > 0) {
            // update
            memberLevelMapper.updateByExampleSelective(memberLevel, example);
        } else {
            // create
            memberLevelMapper.insertSelective(memberLevel);
        }

        return fillMemberLevelResponse(new MemberLevelResponse(), memberLevel);
    }

    public MemberLevelResponse updateMemberLevel(Integer id, UpdateMemberLevelRequest request) {
        MemberLevel memberLevel = new MemberLevel();
        memberLevel.setMemberLevelId(id);

        if (!StringUtils.isEmpty(request.getName())) memberLevel.setLevelName(request.getName());
        if (request.getRequiredRechargeAmount() != null) memberLevel.setRequiredRechargeAmount(request.getRequiredRechargeAmount());
        if (request.getDiscount() != null) memberLevel.setDiscountProportion(request.getDiscount());

        memberLevelMapper.updateByPrimaryKeySelective(memberLevel);

        return fillMemberLevelResponse(new MemberLevelResponse(), memberLevelMapper.selectByPrimaryKey(id));
    }

    public void deleteMemberLevel(DeleteMemberLevelRequest request) {
        MemberLevelExample example = new MemberLevelExample();
        MemberLevelExample.Criteria criteria = example.createCriteria();

        criteria.andLevelEqualTo(request.getLevel());

        switch (RequestHeaderUtil.getRole()) {
            case "sa":
                if (request.getOrg() == null || request.getStore() == null) {
                    throw new BusinessCommonException(MemberErrorCode.NO_ORG_PROVIDED);
                }

                criteria.andOrgIdEqualTo(request.getOrg());
                criteria.andStoreIdEqualTo(request.getStore());
                break;
            case "admin":
                if (request.getStore() == null) {
                    throw new BusinessCommonException(MemberErrorCode.NO_ORG_PROVIDED);
                }
                criteria.andOrgIdEqualTo(RequestHeaderUtil.getOrgId());
                criteria.andStoreIdEqualTo(request.getStore());
                break;
            case "user":
                if (request.getStore() == null) {
                    throw new BusinessCommonException(MemberErrorCode.NO_STORE_PROVIDED);
                }
                criteria.andOrgIdEqualTo(RequestHeaderUtil.getOrgId());
                criteria.andStoreIdEqualTo(request.getStore());
                break;
            default:
                throw new BusinessCommonException(MemberErrorCode.UNKNOWN_USER_ROLE);
        }

        memberLevelMapper.deleteByExample(example);
    }

    public MemberLevel getMemberLevel(MemberWithCard memberWithCard) {
        MemberLevelExample example = new MemberLevelExample();
        example.setOrderByClause("level desc");

        MemberLevelExample.Criteria criteria = example.createCriteria();
        criteria.andOrgIdEqualTo(memberWithCard.getMemberOrgId());
        criteria.andStoreIdEqualTo(memberWithCard.getMemberStoreId());

        List<MemberLevel> memberLevelList = memberLevelMapper.selectByExample(example);

        Long lastRechargeAmount = memberWithCard.getLastRechargeAmount();
        for (MemberLevel memberLevel : memberLevelList) {
            if (new BigDecimal(lastRechargeAmount).compareTo(memberLevel.getRequiredRechargeAmount().multiply(new BigDecimal(100))) >= 0) {
                return memberLevel;
            }
        }

        throw new BusinessCommonException(MemberErrorCode.CANNOT_LOCATE_MEMBER_LEVEL);
    }

    private MemberLevelResponse fillMemberLevelResponse(MemberLevelResponse resp, MemberLevel memberLevel) {
        resp.setId(memberLevel.getMemberLevelId());
        resp.setName(memberLevel.getLevelName());
        resp.setLevel(memberLevel.getLevel());
        resp.setRequiredRechargeAmount(memberLevel.getRequiredRechargeAmount());
        resp.setDiscount(memberLevel.getDiscountProportion());

        return resp;
    }

    private BigDecimal validateDiscount(BigDecimal discount) {
        BigDecimal max = BigDecimal.valueOf(10);
        BigDecimal min = BigDecimal.valueOf(0.01);

        if (discount.compareTo(max) == 1 || discount.compareTo(min) == -1) {
            throw new BusinessCommonException(MemberErrorCode.INVALID_DISCOUNT);
        }

        return discount;
    }
}
