package com.aegis.emergency.plan.service.impl;

import com.aegis.common.exception.ServiceException;
import com.aegis.emergency.plan.domain.Plan;
import com.aegis.emergency.plan.domain.PlanParticipant;
import com.aegis.emergency.plan.domain.PlanStep;
import com.aegis.emergency.plan.domain.PlanStepResource;
import com.aegis.emergency.plan.domain.PlanVersion;
import com.aegis.emergency.plan.domain.PlanVersionSnapshot;
import com.aegis.emergency.plan.mapper.PlanMapper;
import com.aegis.emergency.plan.mapper.PlanVersionMapper;
import com.aegis.emergency.plan.service.IPlanParticipantService;
import com.aegis.emergency.plan.service.IPlanStepResourceService;
import com.aegis.emergency.plan.service.IPlanStepService;
import com.aegis.emergency.plan.service.IPlanVersionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;

/**
 * 预案版本 Service 实现
 */
@Service
public class PlanVersionServiceImpl extends ServiceImpl<PlanVersionMapper, PlanVersion> implements IPlanVersionService {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    private final PlanMapper planMapper;
    private final IPlanParticipantService participantService;
    private final IPlanStepService stepService;
    private final IPlanStepResourceService stepResourceService;

    public PlanVersionServiceImpl(PlanMapper planMapper,
                                  IPlanParticipantService participantService,
                                  IPlanStepService stepService,
                                  IPlanStepResourceService stepResourceService) {
        this.planMapper = planMapper;
        this.participantService = participantService;
        this.stepService = stepService;
        this.stepResourceService = stepResourceService;
    }

    @Override
    public PlanVersion createVersion(PlanVersion version) {
        Objects.requireNonNull(version, "version must not be null");
        Objects.requireNonNull(version.getPlanId(), "planId must not be null");
        PlanVersionSnapshot snapshot = buildSnapshot(version.getPlanId());
        try {
            version.setSnapshot(OBJECT_MAPPER.writeValueAsString(snapshot));
        } catch (JsonProcessingException e) {
            throw new ServiceException("保存版本快照失败").setDetailMessage(e.getMessage());
        }
        this.save(version);
        return version;
    }

    @Override
    public List<PlanVersion> listByPlanId(Long planId) {
        if (planId == null) {
            return Collections.emptyList();
        }
        return this.lambdaQuery()
            .eq(PlanVersion::getPlanId, planId)
            .orderByDesc(PlanVersion::getCreateTime)
            .list();
    }

    @Override
    public PlanVersion findById(Long id) {
        if (id == null) {
            return null;
        }
        return this.getById(id);
    }

    @Override
    public boolean restoreVersion(Long planId, Long versionId) {
        if (planId == null || versionId == null) {
            throw new ServiceException("预案ID或版本ID不能为空");
        }
        PlanVersion version = this.getById(versionId);
        if (version == null || !planId.equals(version.getPlanId())) {
            throw new ServiceException("版本不存在");
        }
        if (version.getSnapshot() == null) {
            throw new ServiceException("该版本没有快照数据，无法恢复");
        }
        PlanVersionSnapshot snapshot;
        try {
            snapshot = OBJECT_MAPPER.readValue(version.getSnapshot(), PlanVersionSnapshot.class);
        } catch (JsonProcessingException e) {
            throw new ServiceException("解析版本快照失败").setDetailMessage(e.getMessage());
        }
        applySnapshot(planId, snapshot);
        return true;
    }

    private PlanVersionSnapshot buildSnapshot(Long planId) {
        Plan plan = planMapper.selectById(planId);
        if (plan == null) {
            throw new ServiceException("预案不存在");
        }
        PlanVersionSnapshot snapshot = new PlanVersionSnapshot();
        snapshot.setPlan(plan);
        snapshot.setParticipants(participantService.listByPlanId(planId));

        List<PlanStep> steps = stepService.listByPlanId(planId);
        List<PlanVersionSnapshot.StepSnapshot> stepSnapshots = steps.stream()
            .map(step -> {
                PlanVersionSnapshot.StepSnapshot ss = new PlanVersionSnapshot.StepSnapshot();
                ss.setStep(step);
                ss.setResources(stepResourceService.listByStepId(step.getId()));
                return ss;
            })
            .collect(Collectors.toList());
        snapshot.setSteps(stepSnapshots);
        return snapshot;
    }

