package com.ruoyi.web.modules.technology.service.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.web.modules.technology.domain.BizPracticalTraining;
import com.ruoyi.web.modules.technology.mapper.BizPracticalTrainingMapper;
import com.ruoyi.web.modules.technology.service.IBizPracticalTrainingService;
import com.ruoyi.web.modules.technology.support.PracticalTrainingEnrollStatusResolver;
import com.ruoyi.web.modules.technology.support.PracticalTrainingRules;
import com.ruoyi.web.modules.technology.support.PracticalTrainingStatusSupport;
import com.ruoyi.web.modules.technology.support.PracticalTrainingValidation;

/**
 * 实战业务培训服务实现。
 */
@Service
public class BizPracticalTrainingServiceImpl implements IBizPracticalTrainingService
{
    @Autowired
    private BizPracticalTrainingMapper bizPracticalTrainingMapper;

    @Autowired
    private PracticalTrainingStatusSupport practicalTrainingStatusSupport;

    @Override
    public BizPracticalTraining selectBizPracticalTrainingById(Long id)
    {
        BizPracticalTraining row = bizPracticalTrainingMapper.selectBizPracticalTrainingById(id);
        enrichRow(row);
        return row;
    }

    @Override
    public List<BizPracticalTraining> selectBizPracticalTrainingList(BizPracticalTraining query)
    {
        PracticalTrainingValidation.validateListDateRange(
                query != null ? query.getStartDate() : null,
                query != null ? query.getEndDate() : null);
        List<BizPracticalTraining> list = bizPracticalTrainingMapper.selectBizPracticalTrainingList(query);
        if (list != null)
        {
            for (BizPracticalTraining row : list)
            {
                enrichRow(row);
            }
        }
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertBizPracticalTraining(BizPracticalTraining row)
    {
        PracticalTrainingValidation.validateRowForSave(row);
        boolean saveAndPublish = Boolean.TRUE.equals(row.getSaveAndPublish());
        row.setSaveAndPublish(null);
        row.setPublishStatus(PracticalTrainingRules.PUBLISH_STATUS_DRAFT);
        row.setPublishTime(null);
        row.setOfflineTime(null);
        row.setDelFlag(PracticalTrainingRules.DEL_FLAG_NORMAL);
        if (row.getActualEnrolledCount() == null)
        {
            row.setActualEnrolledCount(0);
        }
        row.setTrainingStatus(PracticalTrainingRules.TRAINING_STATUS_NOT_STARTED);
        int n = bizPracticalTrainingMapper.insertBizPracticalTraining(row);
        if (n > 0 && saveAndPublish)
        {
            publish(row.getId());
        }
        return n;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateBizPracticalTraining(BizPracticalTraining row)
    {
        if (row.getId() == null)
        {
            throw new ServiceException("主键不能为空");
        }
        PracticalTrainingValidation.validateRowForSave(row);
        BizPracticalTraining db = requireRow(row.getId());
        PracticalTrainingValidation.validateForUpdate(db);

        String oldCoverPath = db.getCoverFilePath();

        row.setPublishStatus(db.getPublishStatus());
        row.setPublishTime(db.getPublishTime());
        row.setOfflineTime(db.getOfflineTime());
        row.setActualEnrolledCount(db.getActualEnrolledCount());
        row.setDelFlag(db.getDelFlag());
        applyPersistedTrainingStatus(row);

        int n = bizPracticalTrainingMapper.updateBizPracticalTraining(row);
        if (n > 0 && !StringUtils.equals(StringUtils.nvl(oldCoverPath, ""), StringUtils.nvl(row.getCoverFilePath(), "")))
        {
            deleteDiskFile(oldCoverPath);
        }
        return n;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteBizPracticalTrainingByIds(Long[] ids, String updateBy)
    {
        if (ids == null || ids.length == 0)
        {
            return 0;
        }
        List<Long> cleaned = new ArrayList<>();
        for (Long id : ids)
        {
            if (id != null)
            {
                cleaned.add(id);
            }
        }
        if (cleaned.isEmpty())
        {
            return 0;
        }
        for (Long id : cleaned)
        {
            BizPracticalTraining row = bizPracticalTrainingMapper.selectBizPracticalTrainingByIdAny(id);
            if (row == null || PracticalTrainingRules.DEL_FLAG_DELETED.equals(row.getDelFlag()))
            {
                continue;
            }
            PracticalTrainingValidation.validateForDelete(row);
            deleteDiskFile(row.getCoverFilePath());
        }
        return bizPracticalTrainingMapper.logicDeleteBizPracticalTrainingByIds(
                cleaned.toArray(new Long[0]), updateBy);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int publish(Long id)
    {
        BizPracticalTraining row = requireRow(id);
        PracticalTrainingValidation.validateForPublish(row);
        PracticalTrainingValidation.validateRowForSave(row);
        row.setPublishStatus(PracticalTrainingRules.PUBLISH_STATUS_PUBLISHED);
        row.setPublishTime(new Date());
        applyPersistedTrainingStatus(row);
        int n = bizPracticalTrainingMapper.updateBizPracticalTraining(row);
        if (n > 0)
        {
            practicalTrainingStatusSupport.refreshAndPersist(row, new Date());
            enrichRow(row);
        }
        return n;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int offline(Long id)
    {
        BizPracticalTraining row = requireRow(id);
        Date now = new Date();
        PracticalTrainingValidation.validateOffline(row, now);
        Date publishTime = row.getPublishTime();
        row.setPublishStatus(PracticalTrainingRules.PUBLISH_STATUS_DRAFT);
        row.setOfflineTime(now);
        row.setPublishTime(publishTime);
        applyPersistedTrainingStatus(row);
        int n = bizPracticalTrainingMapper.updateBizPracticalTraining(row);
        enrichRow(row);
        return n;
    }

    /**
     * 写入库前填充 training_status（管理端表单通常不传该字段）。
     */
    private static void applyPersistedTrainingStatus(BizPracticalTraining row)
    {
        if (row == null)
        {
            return;
        }
        if (row.getPublishStatus() == null
                || row.getPublishStatus() == PracticalTrainingRules.PUBLISH_STATUS_DRAFT)
        {
            row.setTrainingStatus(PracticalTrainingRules.TRAINING_STATUS_NOT_STARTED);
        }
        else
        {
            row.setTrainingStatus(PracticalTrainingEnrollStatusResolver.resolveTrainingStatus(row, new Date()));
        }
    }

    private BizPracticalTraining requireRow(Long id)
    {
        BizPracticalTraining row = bizPracticalTrainingMapper.selectBizPracticalTrainingById(id);
        if (row == null)
        {
            throw new ServiceException("记录不存在或已删除");
        }
        return row;
    }

    private void enrichRow(BizPracticalTraining row)
    {
        if (row != null)
        {
            Date now = new Date();
            String resolved = PracticalTrainingEnrollStatusResolver.resolveTrainingStatus(row, now);
            if (row.getId() != null
                    && row.getPublishStatus() != null
                    && row.getPublishStatus() == PracticalTrainingRules.PUBLISH_STATUS_PUBLISHED
                    && !resolved.equals(row.getTrainingStatus()))
            {
                practicalTrainingStatusSupport.refreshAndPersist(row, now);
            }
            else
            {
                PracticalTrainingEnrollStatusResolver.applyEnrollStatus(row, now);
            }
        }
    }

    private void deleteDiskFile(String resourcePath)
    {
        if (StringUtils.isEmpty(resourcePath) || !resourcePath.startsWith(Constants.RESOURCE_PREFIX))
        {
            return;
        }
        String relative = FileUtils.stripPrefix(resourcePath);
        while (relative.startsWith("/") || relative.startsWith("\\"))
        {
            relative = relative.substring(1);
        }
        String full = RuoYiConfig.getProfile() + File.separator + relative.replace("/", File.separator);
        FileUtils.deleteFile(full);
    }
}
