package com.ruoyi.web.modules.diagnosis.support;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;
import java.util.List;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.diagnosis.domain.BizMedicalResource;

/**
 * 畜牧医疗资源入参校验。
 */
public final class MedicalResourceValidation
{
    private static final String PHONE_PATTERN = "^1[3-9]\\d{9}$";

    private static final DateTimeFormatter TIME_FMT = DateTimeFormatter.ofPattern("HH:mm");

    private MedicalResourceValidation()
    {
    }

    public static void validateListQuery(BizMedicalResource query)
    {
        if (query == null || StringUtils.isEmpty(query.getResourceType()))
        {
            throw new ServiceException("资源类型不能为空");
        }
        Integer ps = query.getQueryPublishStatus();
        if (ps != null && ps != MedicalResourceRules.QUERY_PUBLISH_UNPUBLISHED
                && ps != MedicalResourceRules.QUERY_PUBLISH_PUBLISHED
                && ps != MedicalResourceRules.QUERY_PUBLISH_OFFLINE)
        {
            throw new ServiceException("发布状态筛选无效");
        }
    }

    public static void trimFieldsForSave(BizMedicalResource row)
    {
        if (row == null)
        {
            return;
        }
        trim(row::getResourceName, row::setResourceName);
        trim(row::getIntroduction, row::setIntroduction);
        trim(row::getContactPhone, row::setContactPhone);
        trim(row::getAffiliatedUnit, row::setAffiliatedUnit);
        trim(row::getDetailAddress, row::setDetailAddress);
        trim(row::getServiceArea, row::setServiceArea);
        trim(row::getTeamMembers, row::setTeamMembers);
        trim(row::getPersonInCharge, row::setPersonInCharge);
        trim(row::getEquipmentModel, row::setEquipmentModel);
        trim(row::getPhotoFileUrl, row::setPhotoFileUrl);
        trim(row::getPhotoFilePath, row::setPhotoFilePath);
        trim(row::getServiceStartTime, row::setServiceStartTime);
        trim(row::getServiceEndTime, row::setServiceEndTime);
        if (row.getRemark() != null)
        {
            String r = row.getRemark().trim();
            row.setRemark(r.isEmpty() ? null : r);
        }
        if (row.getTeamMembers() != null && row.getTeamMembers().trim().isEmpty())
        {
            row.setTeamMembers(null);
        }
        blankToNull(row::getIntroduction, row::setIntroduction);
        blankToNull(row::getContactPhone, row::setContactPhone);
        blankToNull(row::getAffiliatedUnit, row::setAffiliatedUnit);
        blankToNull(row::getDetailAddress, row::setDetailAddress);
        blankToNull(row::getServiceArea, row::setServiceArea);
        if (StringUtils.isEmpty(row.getPhotoFileUrl()) && StringUtils.isEmpty(row.getPhotoFilePath()))
        {
            row.setPhotoFileUrl(null);
            row.setPhotoFilePath(null);
        }
        MedicalResourceMultiValueCodec.encodeLists(row);
    }

    private static void blankToNull(java.util.function.Supplier<String> getter,
            java.util.function.Consumer<String> setter)
    {
        String v = getter.get();
        if (v != null && v.trim().isEmpty())
        {
            setter.accept(null);
        }
    }

    private static void trim(java.util.function.Supplier<String> getter, java.util.function.Consumer<String> setter)
    {
        String v = getter.get();
        if (v != null)
        {
            setter.accept(v.trim());
        }
    }

    public static void validateResourceName(String name)
    {
        if (StringUtils.isEmpty(name)
                || name.length() < MedicalResourceRules.MIN_NAME_LEN
                || name.length() > MedicalResourceRules.MAX_NAME_LEN)
        {
            throw new ServiceException("资源名称须为1～10个字符");
        }
    }

    public static void validateIntroduction(String introduction, boolean required)
    {
        if (StringUtils.isEmpty(introduction))
        {
            if (required)
            {
                throw new ServiceException("请填写介绍");
            }
            return;
        }
        if (introduction.length() > MedicalResourceRules.MAX_INTRO_LEN)
        {
            throw new ServiceException("介绍不能超过500个字符");
        }
    }

    public static void validateIntroduction(String introduction)
    {
        validateIntroduction(introduction, true);
    }

