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

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Pattern;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.industrypolicy.domain.BizSubsidyGrantRecord;

/**
 * 补贴发放记录入参校验。
 */
public final class SubsidyGrantRecordValidation
{
    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");

    private static final Pattern BANK_ACCOUNT_PATTERN = Pattern.compile("^\\d{16,19}$");

    private static final Pattern ID_CARD_PATTERN = Pattern.compile(
            "^[1-9]\\d{5}(19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dXx]$");

    private static final int[] ID_CARD_WEIGHT = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };

    private static final char[] ID_CARD_CHECK = { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };

    private SubsidyGrantRecordValidation()
    {
    }

    public static void trimFieldsForSave(BizSubsidyGrantRecord row)
    {
        if (row == null)
        {
            return;
        }
        if (row.getSubsidyProjectName() != null)
        {
            row.setSubsidyProjectName(row.getSubsidyProjectName().trim());
        }
        if (row.getRecipientName() != null)
        {
            row.setRecipientName(row.getRecipientName().trim());
        }
        if (row.getIdCard() != null)
        {
            row.setIdCard(normalizeIdCard(row.getIdCard()));
        }
        if (row.getContactPhone() != null)
        {
            row.setContactPhone(row.getContactPhone().trim());
        }
        if (row.getBankAccount() != null)
        {
            row.setBankAccount(row.getBankAccount().trim());
        }
        if (row.getRemark() != null)
        {
            String remark = row.getRemark().trim();
            row.setRemark(remark.isEmpty() ? null : remark);
        }
    }

    public static void validateSubsidyProjectName(String name)
    {
        if (StringUtils.isEmpty(name) || name.length() < 1 || name.length() > 20)
        {
            throw new ServiceException("补贴项目名称须为1～20个字符");
        }
    }

    public static void validateRecipientName(String name)
    {
        if (StringUtils.isEmpty(name) || name.length() < 1 || name.length() > 10)
        {
            throw new ServiceException("受补贴人姓名须为1～10个字符");
        }
    }

    public static void validateSubsidyType(Integer subsidyType)
    {
        if (subsidyType == null || subsidyType < 1 || subsidyType > 3)
        {
            throw new ServiceException("补贴类型须为1～3（1农业生产2住房基建3民生保障）");
        }
    }

    public static void validateIdCard(String idCard)
    {
        if (StringUtils.isEmpty(idCard))
        {
            throw new ServiceException("身份证号不能为空");
        }
        String normalized = normalizeIdCard(idCard);
        if (SubsidyGrantRecordMasking.isMaskedValue(normalized))
        {
            throw new ServiceException("请填写完整18位身份证号，不能使用脱敏后的号码");
        }
        if (!ID_CARD_PATTERN.matcher(normalized).matches())
        {
            throw new ServiceException("身份证号格式不正确");
        }
        if (!isIdCardChecksumValid(normalized))
        {
            throw new ServiceException("身份证号校验位不正确");
        }
    }

    /**
     * 规范化身份证号：去空白、全角数字转半角、末位 x 转 X。
     */
    public static String normalizeIdCard(String idCard)
    {
        if (idCard == null)
        {
            return null;
        }
        String trimmed = idCard.trim();
        if (trimmed.isEmpty())
        {
            return trimmed;
        }
        StringBuilder sb = new StringBuilder(trimmed.length());
        for (int i = 0; i < trimmed.length(); i++)
        {
            char c = trimmed.charAt(i);
            if (c == ' ' || c == '\t' || c == '\u00A0')
            {
                continue;
            }
            if (c >= '０' && c <= '９')
            {
                sb.append((char) ('0' + (c - '０')));
            }
            else if (c == 'Ｘ' || c == 'ｘ')
            {
                sb.append('X');
            }
            else
            {
                sb.append(c);
            }
        }
        return sb.toString().toUpperCase();
    }

    public static void validateContactPhone(String phone)
    {
        if (StringUtils.isEmpty(phone) || !PHONE_PATTERN.matcher(phone.trim()).matches())
        {
            throw new ServiceException("联系电话须为合法的大陆手机号");
        }
    }

    public static void validateBankAccount(String bankAccount)
    {
        if (StringUtils.isEmpty(bankAccount) || !BANK_ACCOUNT_PATTERN.matcher(bankAccount.trim()).matches())
        {
            throw new ServiceException("银行账户须为16～19位数字");
        }
    }

    public static void validateSubsidyAmount(BigDecimal amount)
    {
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0)
        {
            throw new ServiceException("补贴金额须大于0");
        }
        if (amount.scale() > 2)
        {
            throw new ServiceException("补贴金额最多保留2位小数");
        }
        BigDecimal stripped = amount.stripTrailingZeros();
        if (stripped.scale() > 2)
        {
            throw new ServiceException("补贴金额最多保留2位小数");
        }
    }

    public static void validateGrantDate(Date grantDate)
    {
        if (grantDate == null)
        {
            throw new ServiceException("发放日期不能为空");
        }
        Calendar today = Calendar.getInstance();
        truncateToDay(today);
        Calendar grant = Calendar.getInstance();
        grant.setTime(grantDate);
        truncateToDay(grant);
        if (grant.after(today))
        {
            throw new ServiceException("发放日期不能为未来日期");
        }
    }

    public static void validateDateRange(String startDate, String endDate)
    {
        boolean hasStart = StringUtils.isNotEmpty(startDate);
        boolean hasEnd = StringUtils.isNotEmpty(endDate);
        if (!hasStart && !hasEnd)
        {
            return;
        }
        Date start = hasStart ? parseQueryDate(startDate, "开始日期") : null;
        Date end = hasEnd ? parseQueryDate(endDate, "结束日期") : null;
        if (start != null && end != null && start.after(end))
        {
            throw new ServiceException("发放日期开始不能晚于结束");
        }
    }

    /**
     * 修改时若前端回传脱敏后的身份证/手机/银行卡，则保留库内原值。
     */
    public static void mergeSensitiveFieldsForUpdate(BizSubsidyGrantRecord incoming, BizSubsidyGrantRecord db)
    {
        if (incoming == null || db == null)
        {
            return;
        }
        mergeIdCardForUpdate(incoming, db);
        mergePhoneForUpdate(incoming, db);
        mergeBankAccountForUpdate(incoming, db);
    }

    private static void mergeIdCardForUpdate(BizSubsidyGrantRecord incoming, BizSubsidyGrantRecord db)
    {
        String in = normalizeIdCard(incoming.getIdCard());
        String stored = normalizeIdCard(db.getIdCard());
        if (StringUtils.isEmpty(stored))
        {
            return;
        }
        if (StringUtils.isEmpty(in)
                || SubsidyGrantRecordMasking.isMaskedValue(in)
                || SubsidyGrantRecordMasking.equalsMasked(stored, in))
        {
            incoming.setIdCard(stored);
        }
    }

    private static void mergePhoneForUpdate(BizSubsidyGrantRecord incoming, BizSubsidyGrantRecord db)
    {
        String in = incoming.getContactPhone();
        if (StringUtils.isEmpty(db.getContactPhone()))
        {
            return;
        }
        if (SubsidyGrantRecordMasking.isMaskedValue(in)
                || SubsidyGrantRecordMasking.maskPhone(db.getContactPhone()).equals(in))
        {
            incoming.setContactPhone(db.getContactPhone());
        }
    }

    private static void mergeBankAccountForUpdate(BizSubsidyGrantRecord incoming, BizSubsidyGrantRecord db)
    {
        String in = incoming.getBankAccount();
        if (StringUtils.isEmpty(db.getBankAccount()))
        {
            return;
        }
        if (SubsidyGrantRecordMasking.isMaskedValue(in)
                || SubsidyGrantRecordMasking.maskBankAccount(db.getBankAccount()).equals(in))
        {
            incoming.setBankAccount(db.getBankAccount());
        }
    }

    public static void validateRowForSave(BizSubsidyGrantRecord row)
    {
        trimFieldsForSave(row);
        validateSubsidyProjectName(row.getSubsidyProjectName());
        validateSubsidyType(row.getSubsidyType());
        validateRecipientName(row.getRecipientName());
        validateIdCard(row.getIdCard());
        validateContactPhone(row.getContactPhone());
        validateBankAccount(row.getBankAccount());
        validateSubsidyAmount(row.getSubsidyAmount());
        validateGrantDate(row.getGrantDate());
    }

    public static boolean isIdCardChecksumValid(String idCard)
    {
        int sum = 0;
        for (int i = 0; i < 17; i++)
        {
            sum += (idCard.charAt(i) - '0') * ID_CARD_WEIGHT[i];
        }
        char expected = ID_CARD_CHECK[sum % 11];
        char actual = Character.toUpperCase(idCard.charAt(17));
        return expected == actual;
    }

    private static Date parseQueryDate(String text, String label)
    {
        Date date = DateUtils.parseDate(text);
        if (date == null)
        {
            throw new ServiceException(label + "格式不正确，须为 yyyy-MM-dd");
        }
        return date;
    }

    private static void truncateToDay(Calendar cal)
    {
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
    }
}
