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

import cn.hutool.core.collection.CollUtil;
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.id.core.util.SnowflakeIdWorker3rd;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
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.dal.mysql.funds.advertisement.AdvertisementTaskMapper;
import com.cf.imes.module.system.enums.advertisement.AdvertisementStatusEnum;
import com.cf.imes.module.system.mq.producer.advertisement.AdvertisementProducer;
import com.cf.imes.module.system.service.dict.DictDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
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.File;
import java.io.IOException;
import java.nio.file.Files;
import java.time.LocalDate;
import java.util.*;

import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;

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

    private static final String ADVERTISEMENT_POSITION = "advertisement_position";

    private static final String EMPTY_STRING = new String();

    @Value("${chenfeng.info.name}")
    private String SOFT_WARE_ID; // 获取软件标识-可修改

    @Resource
    private DictDataService dictDataService;

    @Resource
    private AdvertisementMapper advertisementMapper;

    @Resource
    private AdvertisementTaskMapper advertisementTaskMapper;

    @Resource
    private SnowflakeIdWorker3rd idWorker;

    @Resource
    private AdvertisementProducer advertisementProducer;

    @Resource
    private AdImageFilePath adImageFilePath;


    private static final String FIELD_AD_ID = "广告ID为：";


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(AdvertisementSaveReqVO createReqVO) {

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

            throw exception(ADVERTISEMENT_TIME_ERROR);
        }

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

        AssertUtils.empty(aDo,ADVERTISEMENT_NAME_IS_EXIST);

        long id = idWorker.nextId();

        String filePath = "";
        if(createReqVO.getAdImageFile() != null) {
            filePath = uploadAdImageFile(createReqVO.getAdImageFile(), id);
        }

        // 插入广告
        createReqVO.setId(id);
        AdvertisementDO advertisementDO = BeanUtils.toBean(createReqVO, AdvertisementDO.class)
                .setAdPosition(Arrays.toString(createReqVO.getAdPosition()))
                .setStatus(validateAdvertisementStatus(createReqVO.getStartTime()))
                .setAdImagePath(filePath)
                .setSoftwareId(SOFT_WARE_ID);

        advertisementMapper.insert(advertisementDO);

        return advertisementDO.getId();

    }





    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(AdvertisementSaveReqVO reqVO) {

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

        AdvertisementDO aDo = advertisementMapper.selectAdByAdName(reqVO.getAdName(),reqVO.getId());

        AssertUtils.empty(aDo,ADVERTISEMENT_NAME_IS_EXIST);

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


        String adImagePath = validated.getAdImagePath();
        if(reqVO.getAdImageFile() != null) {
            adImagePath = uploadAdImageFile(reqVO.getAdImageFile(), reqVO.getId());

        }


        // 更新内容
        AdvertisementDO advertisementDO = BeanUtils.toBean(reqVO, AdvertisementDO.class)
                .setAdPosition(Arrays.toString(reqVO.getAdPosition()))
                .setStatus(validateAdvertisementStatus(reqVO.getStartTime()))
                .setAdImagePath(adImagePath)
                .setSoftwareId(SOFT_WARE_ID);

        advertisementMapper.updateById(advertisementDO);


    }



    @Override
    public void delete(Long id) {

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

        if(advertisementDO.getStatus().equals(AdvertisementStatusEnum.PUBLISHED.getStatus())){
            throw exception(ADVERTISEMENT_NO_DELETE);
        }

        advertisementMapper.deleteById(id);

        deleteFilesById(adImageFilePath.getFilePath(),id.toString());

    }




    @Override
    public AdvertisementRespVO get(Long id) {

        AdvertisementDO advertisementDO = validateAdvertisementExists(id);

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

        viewImage(respVO);

        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());
            viewImage(f);
        });

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

    }




    @Override
    public void updatePublishStatus(AdvertisementPublishReqVO reqVO) {

        Long id = reqVO.getId();

        Integer status = reqVO.getStatus();

        AdvertisementDO advertisementDO = validateAdvertisementExists(id);

        // 广告的开始时间
        LocalDate startTime = advertisementDO.getStartTime();

        // 广告的结束时间
        LocalDate endTime = advertisementDO.getEndTime();

        // 立即发布
        if (status.equals(AdvertisementStatusEnum.PUBLISHED.getStatus())) {

            if (LocalDate.now().isAfter(startTime)) {
                throw exception(ADVERTISEMENT_STATUS_ERROR);
            }
            if (LocalDate.now().isAfter(endTime)) {
                throw exception(ADVERTISEMENT_STATUS_ERROR2);
            }

            advertisementDO.setStatus(status);
        }
        // 结束发布
        else if (status.equals(AdvertisementStatusEnum.ENDED.getStatus())) {
            if (LocalDate.now().isBefore(startTime)) {
                throw exception(ADVERTISEMENT_END_ERROR);
            }
            if (LocalDate.now().isAfter(endTime)) {
                throw exception(ADVERTISEMENT_END_ERROR2);
            }

            advertisementDO.setStatus(status);
        }
        // 重新发布
        else if(Boolean.TRUE.equals(reqVO.getIsRepublish())){

            // 重新投放开始时间
            LocalDate isRepublishStartTime = Optional.ofNullable(reqVO.getStartTime()).orElseThrow(() -> new ServiceException(ADVERTISEMENT_REPUBLISH_NO_TIME));

            // 重新投放结束时间
            LocalDate isRepublishEndTime = Optional.ofNullable(reqVO.getEndTime()).orElseThrow(() -> new ServiceException(ADVERTISEMENT_REPUBLISH_NO_TIME));

            if(isRepublishStartTime.isAfter(isRepublishEndTime)){
                throw exception(ADVERTISEMENT_TIME_ERROR);
            }

            validateAdvertisementStatus(isRepublishStartTime);

            advertisementDO.setStatus(AdvertisementStatusEnum.PUBLISHED.getStatus());

        }

        advertisementMapper.updateById(advertisementDO);


    }






    @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<>();
        }

        respVOS.forEach(this::viewImage);

        return respVOS;

    }








    // 判断广告状态
    public int validateAdvertisementStatus(LocalDate startTime) {

        // 当前时间
        LocalDate now = LocalDate.now();

        if(now.equals(startTime)){
            // 已上架
            return AdvertisementStatusEnum.PUBLISHED.getStatus();

        }else if(now.isAfter(startTime)){
            throw exception(ADVERTISEMENT_START_TIME_ERROR);

        }else {
            // 未上架
            return AdvertisementStatusEnum.UNPUBLISHED.getStatus();

        }

    }





    private AdvertisementDO validateAdvertisementExists(Long id) {

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






    // 上传图片
    private String uploadAdImageFile(MultipartFile file,Long id){

        try {

            // 删除之前的图片
            deleteFilesById(adImageFilePath.getFilePath(),id.toString());

            // 获取原始文件名并提取扩展名
            String originalFilename = file.getOriginalFilename();
            String extension = null;

            int dotIndex = originalFilename.lastIndexOf('.');
            if (dotIndex != -1) {

                extension = originalFilename.substring(dotIndex);
            }

            // 文件名: id + .扩展名
            String filename = id + extension;

            // 确保目录存在
            File dir = new File(adImageFilePath.getFilePath());
            if (!dir.exists()) {
                dir.mkdirs();
            }

            File dest = new File(dir, filename);
            file.transferTo(dest);

            return filename;

        } catch (Exception e) {
            log.error("图片上传失败："+e.getMessage());
            throw exception(IMAGE_UPLOAD_ERROR);
        }

    }







    // 删除图片
    public static void deleteFilesById(String directoryPath, String id) {
        File dir = new File(directoryPath);
        if (!dir.exists() || !dir.isDirectory()) {
            // 路径不存在或不是文件夹，不做处理
            return;
        }

        File[] files = dir.listFiles();
        if (files == null) {
            return;
        }

        for (File file : files) {
            if (file.isFile()) {
                String fileName = file.getName();
                if (fileName.startsWith(id + ".")) {
                    file.delete(); // 删除文件，不管结果（失败不会抛异常）
                }
            }
        }
    }







    // 查询图片，广告管理界面，广告位置查询，错误只写到日志，页面不显示错误
    public void viewImage(AdvertisementRespVO respVO) {

        File dir = new File(adImageFilePath.getFilePath());
        if (!dir.exists()) {
            log.error(FIELD_AD_ID + respVO.getId() + "，的图片查询失败，其目录不存在");
            return;
        }

        File[] matches = dir.listFiles((d, name) -> name.startsWith(respVO.getId().toString() + "."));
        if (matches == null || matches.length == 0) {
            log.error(FIELD_AD_ID + respVO.getId() + "，的图片查询失败，未找到对应图片");
            return;
        }

        File imageFile = matches[0];

        try {

            // 图片字节数据
            byte[] imageBytes = Files.readAllBytes(imageFile.toPath());

            // 图片的文件类型
            respVO.setAdImageFileType(Files.probeContentType(imageFile.toPath()));

            // 图片的 Base64 字符串形式
            respVO.setAdImageBase64(Base64.getEncoder().encodeToString(imageBytes));

        } catch (IOException e) {

            log.error(FIELD_AD_ID + respVO.getId() + "，的图片读取失败，" + e.getMessage());
        }

    }










    public ResponseEntity<byte[]> getImage(Long adId){


        File dir = new File(adImageFilePath.getFilePath());

        if (!dir.exists()) {
            return ResponseEntity.notFound().build();
        }

        // 找到文件名以 adId 开头的文件，例如 "123.png"
        File[] matches = dir.listFiles((d, name) -> name.startsWith(adId.toString() + "."));

        if (matches == null || matches.length == 0) {
            return ResponseEntity.notFound().build();
        }


        File imageFile = matches[0];

        try {

            byte[] imageBytes = Files.readAllBytes(imageFile.toPath());
            String contentType = Files.probeContentType(imageFile.toPath());

            return ResponseEntity.ok()
                    .contentType(MediaType.parseMediaType(contentType))
                    .body(imageBytes);
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }


    }






}