    public static void validateContactPhone(String phone, boolean required)
    {
        if (StringUtils.isEmpty(phone))
        {
            if (required)
            {
                throw new ServiceException("请填写联系方式");
            }
            return;
        }
        if (!phone.matches(PHONE_PATTERN))
        {
            throw new ServiceException("联系方式格式不正确");
        }
    }

    public static void validateAffiliatedUnit(String unit, boolean required)
    {
        if (StringUtils.isEmpty(unit))
        {
            if (required)
            {
                throw new ServiceException("请填写隶属单位");
            }
            return;
        }
        if (unit.length() > MedicalResourceRules.MAX_UNIT_LEN)
        {
            throw new ServiceException("隶属单位不能超过20个字符");
        }
    }

    public static void validateDetailAddress(String address, boolean required)
    {
        if (StringUtils.isEmpty(address))
        {
            if (required)
            {
                throw new ServiceException("请填写详细地址");
            }
            return;
        }
        if (address.length() > MedicalResourceRules.MAX_ADDRESS_LEN)
        {
            throw new ServiceException("详细地址不能超过100个字符");
        }
    }

    public static void validateServiceArea(String area, boolean required)
    {
        if (StringUtils.isEmpty(area))
        {
            if (required)
            {
                throw new ServiceException("请填写服务区域");
            }
            return;
        }
        if (area.length() > MedicalResourceRules.MAX_SERVICE_AREA_LEN)
        {
            throw new ServiceException("服务区域不能超过100个字符");
        }
    }

    public static void validateFeeStandard(BigDecimal fee, boolean required)
    {
        if (fee == null)
        {
            if (required)
            {
                throw new ServiceException("请填写收费标准");
            }
            return;
        }
        if (fee.compareTo(BigDecimal.ZERO) <= 0)
        {
            throw new ServiceException("收费标准须为正数");
        }
    }

    public static void validateServiceTimeRange(String start, String end, boolean required)
    {
        if (StringUtils.isEmpty(start) || StringUtils.isEmpty(end))
        {
            if (required)
            {
                throw new ServiceException("请填写服务时段");
            }
            return;
        }
        try
        {
            LocalTime s = LocalTime.parse(start, TIME_FMT);
            LocalTime e = LocalTime.parse(end, TIME_FMT);
            if (e.isBefore(s))
            {
                throw new ServiceException("结束时间不能早于开始时间");
            }
        }
        catch (DateTimeParseException ex)
        {
            throw new ServiceException("服务时段格式须为 HH:mm");
        }
    }

    public static void validateServiceWeekdays(List<Integer> weekdays, boolean required)
    {
        if (weekdays == null || weekdays.isEmpty())
        {
            if (required)
            {
                throw new ServiceException("请至少选择一天服务周日");
            }
            return;
        }
        for (Integer d : weekdays)
        {
            if (d == null || d < 1 || d > 7)
            {
                throw new ServiceException("服务周日无效");
            }
        }
    }

    public static void validateConsultModes(List<Integer> modes, boolean required)
    {
        if (modes == null || modes.isEmpty())
        {
            if (required)
            {
                throw new ServiceException("请至少选择一种接诊方式");
            }
            return;
        }
        for (Integer m : modes)
        {
            if (m == null || m < MedicalResourceRules.CONSULT_MODE_FIXED
                    || m > MedicalResourceRules.CONSULT_MODE_ONLINE)
            {
                throw new ServiceException("接诊方式无效");
            }
        }
    }

    public static void validateMaxDailyAppointments(Integer max, boolean required)
    {
        if (max == null)
        {
            if (required)
            {
                throw new ServiceException("请填写单日最大接诊人数");
            }
            return;
        }
        if (max < 1)
        {
            throw new ServiceException("单日最大接诊人数须为正整数");
        }
    }

    public static void validateTeamSize(Integer size, boolean required)
    {
        if (size == null)
        {
            if (required)
            {
                throw new ServiceException("请填写团队规模");
            }
            return;
        }
        if (size < 1)
        {
            throw new ServiceException("团队规模须为正整数");
        }
    }

