package com.cf.imes.module.system.service.funds.advertisement;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.module.infra.api.file.FileApi;
import com.cf.imes.module.system.controller.admin.funds.advertisement.vo.*;
import com.cf.imes.module.system.dal.dataobject.funds.advertisement.AdvertisementDO;
import com.cf.imes.module.system.dal.mysql.funds.advertisement.AdvertisementMapper;
import com.cf.imes.module.system.enums.advertisement.AdvertisementStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import jakarta.annotation.Resource;
import java.io.IOException;
import java.time.LocalDate;
import java.util.*;

import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;

/**
 * 广告表 advertisement Service 实现类
 *
 * @author 晨丰科技
 */
@Service
@Validated
@Slf4j
public class AdvertisementServiceImpl implements AdvertisementService{

    @Resource
    private AdvertisementMapper advertisementMapper;

    @Resource
    private FileApi fileApi;


    @Override
    public Long create(AdvertisementSaveReqVO createReqVO) {

        if (createReqVO.getStartTime().isAfter(createReqVO.getEndTime())) {

            throw new ServiceException(ADVERTISEMENT_TIME_ERROR);
        }

        AdvertisementDO aDo = advertisementMapper.selectAdByAdName(createReqVO.getAdName(), null);

        AssertUtils.empty(aDo, ADVERTISEMENT_NAME_IS_EXIST);

        // 插入广告
        AdvertisementDO advertisementDO = BeanUtils.toBean(createReqVO, AdvertisementDO.class)
                .setAdPosition(createReqVO.getAdPosition().stream().sorted().distinct().toList())
                .setStatus(AdvertisementStatusEnum.UNPUBLISHED.getStatus());

        advertisementMapper.insert(advertisementDO);

        return advertisementDO.getId();

    }





