package com.yushu.system.service.impl;

import com.yushu.common.utils.SecurityUtils;
import com.yushu.system.domain.SysErrorLog;
import com.yushu.system.mapper.SysErrorLogMapper;
import com.yushu.system.service.ISysErrorLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * 错误日志Service业务层处理
 * 
 * @author yushu
 */
@Service
public class SysErrorLogServiceImpl implements ISysErrorLogService {
    
    @Autowired
    private SysErrorLogMapper errorLogMapper;

    @Override
    public SysErrorLog selectErrorLogById(Long errorId) {
        return errorLogMapper.selectErrorLogById(errorId);
    }

    @Override
    public List<SysErrorLog> selectErrorLogList(SysErrorLog errorLog) {
        return errorLogMapper.selectErrorLogList(errorLog);
    }

    /**
     * 记录错误日志（异步、自动去重）
     * 相同错误只增加计数，不重复插入
     */
    @Async
    @Override
    public void recordError(SysErrorLog errorLog) {
        try {
            // 截断过长字段，防止数据库插入失败
            truncateFields(errorLog);
            
            // 生成错误签名（用于去重）
            String errorCode = generateErrorCode(errorLog);
            errorLog.setErrorCode(errorCode);
            
            // 查找是否存在相同错误
            SysErrorLog existing = errorLogMapper.selectBySignature(
                errorCode, 
                errorLog.getSourceClass(), 
                errorLog.getSourceMethod()
            );
            
            if (existing != null) {
                // 已存在，增加计数
                existing.setOccurCount(existing.getOccurCount() + 1);
                existing.setLastTime(new Date());
                errorLogMapper.updateErrorLog(existing);
            } else {
                // 新错误，插入记录
                errorLogMapper.insertErrorLog(errorLog);
            }
        } catch (Exception e) {
            // 记录日志本身出错，仅打印不抛出
            e.printStackTrace();
        }
    }
    
    /**
     * 截断过长字段（VARCHAR类型需要截断，TEXT类型无需）
     */
    private void truncateFields(SysErrorLog errorLog) {
        if (errorLog.getRequestUrl() != null && errorLog.getRequestUrl().length() > 500) {
            errorLog.setRequestUrl(errorLog.getRequestUrl().substring(0, 497) + "...");
        }
        if (errorLog.getUserAgent() != null && errorLog.getUserAgent().length() > 500) {
            errorLog.setUserAgent(errorLog.getUserAgent().substring(0, 497) + "...");
        }
        if (errorLog.getSourceClass() != null && errorLog.getSourceClass().length() > 200) {
            errorLog.setSourceClass(errorLog.getSourceClass().substring(0, 197) + "...");
        }
        if (errorLog.getSourceMethod() != null && errorLog.getSourceMethod().length() > 100) {
            errorLog.setSourceMethod(errorLog.getSourceMethod().substring(0, 97) + "...");
        }
    }

    @Override
    public int resolveError(Long errorId, String status, String remark) {
        SysErrorLog errorLog = new SysErrorLog();
        errorLog.setErrorId(errorId);
        errorLog.setStatus(status);
        errorLog.setResolveBy(SecurityUtils.getUsername());
        errorLog.setResolveTime(new Date());
        errorLog.setResolveRemark(remark);
        return errorLogMapper.updateErrorLog(errorLog);
    }

    @Override
    public int batchResolve(Long[] errorIds, String status, String remark) {
        int count = 0;
        for (Long errorId : errorIds) {
            count += resolveError(errorId, status, remark);
        }
        return count;
    }

    @Override
    public int deleteErrorLogByIds(Long[] errorIds) {
        return errorLogMapper.deleteErrorLogByIds(errorIds);
    }

    @Override
    public void cleanErrorLog() {
        errorLogMapper.cleanErrorLog();
    }

    @Override
    public int countUnresolved() {
        return errorLogMapper.countUnresolved();
    }

    /**
     * 生成错误代码（基于异常类型和消息的MD5）
     */
    private String generateErrorCode(SysErrorLog errorLog) {
        String source = errorLog.getErrorType() + ":" + 
                       errorLog.getSourceClass() + ":" + 
                       errorLog.getSourceMethod();
        // 简化：使用hashCode
        return "ERR" + Math.abs(source.hashCode());
    }
}