    public static void validateEstablishDate(Date date, boolean required)
    {
        if (date == null)
        {
            if (required)
            {
                throw new ServiceException("请填写成立时间");
            }
            return;
        }
        LocalDate d = new java.sql.Date(date.getTime()).toLocalDate();
        if (d.isAfter(LocalDate.now()))
        {
            throw new ServiceException("成立时间不能为未来日期");
        }
    }

    public static void validatePersonInCharge(String name, boolean required)
    {
        if (StringUtils.isEmpty(name))
        {
            if (required)
            {
                throw new ServiceException("请填写负责人");
            }
            return;
        }
        if (name.length() > MedicalResourceRules.MAX_NAME_LEN)
        {
            throw new ServiceException("负责人不能超过10个字符");
        }
    }

    public static void validateOrgLevel(Integer level, boolean required)
    {
        if (level == null)
        {
            if (required)
            {
                throw new ServiceException("请选择机构级别");
            }
            return;
        }
        if (level != MedicalResourceRules.ORG_LEVEL_CLINIC
                && level != MedicalResourceRules.ORG_LEVEL_HOSPITAL)
        {
            throw new ServiceException("机构级别无效");
        }
    }

    public static void validateEquipmentModel(String model, boolean required)
    {
        if (StringUtils.isEmpty(model))
        {
            if (required)
            {
                throw new ServiceException("请填写设备型号");
            }
            return;
        }
        if (model.length() > MedicalResourceRules.MAX_MODEL_LEN)
        {
            throw new ServiceException("设备型号不能超过10个字符");
        }
    }

    public static void validatePhotoPair(String url, String path, boolean required)
    {
        if (StringUtils.isEmpty(url) && StringUtils.isEmpty(path))
        {
            if (required)
            {
                throw new ServiceException("请上传照片");
            }
            return;
        }
        if (StringUtils.isEmpty(url) || StringUtils.isEmpty(path))
        {
            throw new ServiceException("请上传照片");
        }
        if (!MedicalResourceRules.isPhotoExtensionAllowed(path))
        {
            throw new ServiceException("仅支持 jpg/jpeg/png，且不超过 10MB");
        }
        if (!path.startsWith(Constants.RESOURCE_PREFIX))
        {
            throw new ServiceException("照片存储路径非法");
        }
    }

    public static void validatePhotoPair(String url, String path)
    {
        validatePhotoPair(url, path, true);
    }

    public static void validateRemark(String remark)
    {
        if (remark != null && remark.length() > MedicalResourceRules.MAX_REMARK_LEN)
        {
            throw new ServiceException("备注不能超过500个字符");
        }
    }

    public static void validateRowForSave(BizMedicalResource row)
    {
        trimFieldsForSave(row);
        validateResourceName(row.getResourceName());
        validateRemark(row.getRemark());
        String type = row.getResourceType();
        boolean vet = MedicalResourceRules.RESOURCE_TYPE_VET.equals(type);
        boolean team = MedicalResourceRules.RESOURCE_TYPE_TEAM.equals(type);
        boolean org = MedicalResourceRules.RESOURCE_TYPE_ORG.equals(type);
        boolean equipment = MedicalResourceRules.RESOURCE_TYPE_EQUIPMENT.equals(type);
        boolean optionalPhotoIntro = vet || team || org || equipment;
        validateIntroduction(row.getIntroduction(), !optionalPhotoIntro);
        validatePhotoPair(row.getPhotoFileUrl(), row.getPhotoFilePath(), !optionalPhotoIntro);
        if (vet)
        {
            validateVetFields(row);
        }
        else if (MedicalResourceRules.RESOURCE_TYPE_TEAM.equals(type))
        {
            clearTownFields(row);
            validateTeamFields(row);
        }
        else if (MedicalResourceRules.RESOURCE_TYPE_ORG.equals(type))
        {
            clearTownFields(row);
            validateOrgFields(row);
        }
        else if (MedicalResourceRules.RESOURCE_TYPE_EQUIPMENT.equals(type))
        {
            clearTownFields(row);
            validateEquipmentFields(row);
        }
        else
        {
            throw new ServiceException("资源类型无效");
        }
    }

    private static void clearTownFields(BizMedicalResource row)
    {
        row.setTownDeptId(null);
        row.setTownName(null);
    }

