package com.njcn.gather.systemmonitor.disk.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.gather.systemmonitor.disk.component.DiskMonitorNotificationComponent;
import com.njcn.gather.systemmonitor.disk.constant.DiskMonitorConstant;
import com.njcn.gather.systemmonitor.disk.enums.DiskMonitorResponseEnum;
import com.njcn.gather.systemmonitor.disk.mapper.DiskMonitorJobMapper;
import com.njcn.gather.systemmonitor.disk.mapper.DiskMonitorNotifyLogMapper;
import com.njcn.gather.systemmonitor.disk.mapper.DiskMonitorPolicyMapper;
import com.njcn.gather.systemmonitor.disk.mapper.DiskMonitorResultMapper;
import com.njcn.gather.systemmonitor.disk.mapper.DiskMonitorTargetMapper;
import com.njcn.gather.systemmonitor.disk.pojo.param.DiskMonitorParam;
import com.njcn.gather.systemmonitor.disk.pojo.po.DiskMonitorJob;
import com.njcn.gather.systemmonitor.disk.pojo.po.DiskMonitorNotifyLog;
import com.njcn.gather.systemmonitor.disk.pojo.po.DiskMonitorPolicy;
import com.njcn.gather.systemmonitor.disk.pojo.po.DiskMonitorResult;
import com.njcn.gather.systemmonitor.disk.pojo.po.DiskMonitorTarget;
import com.njcn.gather.systemmonitor.disk.pojo.vo.DiskMonitorVO;
import com.njcn.gather.systemmonitor.disk.service.IDiskMonitorJobService;
import com.njcn.gather.systemmonitor.disk.service.IDiskMonitorPolicyService;
import com.njcn.web.factory.PageFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 磁盘监控任务服务实现。
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DiskMonitorJobServiceImpl implements IDiskMonitorJobService {

    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    private final IDiskMonitorPolicyService diskMonitorPolicyService;
    private final DiskMonitorNotificationComponent diskMonitorNotificationComponent;
    private final DiskMonitorJobMapper jobMapper;
    private final DiskMonitorResultMapper resultMapper;
    private final DiskMonitorNotifyLogMapper notifyLogMapper;
    private final DiskMonitorTargetMapper targetMapper;
    private final DiskMonitorPolicyMapper policyMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DiskMonitorVO.JobRunVO runJob(DiskMonitorParam.JobRunParam param) {
        String jobSource = StrUtil.blankToDefault(param.getJobSource(), DiskMonitorConstant.JOB_SOURCE_MANUAL).trim().toUpperCase();
        if (!DiskMonitorConstant.JOB_SOURCE_MANUAL.equals(jobSource)) {
            throw new BusinessException(DiskMonitorResponseEnum.JOB_SOURCE_INVALID);
        }
        return executeMonitorJob(jobSource, null, false, true);
    }

    @Override
    public Page<DiskMonitorVO.JobListVO> listJobs(DiskMonitorParam.JobListParam param) {
        Page<DiskMonitorJob> page = jobMapper.selectPage(
                new Page<>(PageFactory.getPageNum(param), PageFactory.getPageSize(param)),
                new QueryWrapper<DiskMonitorJob>().orderByDesc("started_at", "id")
        );
        Page<DiskMonitorVO.JobListVO> resultPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        resultPage.setRecords(page.getRecords().stream().map(this::toJobListVO).collect(Collectors.toList()));
        return resultPage;
    }

    @Override
    public DiskMonitorVO.JobDetailVO getJobDetail(Long jobId) {
        DiskMonitorJob job = jobMapper.selectById(jobId);
        if (job == null) {
            throw new BusinessException(DiskMonitorResponseEnum.JOB_NOT_FOUND);
        }
        DiskMonitorVO.JobDetailVO detailVO = new DiskMonitorVO.JobDetailVO();
        detailVO.setJob(toJobInfoVO(job));
        List<DiskMonitorResult> results = resultMapper.selectList(new QueryWrapper<DiskMonitorResult>()
                .eq("job_id", jobId)
                .orderByAsc("scan_time", "id"));
        detailVO.setResults(results.stream().map(this::toResultVO).collect(Collectors.toList()));
        List<DiskMonitorNotifyLog> notifyLogs = notifyLogMapper.selectList(new QueryWrapper<DiskMonitorNotifyLog>()
                .eq("job_id", jobId)
                .orderByAsc("sent_at", "id"));
        detailVO.setNotifyLogs(notifyLogs.stream().map(this::toNotifyLogVO).collect(Collectors.toList()));
        return detailVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void executeAppStartMonitor() {
        DiskMonitorPolicy policy = diskMonitorPolicyService.getOrCreatePolicy();
        if (!isEnabled(policy.getMonitorEnabled()) || !isEnabled(policy.getRunOnAppStart())) {
            return;
        }
        executeMonitorJob(DiskMonitorConstant.JOB_SOURCE_APP_START, null, false, false);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void executeDailyScheduleMonitor() {
        DiskMonitorPolicy policy = diskMonitorPolicyService.getOrCreatePolicy();
        if (!isEnabled(policy.getMonitorEnabled()) || policy.getDailyRunTime() == null) {
            return;
        }
        executeMonitorJob(DiskMonitorConstant.JOB_SOURCE_DAILY_SCHEDULE, null, false, false);
    }

    @Override
    public LocalDateTime getNextDailyRunTime() {
        DiskMonitorPolicy policy = diskMonitorPolicyService.getOrCreatePolicy();
        if (!isEnabled(policy.getMonitorEnabled()) || policy.getDailyRunTime() == null) {
            return null;
        }
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime candidate = LocalDate.now().atTime(policy.getDailyRunTime());
        if (!candidate.isAfter(now)) {
            candidate = candidate.plusDays(1);
        }
        return candidate;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void executeNotifyTest(String driveLetter) {
        executeMonitorJob(DiskMonitorConstant.JOB_SOURCE_MANUAL, driveLetter, true, true);
    }

    private DiskMonitorVO.JobRunVO executeMonitorJob(String jobSource, String driveLetter, boolean forceNotify, boolean failWhenNoTarget) {
        validateJobSource(jobSource);
        List<DiskMonitorTarget> targets = resolveExecutionTargets(driveLetter);
        if (targets.isEmpty()) {
            logNoExecutionTargets(jobSource, driveLetter);
            if (failWhenNoTarget) {
                throw new BusinessException(DiskMonitorResponseEnum.NO_ENABLED_TARGET);
            }
            return null;
        }

        LocalDateTime now = LocalDateTime.now();
        DiskMonitorJob job = new DiskMonitorJob();
        job.setJobNo(generateJobNo());
        job.setJobSource(jobSource);
        job.setPlannedTime(now);
        job.setStartedAt(now);
        job.setJobStatus(DiskMonitorConstant.JOB_STATUS_RUNNING);
        job.setTargetCount(targets.size());
        job.setSuccessCount(0);
        job.setWarningCount(0);
        job.setAlarmCount(0);
        job.setMessage(forceNotify ? "通知测试任务" : null);
        jobMapper.insert(job);

        int successCount = 0;
        int warningCount = 0;
        int alarmCount = 0;
        List<String> errorMessages = new ArrayList<>();
        DiskMonitorPolicy policy = diskMonitorPolicyService.getOrCreatePolicy();

        for (DiskMonitorTarget target : targets) {
            try {
                ScanSnapshot snapshot = resolveSnapshotStatus(target, scanDrive(target.getDriveLetter()));
                if (snapshot.isSuccess()) {
                    successCount++;
                }
                if (DiskMonitorConstant.STATUS_WARNING.equals(snapshot.getCurrentStatus())) {
                    warningCount++;
                }
                if (DiskMonitorConstant.STATUS_ALARM.equals(snapshot.getCurrentStatus())) {
                    alarmCount++;
                }

                NotifyDecision notifyDecision = resolveNotifyDecision(target, snapshot.getCurrentStatus(), forceNotify);
                DiskMonitorResult result = buildResult(job, target, snapshot, notifyDecision);
                resultMapper.insert(result);

                if (notifyDecision.isShouldNotify()) {
                    diskMonitorNotificationComponent.sendNotifications(job, target, result,
                            snapshot.getUsedPercent(), snapshot.getCurrentStatus(),
                            notifyDecision.getNotifyReason(), notifyDecision.getNotifyLevel(),
                            snapshot.getScanTime(), snapshot.getMessage());
                }

                updateTargetLastState(target, snapshot);
            } catch (Exception exception) {
                log.error("磁盘监控执行异常，driveLetter={}", target.getDriveLetter(), exception);
                errorMessages.add(target.getDriveLetter() + ":" + exception.getMessage());
                ScanSnapshot failedSnapshot = ScanSnapshot.failed(exception.getMessage());
                DiskMonitorResult result = buildResult(job, target, failedSnapshot,
                        new NotifyDecision(false, DiskMonitorConstant.NOTIFY_REASON_NO_NOTIFY, resolveNotifyLevel(failedSnapshot.getCurrentStatus())));
                resultMapper.insert(result);
                updateTargetLastState(target, failedSnapshot);
            }
        }

        finishJob(job, policy, successCount, warningCount, alarmCount, errorMessages);
        DiskMonitorVO.JobRunVO runVO = new DiskMonitorVO.JobRunVO();
        runVO.setJobId(job.getId());
        runVO.setJobNo(job.getJobNo());
        return runVO;
    }

    private void finishJob(DiskMonitorJob job, DiskMonitorPolicy policy, int successCount, int warningCount,
                           int alarmCount, List<String> errorMessages) {
        job.setSuccessCount(successCount);
        job.setWarningCount(warningCount);
        job.setAlarmCount(alarmCount);
        job.setFinishedAt(LocalDateTime.now());
        if (successCount == job.getTargetCount()) {
            job.setJobStatus(DiskMonitorConstant.JOB_STATUS_SUCCESS);
        } else if (successCount == 0) {
            job.setJobStatus(DiskMonitorConstant.JOB_STATUS_FAILED);
        } else {
            job.setJobStatus(DiskMonitorConstant.JOB_STATUS_PARTIAL_SUCCESS);
        }
        if (!errorMessages.isEmpty()) {
            job.setMessage(String.join("；", errorMessages));
        }
        jobMapper.updateById(job);

        policy.setLastJobId(job.getId());
        policyMapper.updateById(policy);
    }

    private DiskMonitorResult buildResult(DiskMonitorJob job, DiskMonitorTarget target, ScanSnapshot snapshot, NotifyDecision notifyDecision) {
        DiskMonitorResult result = new DiskMonitorResult();
        result.setJobId(job.getId());
        result.setTargetId(target.getId());
        result.setDriveLetter(target.getDriveLetter());
        result.setTotalBytes(snapshot.getTotalBytes());
        result.setUsedBytes(snapshot.getUsedBytes());
        result.setFreeBytes(snapshot.getFreeBytes());
        result.setUsedPercent(snapshot.getUsedPercent());
        result.setCurrentStatus(snapshot.getCurrentStatus());
        result.setPreviousStatus(resolvePreviousStatus(target.getLastStatus()));
        result.setStatusChanged(snapshot.getCurrentStatus().equals(resolvePreviousStatus(target.getLastStatus())) ? 0 : 1);
        result.setShouldNotify(notifyDecision.isShouldNotify() ? 1 : 0);
        result.setNotifyReason(notifyDecision.getNotifyReason());
        result.setScanTime(snapshot.getScanTime());
        result.setMessage(snapshot.getMessage());
        return result;
    }

    private void updateTargetLastState(DiskMonitorTarget target, ScanSnapshot snapshot) {
        target.setLastStatus(snapshot.getCurrentStatus());
        target.setLastScanTime(snapshot.getScanTime());
        target.setLastUsedPercent(snapshot.getUsedPercent());
        targetMapper.updateById(target);
    }

    private NotifyDecision resolveNotifyDecision(DiskMonitorTarget target, String currentStatus, boolean forceNotify) {
        String previousStatus = resolvePreviousStatus(target.getLastStatus());
        if (forceNotify) {
            return new NotifyDecision(true, DiskMonitorConstant.NOTIFY_REASON_STATUS_CHANGED, resolveNotifyLevel(currentStatus));
        }
        if (DiskMonitorConstant.STATUS_ALARM.equals(currentStatus)) {
            return new NotifyDecision(true, DiskMonitorConstant.NOTIFY_REASON_ALARM_EVERY_TIME, DiskMonitorConstant.NOTIFY_LEVEL_ALARM);
        }
        if (DiskMonitorConstant.STATUS_WARNING.equals(currentStatus) && !DiskMonitorConstant.STATUS_WARNING.equals(previousStatus)) {
            return new NotifyDecision(true, DiskMonitorConstant.NOTIFY_REASON_STATUS_CHANGED, DiskMonitorConstant.NOTIFY_LEVEL_WARNING);
        }
        if (DiskMonitorConstant.STATUS_NORMAL.equals(currentStatus)
                && (DiskMonitorConstant.STATUS_WARNING.equals(previousStatus) || DiskMonitorConstant.STATUS_ALARM.equals(previousStatus))) {
            return new NotifyDecision(true, DiskMonitorConstant.NOTIFY_REASON_STATUS_CHANGED, DiskMonitorConstant.NOTIFY_LEVEL_RECOVER);
        }
        return new NotifyDecision(false, DiskMonitorConstant.NOTIFY_REASON_NO_NOTIFY, resolveNotifyLevel(currentStatus));
    }

    private String resolveNotifyLevel(String currentStatus) {
        if (DiskMonitorConstant.STATUS_ALARM.equals(currentStatus)) {
            return DiskMonitorConstant.NOTIFY_LEVEL_ALARM;
        }
        if (DiskMonitorConstant.STATUS_WARNING.equals(currentStatus)) {
            return DiskMonitorConstant.NOTIFY_LEVEL_WARNING;
        }
        return DiskMonitorConstant.NOTIFY_LEVEL_RECOVER;
    }

    private ScanSnapshot scanDrive(String driveLetter) {
        File driveRoot = new File(driveLetter + File.separator);
        if (!driveRoot.exists()) {
            log.warn("磁盘监控扫描跳过，监控盘符不存在或当前运行账号无访问权限，driveLetter={}", driveLetter);
            return ScanSnapshot.failed("盘符不存在或当前运行账户无访问权限");
        }
        long totalBytes = driveRoot.getTotalSpace();
        if (totalBytes <= 0) {
            log.warn("磁盘监控扫描失败，未读取到有效磁盘容量，driveLetter={}", driveLetter);
            return ScanSnapshot.failed("未读取到有效磁盘容量");
        }
        long freeBytes = driveRoot.getUsableSpace();
        long usedBytes = totalBytes - freeBytes;
        BigDecimal usedPercent = BigDecimal.valueOf(usedBytes)
                .multiply(BigDecimal.valueOf(100))
                .divide(BigDecimal.valueOf(totalBytes), 2, RoundingMode.HALF_UP);
        return new ScanSnapshot(true, totalBytes, usedBytes, freeBytes, usedPercent, LocalDateTime.now(),
                DiskMonitorConstant.STATUS_UNKNOWN, null);
    }

    private ScanSnapshot resolveSnapshotStatus(DiskMonitorTarget target, ScanSnapshot snapshot) {
        if (!snapshot.isSuccess()) {
            return snapshot;
        }
        String currentStatus;
        if (snapshot.getUsedPercent().compareTo(BigDecimal.valueOf(target.getAlarmUsagePercent())) >= 0) {
            currentStatus = DiskMonitorConstant.STATUS_ALARM;
        } else if (snapshot.getUsedPercent().compareTo(BigDecimal.valueOf(target.getWarningUsagePercent())) >= 0) {
            currentStatus = DiskMonitorConstant.STATUS_WARNING;
        } else {
            currentStatus = DiskMonitorConstant.STATUS_NORMAL;
        }
        return new ScanSnapshot(true, snapshot.getTotalBytes(), snapshot.getUsedBytes(), snapshot.getFreeBytes(),
                snapshot.getUsedPercent(), snapshot.getScanTime(), currentStatus, snapshot.getMessage());
    }

    private List<DiskMonitorTarget> resolveExecutionTargets(String driveLetter) {
        if (StrUtil.isNotBlank(driveLetter)) {
            DiskMonitorTarget target = diskMonitorPolicyService.getTargetByDriveLetter(driveLetter);
            return target == null ? Collections.emptyList() : Collections.singletonList(target);
        }
        return diskMonitorPolicyService.listEnabledTargets();
    }

    private void logNoExecutionTargets(String jobSource, String driveLetter) {
        if (StrUtil.isNotBlank(driveLetter)) {
            log.warn("磁盘监控执行跳过，未找到可执行的盘符配置，jobSource={}, driveLetter={}", jobSource, driveLetter);
            return;
        }
        log.warn("磁盘监控执行跳过，暂无启用的磁盘监控盘符配置，jobSource={}", jobSource);
    }

    private void validateJobSource(String jobSource) {
        if (!DiskMonitorConstant.JOB_SOURCE_APP_START.equals(jobSource)
                && !DiskMonitorConstant.JOB_SOURCE_DAILY_SCHEDULE.equals(jobSource)
                && !DiskMonitorConstant.JOB_SOURCE_MANUAL.equals(jobSource)) {
            throw new BusinessException(DiskMonitorResponseEnum.JOB_SOURCE_INVALID);
        }
    }

    private boolean isEnabled(Integer value) {
        return value != null && value == 1;
    }

    private String resolvePreviousStatus(String previousStatus) {
        return StrUtil.isBlank(previousStatus) ? DiskMonitorConstant.STATUS_UNKNOWN : previousStatus;
    }

    private String formatDateTime(LocalDateTime dateTime) {
        return dateTime == null ? null : dateTime.format(DATE_TIME_FORMATTER);
    }

    private String generateJobNo() {
        return "DM" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
    }

    private DiskMonitorVO.JobListVO toJobListVO(DiskMonitorJob job) {
        DiskMonitorVO.JobListVO jobListVO = new DiskMonitorVO.JobListVO();
        jobListVO.setJobId(job.getId());
        jobListVO.setJobNo(job.getJobNo());
        jobListVO.setJobSource(job.getJobSource());
        jobListVO.setStartedAt(formatDateTime(job.getStartedAt()));
        jobListVO.setFinishedAt(formatDateTime(job.getFinishedAt()));
        jobListVO.setJobStatus(job.getJobStatus());
        jobListVO.setTargetCount(job.getTargetCount());
        jobListVO.setWarningCount(job.getWarningCount());
        jobListVO.setAlarmCount(job.getAlarmCount());
        jobListVO.setMessage(job.getMessage());
        return jobListVO;
    }

    private DiskMonitorVO.JobInfoVO toJobInfoVO(DiskMonitorJob job) {
        DiskMonitorVO.JobInfoVO jobInfoVO = new DiskMonitorVO.JobInfoVO();
        jobInfoVO.setId(job.getId());
        jobInfoVO.setJobNo(job.getJobNo());
        jobInfoVO.setJobSource(job.getJobSource());
        jobInfoVO.setStartedAt(formatDateTime(job.getStartedAt()));
        jobInfoVO.setFinishedAt(formatDateTime(job.getFinishedAt()));
        jobInfoVO.setJobStatus(job.getJobStatus());
        jobInfoVO.setTargetCount(job.getTargetCount());
        jobInfoVO.setSuccessCount(job.getSuccessCount());
        jobInfoVO.setWarningCount(job.getWarningCount());
        jobInfoVO.setAlarmCount(job.getAlarmCount());
        jobInfoVO.setMessage(job.getMessage());
        return jobInfoVO;
    }

    private DiskMonitorVO.ResultVO toResultVO(DiskMonitorResult result) {
        DiskMonitorVO.ResultVO resultVO = new DiskMonitorVO.ResultVO();
        resultVO.setResultId(result.getId());
        resultVO.setTargetId(result.getTargetId());
        resultVO.setDriveLetter(result.getDriveLetter());
        resultVO.setTotalBytes(result.getTotalBytes());
        resultVO.setUsedBytes(result.getUsedBytes());
        resultVO.setFreeBytes(result.getFreeBytes());
        resultVO.setUsedPercent(result.getUsedPercent());
        resultVO.setCurrentStatus(result.getCurrentStatus());
        resultVO.setPreviousStatus(result.getPreviousStatus());
        resultVO.setStatusChanged(Objects.equals(result.getStatusChanged(), 1));
        resultVO.setShouldNotify(Objects.equals(result.getShouldNotify(), 1));
        resultVO.setNotifyReason(result.getNotifyReason());
        resultVO.setScanTime(formatDateTime(result.getScanTime()));
        resultVO.setMessage(result.getMessage());
        return resultVO;
    }

    private DiskMonitorVO.NotifyLogVO toNotifyLogVO(DiskMonitorNotifyLog notifyLog) {
        DiskMonitorVO.NotifyLogVO notifyLogVO = new DiskMonitorVO.NotifyLogVO();
        notifyLogVO.setId(notifyLog.getId());
        notifyLogVO.setResultId(notifyLog.getResultId());
        notifyLogVO.setDriveLetter(notifyLog.getDriveLetter());
        notifyLogVO.setNotifyLevel(notifyLog.getNotifyLevel());
        notifyLogVO.setChannelType(notifyLog.getChannelType());
        notifyLogVO.setChannelTarget(notifyLog.getChannelTarget());
        notifyLogVO.setSendStatus(notifyLog.getSendStatus());
        notifyLogVO.setResponseMessage(notifyLog.getResponseMessage());
        notifyLogVO.setSentAt(formatDateTime(notifyLog.getSentAt()));
        return notifyLogVO;
    }

    private static class NotifyDecision {
        private final boolean shouldNotify;
        private final String notifyReason;
        private final String notifyLevel;

        private NotifyDecision(boolean shouldNotify, String notifyReason, String notifyLevel) {
            this.shouldNotify = shouldNotify;
            this.notifyReason = notifyReason;
            this.notifyLevel = notifyLevel;
        }

        public boolean isShouldNotify() {
            return shouldNotify;
        }

        public String getNotifyReason() {
            return notifyReason;
        }

        public String getNotifyLevel() {
            return notifyLevel;
        }
    }

    private static class ScanSnapshot {
        private final boolean success;
        private final Long totalBytes;
        private final Long usedBytes;
        private final Long freeBytes;
        private final BigDecimal usedPercent;
        private final LocalDateTime scanTime;
        private final String currentStatus;
        private final String message;

        private ScanSnapshot(boolean success, Long totalBytes, Long usedBytes, Long freeBytes,
                             BigDecimal usedPercent, LocalDateTime scanTime, String currentStatus, String message) {
            this.success = success;
            this.totalBytes = totalBytes;
            this.usedBytes = usedBytes;
            this.freeBytes = freeBytes;
            this.usedPercent = usedPercent == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP) : usedPercent;
            this.scanTime = scanTime == null ? LocalDateTime.now() : scanTime;
            this.currentStatus = StrUtil.blankToDefault(currentStatus, DiskMonitorConstant.STATUS_UNKNOWN);
            this.message = message;
        }

        public static ScanSnapshot failed(String message) {
            return new ScanSnapshot(false, 0L, 0L, 0L, BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP),
                    LocalDateTime.now(), DiskMonitorConstant.STATUS_UNKNOWN, message);
        }

        public boolean isSuccess() {
            return success;
        }

        public Long getTotalBytes() {
            return totalBytes;
        }

        public Long getUsedBytes() {
            return usedBytes;
        }

        public Long getFreeBytes() {
            return freeBytes;
        }

        public BigDecimal getUsedPercent() {
            return usedPercent;
        }

        public LocalDateTime getScanTime() {
            return scanTime;
        }

        public String getCurrentStatus() {
            if (!success || totalBytes == null || totalBytes <= 0) {
                return DiskMonitorConstant.STATUS_UNKNOWN;
            }
            return currentStatus == null ? DiskMonitorConstant.STATUS_NORMAL : currentStatus;
        }

        public String getMessage() {
            return message;
        }
    }
}
