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

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.exception.ServiceException;
import com.ruoyi.web.modules.diagnosis.domain.BizServiceAppointment;
import com.ruoyi.web.modules.diagnosis.mapper.BizServiceAppointmentMapper;
import com.ruoyi.web.modules.diagnosis.support.ServiceAppointmentRules;
import com.ruoyi.web.modules.diagnosis.support.VetAppointmentStatusResolver;
import com.ruoyi.web.modules.farming.domain.BizServiceAppointmentReview;
import com.ruoyi.web.modules.farming.mapper.BizServiceAppointmentReviewMapper;
import com.ruoyi.web.modules.farming.service.IBizExpertMyAppointmentService;
import com.ruoyi.web.modules.farming.support.ExpertAppointmentValidation;
import com.ruoyi.web.modules.farming.support.ExpertProviderResolver;

/**
 * 我的预约（专家）服务实现。
 */
@Service
public class BizExpertMyAppointmentServiceImpl implements IBizExpertMyAppointmentService
{
    @Autowired
    private BizServiceAppointmentMapper bizServiceAppointmentMapper;

    @Autowired
    private BizServiceAppointmentReviewMapper bizServiceAppointmentReviewMapper;

    @Autowired
    private ExpertProviderResolver expertProviderResolver;

    @Override
    public List<BizServiceAppointment> selectExpertAppointmentList(BizServiceAppointment query, Long sysUserId)
    {
        Long providerId = expertProviderResolver.resolveProviderId(sysUserId);
        if (providerId == null)
        {
            return new ArrayList<>();
        }
        ExpertAppointmentValidation.validateListQuery(query);
        BizServiceAppointment criteria = query != null ? query : new BizServiceAppointment();
        criteria.setProviderType(ServiceAppointmentRules.PROVIDER_TYPE_EXPERT);
        criteria.setProviderId(providerId);
        List<BizServiceAppointment> list = bizServiceAppointmentMapper.selectExpertAppointmentList(criteria);
        if (list != null)
        {
            for (BizServiceAppointment row : list)
            {
                enrichRow(row);
            }
        }
        return list != null ? list : new ArrayList<>();
    }

