package com.bizzan.bitrade.service;

import com.bizzan.bitrade.dao.ConfigSymbolDao;
import com.bizzan.bitrade.dao.ConfigSymbolSlippageDao;
import com.bizzan.bitrade.entity.ConfigSymbol;
import com.bizzan.bitrade.entity.ConfigSymbolSlippage;
import com.bizzan.bitrade.service.Base.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class ConfigSymbolService extends BaseService {

    @Autowired
    private ConfigSymbolDao configSymbolDao;

    @Autowired
    private ConfigSymbolSlippageDao configSymbolSlippageDao;

    public ConfigSymbol findOne(Long id) {
        ConfigSymbol symbol = configSymbolDao.findOne(id);
        if (symbol != null) {
            List<ConfigSymbolSlippage> list = configSymbolSlippageDao.findBySymbolOrderBySortAsc(symbol.getSymbol());
            for (ConfigSymbolSlippage s : list) {
                if (s.getSlippage() != null) {
                    s.setSlippage(s.getSlippage().multiply(new BigDecimal("100")));
                }
            }
            symbol.setSlippageList(list);
        }
        return symbol;
    }

    public ConfigSymbol findBySymbol(String symbol) {
        return configSymbolDao.findBySymbol(symbol);
    }

    public List<ConfigSymbol> findAll() {
        return configSymbolDao.findAll();
    }

    public Page<ConfigSymbol> pageQuery(String base, String quote, String zone, String isOpen, Pageable pageable) {
        Specification<ConfigSymbol> spec = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (StringUtils.hasText(base)) {
                predicates.add(cb.equal(root.get("base"), base));
            }
            if (StringUtils.hasText(quote)) {
                predicates.add(cb.equal(root.get("quote"), quote));
            }
            if (StringUtils.hasText(isOpen)) {
                predicates.add(cb.equal(root.get("isOpen"), Integer.parseInt(isOpen)));
            }
            return cb.and(predicates.toArray(new Predicate[0]));
        };
        return configSymbolDao.findAll(spec, pageable);
    }

    @Transactional(rollbackFor = Exception.class)
    public ConfigSymbol create(ConfigSymbol symbol) {
        symbol.setCtime(new Date());
        symbol.setMtime(new Date());
        if (symbol.getCreateTime() == null) {
            symbol.setCreateTime(new Date().getTime());
        }
        ConfigSymbol saved = configSymbolDao.save(symbol);
        saveSlippageList(saved.getSymbol(), symbol.getSlippageList());
        return saved;
    }

    @Transactional(rollbackFor = Exception.class)
    public ConfigSymbol update(ConfigSymbol symbol) {
        symbol.setMtime(new Date());
        ConfigSymbol saved = configSymbolDao.save(symbol);
        configSymbolSlippageDao.deleteBySymbol(saved.getSymbol());
        saveSlippageList(saved.getSymbol(), symbol.getSlippageList());
        return saved;
    }

    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        ConfigSymbol symbol = configSymbolDao.findOne(id);
        if (symbol != null) {
            configSymbolSlippageDao.deleteBySymbol(symbol.getSymbol());
            configSymbolDao.delete(id);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void toggleStatus(Long id) {
        ConfigSymbol symbol = configSymbolDao.findOne(id);
        if (symbol != null) {
            symbol.setIsOpen(symbol.getIsOpen() == 1 ? 2 : 1);
            symbol.setMtime(new Date());
            configSymbolDao.save(symbol);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void togglePublish(Long id) {
        ConfigSymbol symbol = configSymbolDao.findOne(id);
        if (symbol != null) {
            symbol.setPublish(symbol.getPublish() == 1 ? 2 : 1);
            symbol.setMtime(new Date());
            configSymbolDao.save(symbol);
        }
    }

    private void saveSlippageList(String symbol, List<ConfigSymbolSlippage> slippageList) {
        if (slippageList != null && !slippageList.isEmpty()) {
            int sort = 0;
            for (ConfigSymbolSlippage slippage : slippageList) {
                if (slippage.getAmountMin() == null || slippage.getSlippage() == null) {
                    // amountMax 可以为 null，表示无上限
                    continue;
                }
                slippage.setSymbol(symbol);
                slippage.setSort(sort++);
                slippage.setCtime(new Date());
                slippage.setMtime(new Date());
                // 前端输入的是百分比（如 1 表示 1%），转换为实际比例（0.01）
                slippage.setSlippage(slippage.getSlippage().divide(new BigDecimal("100"), 10, RoundingMode.HALF_UP));
                configSymbolSlippageDao.save(slippage);
            }
        }
    }

    public List<ConfigSymbolSlippage> getSlippageList(String symbol) {
        List<ConfigSymbolSlippage> list = configSymbolSlippageDao.findBySymbolOrderBySortAsc(symbol);
        for (ConfigSymbolSlippage s : list) {
            if (s.getSlippage() != null) {
                s.setSlippage(s.getSlippage().multiply(new BigDecimal("100")));
            }
        }
        return list;
    }
}