    private void applySnapshot(Long planId, PlanVersionSnapshot snapshot) {
        if (snapshot == null || snapshot.getPlan() == null) {
            throw new ServiceException("快照数据不完整，无法恢复");
        }
        Plan snapshotPlan = snapshot.getPlan();
        snapshotPlan.setId(planId);
        snapshotPlan.setUpdateTime(new java.util.Date());
        planMapper.updateById(snapshotPlan);

        // Restore participants
        participantService.removeByPlanId(planId);
        List<PlanParticipant> participants = snapshot.getParticipants();
        if (participants != null && !participants.isEmpty()) {
            List<PlanParticipant> newParticipants = new ArrayList<>();
            for (PlanParticipant participant : participants) {
                PlanParticipant copy = new PlanParticipant();
                copy.setPlanId(planId);
                copy.setParticipantType(participant.getParticipantType());
                copy.setReferenceTeamId(participant.getReferenceTeamId());
                copy.setReferenceMemberId(participant.getReferenceMemberId());
                copy.setReferenceExpertId(participant.getReferenceExpertId());
                copy.setDisplayName(participant.getDisplayName());
                copy.setRole(participant.getRole());
                copy.setContactSnapshot(participant.getContactSnapshot());
                copy.setSortOrder(participant.getSortOrder());
                copy.setRemark(participant.getRemark());
                copy.setDelFlag("0");
                newParticipants.add(copy);
            }
            participantService.saveBatch(newParticipants);
        }

        // Restore steps and resources
        stepResourceService.removeByPlanId(planId);
        stepService.removeByPlanId(planId);

        List<PlanVersionSnapshot.StepSnapshot> stepSnapshots = snapshot.getSteps();
        if (stepSnapshots != null && !stepSnapshots.isEmpty()) {
            for (PlanVersionSnapshot.StepSnapshot stepSnapshot : stepSnapshots) {
                PlanStep originalStep = stepSnapshot.getStep();
                if (originalStep == null) {
                    continue;
                }
                PlanStep stepCopy = new PlanStep();
                stepCopy.setPlanId(planId);
                stepCopy.setStepName(originalStep.getStepName());
                stepCopy.setStepOrder(originalStep.getStepOrder());
                stepCopy.setDescription(originalStep.getDescription());
                stepCopy.setSuggestedParticipantId(originalStep.getSuggestedParticipantId());
                stepCopy.setEstimatedDuration(originalStep.getEstimatedDuration());
                stepCopy.setCreateBy(originalStep.getCreateBy());
                stepCopy.setCreateTime(originalStep.getCreateTime());
                stepCopy.setUpdateBy(originalStep.getUpdateBy());
                stepCopy.setUpdateTime(originalStep.getUpdateTime());
                stepCopy.setDelFlag("0");
                stepService.save(stepCopy);

                List<PlanStepResource> resources = stepSnapshot.getResources();
                if (resources != null && !resources.isEmpty()) {
                    List<PlanStepResource> resourceCopies = new ArrayList<>();
                    for (PlanStepResource resource : resources) {
                        PlanStepResource resourceCopy = new PlanStepResource();
                        resourceCopy.setPlanId(planId);
                        resourceCopy.setStepId(stepCopy.getId());
                        resourceCopy.setResourceType(resource.getResourceType());
                        resourceCopy.setResourceRefId(resource.getResourceRefId());
                        resourceCopy.setSuggestedQuantity(resource.getSuggestedQuantity());
                        resourceCopy.setRequired(resource.getRequired());
                        resourceCopy.setUsageNote(resource.getUsageNote());
                        resourceCopy.setDelFlag("0");
                        resourceCopies.add(resourceCopy);
                    }
                    stepResourceService.saveBatch(resourceCopies);
                }
            }
        }
    }
}