    @Override
    public void update(AdvertisementSaveReqVO reqVO) {
        if (reqVO.getStartTime().isAfter(reqVO.getEndTime())) {
            throw new ServiceException(ADVERTISEMENT_TIME_ERROR);
        }

        Long id = reqVO.getId();
        // 确认广告是否存在
        AdvertisementDO advertisementDO = validateAdvertisementExists(id);

        // 发布中的广告不允许编辑
        if (AdvertisementStatusEnum.PUBLISHED.getStatus().equals(advertisementDO.getStatus())) {
            throw new ServiceException(ADVERTISEMENT_UPDATE_STATUS_ERROR);
        }

        // 广告名重复校验
        AdvertisementDO aDo = advertisementMapper.selectAdByAdName(reqVO.getAdName(), id);

        AssertUtils.empty(aDo, ADVERTISEMENT_NAME_IS_EXIST);

        // 更新内容
        advertisementDO.setAdName(reqVO.getAdName())
                .setAdImagePath(reqVO.getAdImagePath())
                .setStartTime(reqVO.getStartTime())
                .setEndTime(reqVO.getEndTime())
                .setAdPosition(reqVO.getAdPosition().stream().sorted().distinct().toList())
                .setSort(ObjectUtil.defaultIfNull(reqVO.getSort(), advertisementDO.getSort()))
                .setAdRedirectUrl(StringUtils.defaultIfEmpty(reqVO.getAdRedirectUrl(), advertisementDO.getAdRedirectUrl()));
        advertisementMapper.updateById(advertisementDO);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {

        // 确认广告是否存在
        AdvertisementDO advertisementDO = validateAdvertisementExists(id);

        if (advertisementDO.getStatus().equals(AdvertisementStatusEnum.PUBLISHED.getStatus())) {
            throw new ServiceException(ADVERTISEMENT_NO_DELETE);
        }
        // 删除广告
        advertisementMapper.deleteById(id);

        // 删除广告图片文件
        fileApi.deleteFileByPath(advertisementDO.getAdImagePath());
    }


    @Override
    public AdvertisementRespVO get(Long id) {

        AdvertisementDO advertisementDO = validateAdvertisementExists(id);

        AdvertisementRespVO respVO = BeanUtils.toBean(advertisementDO, AdvertisementRespVO.class);

        return respVO;
    }



    @Override
    public PageResult<AdvertisementRespVO> getPage(AdvertisementPageReqVO pageReqVO) {

        PageResult<AdvertisementDO> pageResult = advertisementMapper.selectPage(pageReqVO);

        if (CollUtil.isEmpty(pageResult.getList())) {
            return new PageResult<>(pageResult.getTotal());
        }

        List<AdvertisementRespVO> respVOS = BeanUtils.toBean(pageResult.getList(), AdvertisementRespVO.class);

        respVOS.forEach(f -> {
            f.setLaunchTime(f.getStartTime() + "~" + f.getEndTime());
        });

        return new PageResult<>(respVOS, pageResult.getTotal());

    }


    @Override
    public void publish(Long id) {
        // 校验广告存在
        AdvertisementDO advertisementDO = validateAdvertisementExists(id);

        // 广告的结束时间
        LocalDate endTime = advertisementDO.getEndTime();
        if (LocalDate.now().isAfter(endTime)) {
            throw new ServiceException(ADVERTISEMENT_STATUS_ENDTIME_EXPIRED);
        }

        advertisementMapper.update(new LambdaUpdateWrapper<AdvertisementDO>()
                .eq(AdvertisementDO::getId, id)
                .set(AdvertisementDO::getStatus, AdvertisementStatusEnum.PUBLISHED.getStatus()));
    }

    @Override
    public void endPublish(Long id) {
        // 校验广告存在
        validateAdvertisementExists(id);

        advertisementMapper.update(new LambdaUpdateWrapper<AdvertisementDO>()
                .eq(AdvertisementDO::getId, id)
                .set(AdvertisementDO::getStatus, AdvertisementStatusEnum.ENDED.getStatus()));
    }

    @Override
    public void republish(AdvertisementRePublishReqVO reqVO) {
        // 校验广告存在
        Long id = reqVO.getId();
        validateAdvertisementExists(id);

        if (reqVO.getStartTime().isAfter(reqVO.getEndTime())) {
            throw new ServiceException(ADVERTISEMENT_TIME_ERROR);
        }

        advertisementMapper.update(new LambdaUpdateWrapper<AdvertisementDO>()
                .eq(AdvertisementDO::getId, id)
                .set(AdvertisementDO::getStatus, AdvertisementStatusEnum.PUBLISHED.getStatus())
                .set(AdvertisementDO::getStartTime, reqVO.getStartTime())
                .set(AdvertisementDO::getEndTime, reqVO.getEndTime()));
    }


    @Override
    public List<AdvertisementRespVO> getAdvertisementByPosition(Integer adPosition) {

        List<AdvertisementRespVO> respVOS = advertisementMapper.selectAdList(adPosition, AdvertisementStatusEnum.PUBLISHED.getStatus(), LocalDate.now());

        if(CollUtil.isEmpty(respVOS)){
            return new ArrayList<>();
        }

        return respVOS;
    }

    /**
     * 校验广告是否存在
     *
     * @param id
     * @return
     */
    private AdvertisementDO validateAdvertisementExists(Long id) {

        AdvertisementDO advertisementDO = advertisementMapper.selectOne(new LambdaQueryWrapperX<AdvertisementDO>()
                .eq(AdvertisementDO::getDeleted, false)
                .eq(AdvertisementDO::getId, id));
        if (advertisementDO == null) {
            throw new ServiceException(ADVERTISEMENT_NO_EXIST);
        }
        return advertisementDO;
    }

    @Override
    public String uploadAdImage(MultipartFile adImageFile) {
        try {
            if (adImageFile.isEmpty()) {
                throw new ServiceException(ADVERTISEMENT_IMAGE_EMPTY_ERROR);
            }
            return fileApi.createFile(adImageFile.getBytes());
        } catch (IOException e) {
            log.error("上传广告图片失败", e);
            throw new ServiceException(ADVERTISEMENT_IMAGE_UPLOAD_FAIL);
        }
    }
}