    @Override
    public BizServiceAppointment selectExpertAppointmentById(Long id, Long sysUserId)
    {
        BizServiceAppointment row = loadOwnedRow(id, sysUserId, false);
        enrichRow(row);
        attachLatestReviewIfCompleted(row);
        return row;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int confirm(Long id, Long sysUserId, String operator)
    {
        BizServiceAppointment owned = loadOwnedRow(id, sysUserId, true);
        assertPendingForAction(owned, true);
        Date now = new Date();
        BizServiceAppointment patch = new BizServiceAppointment();
        patch.setId(id);
        patch.setProviderId(owned.getProviderId());
        patch.setConfirmTime(now);
        patch.setUpdateBy(operator);
        patch.setUpdateTime(now);
        int rows = bizServiceAppointmentMapper.updateConfirmExpertAppointment(patch);
        if (rows <= 0)
        {
            throwStatusChanged(owned.getId(), owned.getProviderId(), true);
        }
        return rows;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int reject(Long id, String rejectReason, Long sysUserId, String operator)
    {
        String reason = ExpertAppointmentValidation.trimRejectReason(rejectReason);
        ExpertAppointmentValidation.validateRejectReason(reason);
        BizServiceAppointment owned = loadOwnedRow(id, sysUserId, true);
        assertPendingForAction(owned, false);
        Date now = new Date();
        BizServiceAppointment patch = new BizServiceAppointment();
        patch.setId(id);
        patch.setProviderId(owned.getProviderId());
        patch.setRejectReason(reason);
        patch.setRejectTime(now);
        patch.setUpdateBy(operator);
        patch.setUpdateTime(now);
        int rows = bizServiceAppointmentMapper.updateRejectExpertAppointment(patch);
        if (rows <= 0)
        {
            throwStatusChanged(owned.getId(), owned.getProviderId(), false);
        }
        return rows;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int complete(Long id, Long sysUserId, String operator)
    {
        BizServiceAppointment owned = loadOwnedRow(id, sysUserId, true);
        assertCanComplete(owned);
        Date now = new Date();
        BizServiceAppointment patch = new BizServiceAppointment();
        patch.setId(id);
        patch.setProviderId(owned.getProviderId());
        patch.setUpdateBy(operator);
        patch.setUpdateTime(now);
        int rows = bizServiceAppointmentMapper.updateCompleteExpertAppointment(patch);
        if (rows <= 0)
        {
            throwCompleteNotAllowed(owned.getId(), owned.getProviderId());
        }
        return rows;
    }

    @Override
    public List<BizServiceAppointmentReview> selectReviewList(Long appointmentId, Long sysUserId)
    {
        BizServiceAppointment owned = loadOwnedRow(appointmentId, sysUserId, false);
        if (owned.getStatus() == null || owned.getStatus() != ServiceAppointmentRules.STATUS_COMPLETED)
        {
            throw new ServiceException("仅已完成预约可查看评价");
        }
        List<BizServiceAppointmentReview> list =
                bizServiceAppointmentReviewMapper.selectReviewListByAppointmentId(appointmentId);
        return list != null ? list : new ArrayList<>();
    }

    private BizServiceAppointment loadOwnedRow(Long id, Long sysUserId, boolean forWrite)
    {
        if (id == null)
        {
            throw new ServiceException("预约记录不存在");
        }
        Long providerId = expertProviderResolver.resolveProviderId(sysUserId);
        if (providerId == null)
        {
            if (forWrite)
            {
                throw new ServiceException("未绑定专家资源，无法操作");
            }
            throw new ServiceException("未绑定专家资源，无法查询预约");
        }
        BizServiceAppointment row = bizServiceAppointmentMapper.selectExpertAppointmentByIdAndProvider(id, providerId);
        if (row == null)
        {
            throw new ServiceException(forWrite ? "无权操作该预约记录" : "无权查看该预约记录");
        }
        return row;
    }

    private static void assertPendingForAction(BizServiceAppointment row, boolean confirm)
    {
        if (row.getStatus() == null)
        {
            throw new ServiceException(confirm ? "当前状态不允许确认接诊" : "当前状态不允许拒绝接诊");
        }
        if (row.getStatus() == ServiceAppointmentRules.STATUS_CANCELLED)
        {
            throw new ServiceException("该预约已取消，无法操作");
        }
        if (!ServiceAppointmentRules.canConfirmOrReject(row.getStatus()))
        {
            throw new ServiceException(confirm ? "当前状态不允许确认接诊" : "当前状态不允许拒绝接诊");
        }
    }

    private void throwStatusChanged(Long id, Long providerId, boolean confirm)
    {
        BizServiceAppointment latest =
                bizServiceAppointmentMapper.selectExpertAppointmentByIdAndProvider(id, providerId);
        if (latest != null && latest.getStatus() != null
                && latest.getStatus() == ServiceAppointmentRules.STATUS_CANCELLED)
        {
            throw new ServiceException("该预约已取消，无法操作");
        }
        throw new ServiceException(confirm ? "当前状态不允许确认接诊" : "当前状态不允许拒绝接诊");
    }

    private static void assertCanComplete(BizServiceAppointment row)
    {
        if (row.getStatus() == null)
        {
            throw new ServiceException("当前状态不允许完成接诊");
        }
        if (row.getStatus() == ServiceAppointmentRules.STATUS_CANCELLED)
        {
            throw new ServiceException("该预约已取消，无法操作");
        }
        if (!ServiceAppointmentRules.canCompleteVetOrExpert(row.getStatus()))
        {
            throw new ServiceException("当前状态不允许完成接诊");
        }
    }

    private void throwCompleteNotAllowed(Long id, Long providerId)
    {
        BizServiceAppointment latest =
                bizServiceAppointmentMapper.selectExpertAppointmentByIdAndProvider(id, providerId);
        if (latest != null && latest.getStatus() != null
                && latest.getStatus() == ServiceAppointmentRules.STATUS_CANCELLED)
        {
            throw new ServiceException("该预约已取消，无法操作");
        }
        throw new ServiceException("当前状态不允许完成接诊");
    }

    private static void enrichRow(BizServiceAppointment row)
    {
        if (row == null)
        {
            return;
        }
        row.setStatusLabel(VetAppointmentStatusResolver.resolveLabel(row.getStatus()));
        if (row.getStatus() != null)
        {
            row.setCanComplete(Boolean.valueOf(ServiceAppointmentRules.canCompleteVetOrExpert(row.getStatus())));
        }
    }

    private void attachLatestReviewIfCompleted(BizServiceAppointment row)
    {
        if (row == null || row.getStatus() == null
                || row.getStatus() != ServiceAppointmentRules.STATUS_COMPLETED)
        {
            return;
        }
        BizServiceAppointmentReview latest =
                bizServiceAppointmentReviewMapper.selectLatestReviewByAppointmentId(row.getId());
        if (latest == null)
        {
            return;
        }
        row.setPunctualityScore(latest.getPunctualityScore());
        row.setAttitudeScore(latest.getAttitudeScore());
        row.setGuidanceScore(latest.getGuidanceScore());
        row.setSummary(latest.getSummary());
    }
}
