package com.erp.print.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.erp.print.dto.request.PrintTaskQueryRequest;
import com.erp.print.dto.request.PrintTaskRequest;
import com.erp.common.core.model.PageResponse;
import com.erp.print.dto.response.PrintTaskResponse;
import com.erp.print.entity.PrintTemplate;
import com.erp.print.entity.PrintTask;
import com.erp.print.exception.PrintException;
import com.erp.print.repository.PrintTaskRepository;
import com.erp.print.service.PrintRecordService;
import com.erp.print.service.PrintTemplateService;
import com.erp.print.service.PrintTaskService;
import com.erp.print.service.PrinterService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RequiredArgsConstructor
public class PrintTaskServiceImpl implements PrintTaskService {

    private final PrintTaskRepository taskRepository;
    private final PrintTemplateService templateService;
    private final PrinterService printerService;
    private final PrintRecordService recordService;
    private final ObjectMapper objectMapper;
    private final RedisTemplate<String, Object> redisTemplate;

    private static final String TASK_LOCK_PREFIX = "print:task:lock:";
    private static final DateTimeFormatter TASK_NO_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

    @Override
    public PageResponse<PrintTask> listTasks(Integer page, Integer limit, PrintTaskQueryRequest request) {
        Page<PrintTask> p = new Page<>(page, limit);
        IPage<PrintTask> result = taskRepository.selectTaskPage(p, request.getTaskStatus(),
                request.getStartDate(), request.getEndDate());
        return PageResponse.of(result.getTotal(), page, limit, result.getRecords());
    }

    @Override
    public PrintTask getTaskById(Long id) {
        return taskRepository.selectById(id);
    }

    @Override
    public PrintTask getTaskByTaskNo(String taskNo) {
        return taskRepository.selectByTaskNo(taskNo);
    }

    @Override
    @Transactional
    public PrintTask createTask(PrintTaskRequest request) {
        PrintTemplate template = templateService.getTemplateById(request.getTemplateId());
        if (template == null) {
            throw new PrintException("打印模板不存在: " + request.getTemplateId());
        }

        String taskNo = generateTaskNo();

        PrintTask task = new PrintTask();
        BeanUtils.copyProperties(request, task);
        task.setTaskNo(taskNo);
        task.setTemplateName(template.getTemplateName());
        task.setTaskStatus("pending");
        task.setRetryCount(0);
        task.setMaxRetries(3);

        if (request.getPrintParams() != null) {
            try {
                task.setPrintParams(objectMapper.writeValueAsString(request.getPrintParams()));
            } catch (JsonProcessingException e) {
                throw new PrintException("打印参数序列化失败");
            }
        }

        taskRepository.insert(task);
        log.info("创建打印任务成功: {}", taskNo);
        return task;
    }

    @Override
    @Transactional
    public void cancelTask(Long id) {
        PrintTask task = taskRepository.selectById(id);
        if (task == null) {
            throw new PrintException("任务不存在: " + id);
        }
        if (!"pending".equals(task.getTaskStatus()) && !"failed".equals(task.getTaskStatus())) {
            throw new PrintException("当前状态不允许取消: " + task.getTaskStatus());
        }
        task.setTaskStatus("cancelled");
        taskRepository.updateById(task);
        log.info("取消打印任务: {}", task.getTaskNo());
    }

    @Override
    @Transactional
    public void retryTask(Long id) {
        PrintTask task = taskRepository.selectById(id);
        if (task == null) {
            throw new PrintException("任务不存在: " + id);
        }
        if (!"failed".equals(task.getTaskStatus())) {
            throw new PrintException("只能重试失败的任务");
        }
        if (task.getRetryCount() >= task.getMaxRetries()) {
            throw new PrintException("已达到最大重试次数");
        }
        task.setTaskStatus("pending");
        task.setRetryCount(task.getRetryCount() + 1);
        taskRepository.updateById(task);
        log.info("重试打印任务: {}", task.getTaskNo());
    }

    @Override
    @Transactional
    public void deleteTask(Long id) {
        taskRepository.deleteById(id);
        log.info("删除打印任务: {}", id);
    }

    @Override
    public IPage<PrintTask> selectTaskPage(Page<PrintTask> page, PrintTaskQueryRequest request) {
        LambdaQueryWrapper<PrintTask> wrapper = new LambdaQueryWrapper<>();
        if (request.getTaskStatus() != null) {
            wrapper.eq(PrintTask::getTaskStatus, request.getTaskStatus());
        }
        if (request.getStartDate() != null) {
            wrapper.ge(PrintTask::getCreatedAt, request.getStartDate());
        }
        if (request.getEndDate() != null) {
            wrapper.le(PrintTask::getCreatedAt, request.getEndDate());
        }
        wrapper.orderByDesc(PrintTask::getPriority)
               .orderByAsc(PrintTask::getCreatedAt);
        return taskRepository.selectPage(page, wrapper);
    }

    @Override
    @Transactional
    public PrintTask processTask(Long taskId) {
        String lockKey = TASK_LOCK_PREFIX + taskId;
        Boolean acquired = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 5, TimeUnit.MINUTES);
        if (Boolean.FALSE.equals(acquired)) {
            throw new PrintException("任务正在处理中");
        }

        try {
            PrintTask task = taskRepository.selectById(taskId);
            if (task == null) {
                throw new PrintException("任务不存在: " + taskId);
            }

            task.setTaskStatus("processing");
            taskRepository.updateById(task);

            // 这里可以调用实际的打印驱动执行打印
            // 本示例中模拟打印过程
            log.info("开始处理打印任务: {}", task.getTaskNo());

            return task;
        } finally {
            redisTemplate.delete(lockKey);
        }
    }

    @Override
    @Transactional
    public void markTaskCompleted(String taskNo) {
        PrintTask task = taskRepository.selectByTaskNo(taskNo);
        if (task == null) {
            throw new PrintException("任务不存在: " + taskNo);
        }
        task.setTaskStatus("completed");
        task.setPrintedAt(LocalDateTime.now());
        taskRepository.updateById(task);
        log.info("标记任务完成: {}", taskNo);
    }

    @Override
    @Transactional
    public void markTaskFailed(String taskNo, String errorMessage) {
        PrintTask task = taskRepository.selectByTaskNo(taskNo);
        if (task == null) {
            throw new PrintException("任务不存在: " + taskNo);
        }
        task.setTaskStatus("failed");
        task.setErrorMessage(errorMessage);
        taskRepository.updateById(task);
        log.error("标记任务失败: {} - {}", taskNo, errorMessage);
    }

    @Override
    public List<PrintTask> getPendingTasks(Integer limit) {
        LambdaQueryWrapper<PrintTask> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PrintTask::getTaskStatus, "pending")
               .orderByDesc(PrintTask::getPriority)
               .orderByAsc(PrintTask::getCreatedAt)
               .last("LIMIT " + limit);
        return taskRepository.selectList(wrapper);
    }

    private String generateTaskNo() {
        String timestamp = LocalDateTime.now().format(TASK_NO_FORMATTER);
        String random = String.format("%04d", (int) (Math.random() * 10000));
        return "PT" + timestamp + random;
    }
}
