package com.weather.modules.weather.dailydata;

import com.alibaba.excel.EasyExcel;
import com.weather.modules.weather.dailydata.dto.ImportProgress;
import com.weather.modules.weather.dailydata.service.WeatherDailyDataService;
import com.weather.modules.weather.dailydata.vo.WeatherExcelVO;
import com.weather.modules.security.user.SecurityUser;
import com.weather.modules.security.user.UserContextHolder;
import com.weather.modules.security.user.UserDetail;
import com.weather.common.redis.RedisKeys;
import com.weather.common.redis.RedisUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@AllArgsConstructor
public class WeatherDataImportManager {

    private final WeatherDailyDataService weatherDailyDataService;
    private final RedisUtils redisUtils;

    /** 已完成/失败任务的保留时间（毫秒） */
    private static final long TASK_TTL_MS = TimeUnit.HOURS.toMillis(1);

    private final Map<String, ImportProgress> tasks = new ConcurrentHashMap<>();

    public String submitImport(MultipartFile file) throws IOException {
        File tempFile = File.createTempFile("import_", ".xlsx");
        file.transferTo(tempFile);

        String taskId = UUID.randomUUID().toString();
        ImportProgress progress = new ImportProgress(taskId);
        progress.setStatus("PROCESSING");
        tasks.put(taskId, progress);

        UserDetail user = SecurityUser.getUser();
        CompletableFuture.runAsync(() -> {
            UserContextHolder.set(user);
            try {
                processImport(taskId, tempFile);
            } catch (Exception e) {
                log.error("导入任务 {} 失败", taskId, e);
                ImportProgress p = tasks.get(taskId);
                if (p != null) {
                    p.setStatus("FAILED");
                    p.setErrorMessage(e.getMessage());
                }
            } finally {
                UserContextHolder.remove();
                if (!tempFile.delete()) {
                    tempFile.deleteOnExit();
                }
            }
        });

        return taskId;
    }

    private void processImport(String taskId, File tempFile) {
        ImportProgress progress = tasks.get(taskId);

        // 单次读取：WeatherDataListener 同时负责计数和入库，避免双次 I/O
        EasyExcel.read(tempFile, WeatherExcelVO.class,
                new WeatherDataListener(weatherDailyDataService, progress))
                .sheet()
                .doRead();

        progress.setStatus("COMPLETED");
        progress.setCompletedAt(System.currentTimeMillis());
        log.info("导入任务 {} 完成，共导入 {} 行", taskId, progress.getProcessedRows().get());

        // 导入完成后清除天气汇总缓存，等待下次定时任务刷新
        try {
            redisUtils.deleteByPattern(RedisKeys.getWeatherSummarizePattern());
            log.info("已清除天气汇总缓存");
        } catch (Exception e) {
            log.warn("清除天气汇总缓存失败", e);
        }
    }

    public ImportProgress getProgress(String taskId) {
        ImportProgress progress = tasks.get(taskId);
        if (progress != null && isExpired(progress)) {
            tasks.remove(taskId);
            return null;
        }
        return progress;
    }

    private boolean isExpired(ImportProgress progress) {
        if ("PROCESSING".equals(progress.getStatus())) {
            return false;
        }
        Long completedAt = progress.getCompletedAt();
        return completedAt != null && System.currentTimeMillis() - completedAt > TASK_TTL_MS;
    }

    /**
     * 定时清理过期任务，每30分钟执行一次
     */
    @Scheduled(fixedRate = 30 * 60 * 1000)
    public void cleanExpiredTasks() {
        int removed = 0;
        for (Map.Entry<String, ImportProgress> entry : tasks.entrySet()) {
            if (isExpired(entry.getValue())) {
                tasks.remove(entry.getKey());
                removed++;
            }
        }
        if (removed > 0) {
            log.info("清理过期导入任务 {} 个，当前剩余 {} 个", removed, tasks.size());
        }
    }
}