    private static void validateVetFields(BizMedicalResource row)
    {
        validateContactPhone(row.getContactPhone(), false);
        validateAffiliatedUnit(row.getAffiliatedUnit(), false);
        validateDetailAddress(row.getDetailAddress(), false);
        validateConsultModes(row.getConsultModesList(), true);
        validateServiceArea(row.getServiceArea(), false);
        validateFeeStandard(row.getFeeStandard(), false);
        validateServiceTimeRange(row.getServiceStartTime(), row.getServiceEndTime(), false);
        validateServiceWeekdays(row.getServiceWeekdaysList(), false);
        row.setMaxDailyAppointments(null);
    }

    private static void validateTeamFields(BizMedicalResource row)
    {
        validateContactPhone(row.getContactPhone(), false);
        validateAffiliatedUnit(row.getAffiliatedUnit(), false);
        validateEstablishDate(row.getEstablishDate(), false);
        validateTeamSize(row.getTeamSize(), false);
        validatePersonInCharge(row.getPersonInCharge(), false);
        if (row.getTeamMembers() != null
                && row.getTeamMembers().length() > MedicalResourceRules.MAX_TEAM_MEMBERS_LEN)
        {
            throw new ServiceException("团队成员不能超过500个字符");
        }
    }

    private static void validateOrgFields(BizMedicalResource row)
    {
        validateContactPhone(row.getContactPhone(), false);
        validateDetailAddress(row.getDetailAddress(), false);
        validateOrgLevel(row.getOrgLevel(), true);
        validatePersonInCharge(row.getPersonInCharge(), false);
        validateServiceTimeRange(row.getServiceStartTime(), row.getServiceEndTime(), false);
        validateServiceWeekdays(row.getServiceWeekdaysList(), false);
        validateMaxDailyAppointments(row.getMaxDailyAppointments(), false);
    }

    private static void validateEquipmentFields(BizMedicalResource row)
    {
        validateAffiliatedUnit(row.getAffiliatedUnit(), false);
        validateEquipmentModel(row.getEquipmentModel(), false);
    }

    public static void validateForUpdate(BizMedicalResource db)
    {
        if (db == null)
        {
            throw new ServiceException("记录不存在或已删除");
        }
        if (!MedicalResourceRules.canEdit(db.getPublishStatus()))
        {
            throw new ServiceException("已发布资源请先下架后再编辑");
        }
    }

    public static void validateForDelete(BizMedicalResource db)
    {
        if (db == null)
        {
            throw new ServiceException("记录不存在或已删除");
        }
        if (!MedicalResourceRules.canDelete(db.getPublishStatus()))
        {
            throw new ServiceException("已发布资源请先下架后再删除");
        }
    }

    public static void validateForPublish(BizMedicalResource db)
    {
        if (db == null)
        {
            throw new ServiceException("记录不存在或已删除");
        }
        if (!MedicalResourceRules.canPublish(db.getPublishStatus()))
        {
            throw new ServiceException("该资源已发布");
        }
    }

    public static void validateForOffline(BizMedicalResource db)
    {
        if (db == null)
        {
            throw new ServiceException("记录不存在或已删除");
        }
        if (!MedicalResourceRules.canOffline(db.getPublishStatus()))
        {
            throw new ServiceException("仅已发布资源可下架");
        }
    }

    public static void validateForAssignAccount(BizMedicalResource db)
    {
        if (db == null)
        {
            throw new ServiceException("记录不存在或已删除");
        }
        if (!MedicalResourceRules.canAssignAccount(db.getResourceType()))
        {
            throw new ServiceException("该资源类型不支持分配账号");
        }
        if (!MedicalResourceRules.canEdit(db.getPublishStatus()))
        {
            throw new ServiceException("已发布资源请先下架后再操作");
        }
        if (db.getAccountAssigned() != null
                && db.getAccountAssigned() == MedicalResourceRules.ACCOUNT_ASSIGNED_YES)
        {
            throw new ServiceException("该资源已分配账号，不可重复分配");
        }
    }

    public static void validateResourceTypeUnchanged(BizMedicalResource db, BizMedicalResource input)
    {
        if (input.getResourceType() != null && !input.getResourceType().equals(db.getResourceType()))
        {
            throw new ServiceException("资源类型保存后不可变更");
        }
    }
}
