package cn.iocoder.yudao.module.asset.service.inspection;

import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionRecordDetailVO;
import cn.iocoder.yudao.module.asset.controller.admin.inspection.vo.InspectionRecordItemUpdateReqVO;
import cn.iocoder.yudao.module.asset.convert.inspection.InspectionConvert;
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionRecordDO;
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionRecordItemDO;
import cn.iocoder.yudao.module.asset.dal.dataobject.inspection.InspectionTemplateItemDO;
import cn.iocoder.yudao.module.asset.dal.mysql.inspection.InspectionRecordItemMapper;
import cn.iocoder.yudao.module.asset.dal.mysql.inspection.InspectionRecordMapper;
import cn.iocoder.yudao.module.asset.dal.mysql.inspection.InspectionTemplateItemMapper;
import cn.iocoder.yudao.module.asset.enums.inspection.InspectionSourceTypeEnum;
import cn.iocoder.yudao.module.asset.enums.inspection.InspectionStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.*;

/**
 * 验车记录 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class InspectionRecordServiceImpl implements InspectionRecordService {

    @Resource
    private InspectionRecordMapper inspectionRecordMapper;

    @Resource
    private InspectionRecordItemMapper inspectionRecordItemMapper;

    @Resource
    private InspectionTemplateItemMapper inspectionTemplateItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createRecord(Long templateId, Integer sourceType, Long sourceId, Long vehicleId) {
        // 查询模板检查项
        List<InspectionTemplateItemDO> templateItems = inspectionTemplateItemMapper.selectByTemplateId(templateId);

        // 生成记录编码
        String recordCode = generateRecordCode(sourceType);

        // 创建验车记录
        InspectionRecordDO record = InspectionRecordDO.builder()
                .recordCode(recordCode)
                .templateId(templateId)
                .sourceType(sourceType)
                .sourceId(sourceId)
                .vehicleId(vehicleId)
                .status(InspectionStatusEnum.PENDING.getStatus())
                .build();
        inspectionRecordMapper.insert(record);

        // 批量插入检查项（从模板复制）
        if (!templateItems.isEmpty()) {
            List<InspectionRecordItemDO> recordItems = new ArrayList<>(templateItems.size());
            for (InspectionTemplateItemDO templateItem : templateItems) {
                InspectionRecordItemDO recordItem = InspectionRecordItemDO.builder()
                        .recordId(record.getId())
                        .itemCode(templateItem.getItemCode())
                        .category(templateItem.getCategory())
                        .itemName(templateItem.getItemName())
                        .inputType(templateItem.getInputType())
                        .build();
                recordItems.add(recordItem);
            }
            inspectionRecordItemMapper.insertBatch(recordItems);
        }

        return record.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long cloneRecord(Long sourceRecordId, Integer newSourceType, Long newSourceId) {
        // 查询源记录
        InspectionRecordDO sourceRecord = inspectionRecordMapper.selectById(sourceRecordId);
        if (sourceRecord == null) {
            throw exception(INSPECTION_RECORD_NOT_EXISTS);
        }

        // 查询源检查项
        List<InspectionRecordItemDO> sourceItems = inspectionRecordItemMapper.selectByRecordId(sourceRecordId);

        // 生成记录编码
        String recordCode = generateRecordCode(newSourceType);

        // 创建新记录
        InspectionRecordDO newRecord = InspectionRecordDO.builder()
                .recordCode(recordCode)
                .templateId(sourceRecord.getTemplateId())
                .sourceType(newSourceType)
                .sourceId(newSourceId)
                .vehicleId(sourceRecord.getVehicleId())
                .status(InspectionStatusEnum.PENDING.getStatus())
                .clonedFromId(sourceRecordId)
                .build();
        inspectionRecordMapper.insert(newRecord);

        // 复制检查项（保留结果数据）
        if (!sourceItems.isEmpty()) {
            List<InspectionRecordItemDO> newItems = new ArrayList<>(sourceItems.size());
            for (InspectionRecordItemDO sourceItem : sourceItems) {
                InspectionRecordItemDO newItem = InspectionRecordItemDO.builder()
                        .recordId(newRecord.getId())
                        .itemCode(sourceItem.getItemCode())
                        .category(sourceItem.getCategory())
                        .itemName(sourceItem.getItemName())
                        .inputType(sourceItem.getInputType())
                        .result(sourceItem.getResult())
                        .value(sourceItem.getValue())
                        .remark(sourceItem.getRemark())
                        .imageUrls(sourceItem.getImageUrls())
                        .build();
                newItems.add(newItem);
            }
            inspectionRecordItemMapper.insertBatch(newItems);
        }

        return newRecord.getId();
    }

    @Override
    public void updateRecordItem(InspectionRecordItemUpdateReqVO updateReqVO) {
        // 校验检查项存在
        InspectionRecordItemDO item = inspectionRecordItemMapper.selectById(updateReqVO.getId());
        if (item == null) {
            throw exception(INSPECTION_RECORD_NOT_EXISTS);
        }

        // 更新检查项
        InspectionRecordItemDO updateObj = InspectionRecordItemDO.builder()
                .id(updateReqVO.getId())
                .result(updateReqVO.getResult())
                .value(updateReqVO.getValue())
                .remark(updateReqVO.getRemark())
                .imageUrls(updateReqVO.getImageUrls())
                .build();
        inspectionRecordItemMapper.updateById(updateObj);

        // 如果记录状态为待检，更新为检查中
        InspectionRecordDO record = inspectionRecordMapper.selectById(item.getRecordId());
        if (record != null && InspectionStatusEnum.PENDING.getStatus().equals(record.getStatus())) {
            InspectionRecordDO updateRecord = InspectionRecordDO.builder()
                    .id(record.getId())
                    .status(InspectionStatusEnum.IN_PROGRESS.getStatus())
                    .build();
            inspectionRecordMapper.updateById(updateRecord);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completeRecord(Long recordId, String inspectorName) {
        // 校验记录存在
        InspectionRecordDO record = inspectionRecordMapper.selectById(recordId);
        if (record == null) {
            throw exception(INSPECTION_RECORD_NOT_EXISTS);
        }

        // 校验未完成
        if (InspectionStatusEnum.COMPLETED.getStatus().equals(record.getStatus())) {
            throw exception(INSPECTION_RECORD_ALREADY_COMPLETED);
        }

        // 校验必填项是否全部完成
        List<InspectionRecordItemDO> items = inspectionRecordItemMapper.selectByRecordId(recordId);
        // 查询模板检查项获取必填信息
        List<InspectionTemplateItemDO> templateItems = inspectionTemplateItemMapper.selectByTemplateId(record.getTemplateId());
        for (InspectionTemplateItemDO templateItem : templateItems) {
            if (Integer.valueOf(1).equals(templateItem.getRequired())) {
                // 查找对应的记录检查项
                boolean hasResult = items.stream()
                        .filter(item -> item.getItemCode().equals(templateItem.getItemCode()))
                        .anyMatch(item -> item.getResult() != null);
                if (!hasResult) {
                    throw exception(INSPECTION_RECORD_REQUIRED_ITEMS_INCOMPLETE);
                }
            }
        }

        // 计算总体结果：如果有任一不通过则整体不通过，否则通过
        Integer overallResult = 1; // 默认通过
        for (InspectionRecordItemDO item : items) {
            if (item.getResult() != null && item.getResult() == 2) {
                overallResult = 2; // 不通过
                break;
            }
        }

        // 更新记录状态
        InspectionRecordDO updateRecord = InspectionRecordDO.builder()
                .id(recordId)
                .status(InspectionStatusEnum.COMPLETED.getStatus())
                .inspectorName(inspectorName)
                .inspectionTime(LocalDateTime.now())
                .overallResult(overallResult)
                .build();
        inspectionRecordMapper.updateById(updateRecord);
    }

    @Override
    public InspectionRecordDetailVO getRecordDetail(Long recordId) {
        InspectionRecordDO record = inspectionRecordMapper.selectById(recordId);
        if (record == null) {
            return null;
        }

        InspectionRecordDetailVO detailVO = InspectionConvert.INSTANCE.convertRecordDetail(record);

        // 查询检查项
        List<InspectionRecordItemDO> items = inspectionRecordItemMapper.selectByRecordId(recordId);
        detailVO.setItems(InspectionConvert.INSTANCE.convertRecordItemVOList(items));

        return detailVO;
    }

    @Override
    public InspectionRecordDO getLatestRecord(Long vehicleId, Integer sourceType) {
        return inspectionRecordMapper.selectLatestByVehicleAndSourceType(vehicleId, sourceType);
    }

    /**
     * 生成记录编码
     * 格式: {BC|JC|HC}-yyyyMMdd-{seq}
     */
    private String generateRecordCode(Integer sourceType) {
        String prefix;
        InspectionSourceTypeEnum sourceTypeEnum = InspectionSourceTypeEnum.valueOf(sourceType);
        if (sourceTypeEnum == null) {
            prefix = "YC";
        } else {
            switch (sourceTypeEnum) {
                case PREPARE:
                    prefix = "BC";
                    break;
                case DELIVERY:
                    prefix = "JC";
                    break;
                case RETURN:
                    prefix = "HC";
                    break;
                default:
                    prefix = "YC";
            }
        }

        String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        int seq = ThreadLocalRandom.current().nextInt(100, 999);
        return prefix + "-" + dateStr + "-" + String.format("%03d", seq);
    }

}
