package com.erp.task.service;

import com.erp.common.core.model.PageResponse;
import com.erp.task.dto.TaskExecutionLogDTO;
import com.erp.task.entity.TaskExecutionLog;
import com.erp.task.repository.TaskExecutionLogRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 任务执行记录服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TaskExecutionLogService {

    private final TaskExecutionLogRepository logRepository;

    /**
     * 创建执行记录
     */
    @Transactional
    public TaskExecutionLog createLog(Long taskId, String taskName, String taskGroup, String batchNo, String taskParams) {
        TaskExecutionLog log = TaskExecutionLog.builder()
                .taskId(taskId)
                .taskName(taskName)
                .taskGroup(taskGroup)
                .batchNo(batchNo)
                .triggerTime(LocalDateTime.now())
                .startTime(LocalDateTime.now())
                .status("RUNNING")
                .executorNode(getLocalIp())
                .retryCount(0)
                .isRetry(false)
                .taskParams(taskParams)
                .build();

        return logRepository.save(log);
    }

    /**
     * 更新执行记录 - 成功
     */
    @Transactional
    public void logSuccess(Long logId, String result) {
        Optional<TaskExecutionLog> optLog = logRepository.findById(logId);
        if (optLog.isPresent()) {
            TaskExecutionLog taskLog = optLog.get();
            taskLog.setStatus("SUCCESS");
            taskLog.setEndTime(LocalDateTime.now());
            taskLog.setDuration(java.time.Duration.between(taskLog.getStartTime(), taskLog.getEndTime()).toMillis());
            taskLog.setResult(result);
            logRepository.save(taskLog);
        }
    }

    /**
     * 更新执行记录 - 失败
     */
    @Transactional
    public void logFailure(Long logId, String errorMessage, String errorTrace) {
        Optional<TaskExecutionLog> optLog = logRepository.findById(logId);
        if (optLog.isPresent()) {
            TaskExecutionLog taskLog = optLog.get();
            taskLog.setStatus("FAILED");
            taskLog.setEndTime(LocalDateTime.now());
            taskLog.setDuration(java.time.Duration.between(taskLog.getStartTime(), taskLog.getEndTime()).toMillis());
            taskLog.setResult(errorMessage);
            taskLog.setErrorTrace(errorTrace);
            logRepository.save(taskLog);
        }
    }

    /**
     * 更新执行记录 - 超时
     */
    @Transactional
    public void logTimeout(Long logId, Integer timeout) {
        Optional<TaskExecutionLog> optLog = logRepository.findById(logId);
        if (optLog.isPresent()) {
            TaskExecutionLog taskLog = optLog.get();
            taskLog.setStatus("TIMEOUT");
            taskLog.setEndTime(LocalDateTime.now());
            taskLog.setDuration(java.time.Duration.between(taskLog.getStartTime(), taskLog.getEndTime()).toMillis());
            taskLog.setResult("任务执行超时，超时时间: " + timeout + "秒");
            logRepository.save(taskLog);
        }
    }

    /**
     * 标记为重试
     */
    @Transactional
    public void markRetrying(Long logId) {
        Optional<TaskExecutionLog> optLog = logRepository.findById(logId);
        if (optLog.isPresent()) {
            TaskExecutionLog taskLog = optLog.get();
            taskLog.setStatus("RETRYING");
            taskLog.setRetryCount(taskLog.getRetryCount() + 1);
            taskLog.setIsRetry(true);
            logRepository.save(taskLog);
        }
    }

    /**
     * 根据批次号查询
     */
    public Optional<TaskExecutionLogDTO> findByBatchNo(String batchNo) {
        return logRepository.findByBatchNo(batchNo).map(this::toDTO);
    }

    /**
     * 分页查询任务执行记录
     */
    public PageResponse<TaskExecutionLogDTO> findByTaskId(Long taskId, int page, int pageSize) {
        Pageable pageable = PageRequest.of(page - 1, pageSize);
        Page<TaskExecutionLog> pageResult = logRepository.findByTaskIdOrderByTriggerTimeDesc(taskId, pageable);

        List<TaskExecutionLogDTO> records = pageResult.getContent().stream()
                .map(this::toDTO)
                .collect(Collectors.toList());

        return PageResponse.of(records, pageResult.getTotalElements(), page, pageSize);
    }

    /**
     * 分页查询所有执行记录
     */
    public PageResponse<TaskExecutionLogDTO> findAll(int page, int pageSize) {
        Pageable pageable = PageRequest.of(page - 1, pageSize);
        Page<TaskExecutionLog> pageResult = logRepository.findAllByOrderByTriggerTimeDesc(pageable);

        List<TaskExecutionLogDTO> records = pageResult.getContent().stream()
                .map(this::toDTO)
                .collect(Collectors.toList());

        return PageResponse.of(records, pageResult.getTotalElements(), page, pageSize);
    }

    /**
     * 条件查询
     */
    public PageResponse<TaskExecutionLogDTO> query(Long taskId, String status, String startTime, String endTime, int page, int pageSize) {
        Pageable pageable = PageRequest.of(page - 1, pageSize);

        Specification<TaskExecutionLog> spec = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (taskId != null) {
                predicates.add(cb.equal(root.get("taskId"), taskId));
            }
            if (status != null && !status.isEmpty()) {
                predicates.add(cb.equal(root.get("status"), status));
            }
            if (startTime != null && !startTime.isEmpty()) {
                LocalDateTime start = LocalDateTime.parse(startTime);
                predicates.add(cb.greaterThanOrEqualTo(root.get("triggerTime"), start));
            }
            if (endTime != null && !endTime.isEmpty()) {
                LocalDateTime end = LocalDateTime.parse(endTime);
                predicates.add(cb.lessThanOrEqualTo(root.get("triggerTime"), end));
            }

            return cb.and(predicates.toArray(new Predicate[0]));
        };

        Page<TaskExecutionLog> pageResult = logRepository.findAll(spec, pageable);

        List<TaskExecutionLogDTO> records = pageResult.getContent().stream()
                .map(this::toDTO)
                .collect(Collectors.toList());

        return PageResponse.of(records, pageResult.getTotalElements(), page, pageSize);
    }

    /**
     * 查询可重试的失败记录
     */
    public List<TaskExecutionLogDTO> findRetryableFailures(Integer maxRetries) {
        return logRepository.findRetryableFailures(maxRetries).stream()
                .map(this::toDTO)
                .collect(Collectors.toList());
    }

    /**
     * 删除旧记录
     */
    @Transactional
    public int deleteOldLogs(int days) {
        LocalDateTime before = LocalDateTime.now().minusDays(days);
        return logRepository.deleteOldLogs(before);
    }

    /**
     * 获取执行记录统计
     */
    public java.util.Map<String, Long> getStatsToday() {
        LocalDateTime today = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);

        List<Object[]> statusCounts = logRepository.countByStatusToday(today);

        java.util.Map<String, Long> stats = new java.util.HashMap<>();
        for (Object[] row : statusCounts) {
            stats.put(row[0].toString(), (Long) row[1]);
        }

        return stats;
    }

    /**
     * 获取本地IP
     */
    private String getLocalIp() {
        try {
            return java.net.InetAddress.getLocalHost().getHostAddress();
        } catch (Exception e) {
            return "unknown";
        }
    }

    /**
     * DTO转换
     */
    private TaskExecutionLogDTO toDTO(TaskExecutionLog log) {
        return TaskExecutionLogDTO.builder()
                .id(log.getId())
                .taskId(log.getTaskId())
                .taskName(log.getTaskName())
                .taskGroup(log.getTaskGroup())
                .batchNo(log.getBatchNo())
                .triggerTime(log.getTriggerTime())
                .startTime(log.getStartTime())
                .endTime(log.getEndTime())
                .status(log.getStatus())
                .duration(log.getDuration())
                .executorNode(log.getExecutorNode())
                .result(log.getResult())
                .errorTrace(log.getErrorTrace())
                .retryCount(log.getRetryCount())
                .isRetry(log.getIsRetry())
                .taskParams(log.getTaskParams())
                .createdAt(log.getCreatedAt())
                .build();
    }
}
