package com.miraclegarden.smsmessage.service;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 上传失败重试管理器（内存队列 + SharedPreferences 持久化）。
 * <p>
 * 主要职责：
 * 1. 入队失败上传任务并立即尝试上传；
 * 2. 上传失败后按延迟策略重试；
 * 3. 进程重启后从本地恢复重试队列；
 * 4. 统计成功上传总数，供前台通知展示。
 */
public class RetryManager {
    private static final String TAG = "RetryManager";

    private static final String SP_NAME = "server";
    private static final String KEY_RETRY_QUEUE = "retry_queue";
    private static final String KEY_UPLOADED_COUNT = "uploaded_count";
    private static final String KEY_TOTAL_COUNT = "total_count";
    private static final String KEY_FAILED_COUNT = "failed_count";

    private static final int MAX_QUEUE_SIZE = 100;
    private static final long[] RETRY_DELAYS = new long[]{2000L, 5000L, 15000L};

    private final SharedPreferences sharedPreferences;
    private final Handler handler;
    private final List<QueueItem> retryQueue = new ArrayList<>();

    private UploadCallback uploadCallback;
    private int uploadedCount;
    private int totalCount;
    private int failedCount;

    /**
     * 上传抽象回调。
     */
    public interface UploadCallback {
        void onUpload(String jsonPayload, UploadResultListener listener);
    }

    /**
     * 上传结果监听。
     */
    public interface UploadResultListener {
        void onSuccess();

        void onFailure(String error);
    }

    /**
     * 重试队列元素。
     */
    private static class QueueItem {
        String jsonPayload;
        int retryCount;  // starts at 0, max 2 (3 attempts total: initial + 2 retries)
        long nextRetryTime;
    }

    public RetryManager(Context context) {
        Context appContext = context.getApplicationContext();
        this.sharedPreferences = appContext.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
        this.handler = new Handler(Looper.getMainLooper());
        this.uploadedCount = sharedPreferences.getInt(KEY_UPLOADED_COUNT, 0);
        this.totalCount = sharedPreferences.getInt(KEY_TOTAL_COUNT, 0);
        this.failedCount = sharedPreferences.getInt(KEY_FAILED_COUNT, 0);
    }

    /**
     * 设置上传实现。
     */
    public void setUploadCallback(UploadCallback callback) {
        this.uploadCallback = callback;
    }

    /**
     * 添加任务到队列并立即尝试上传。
     */
    public void enqueue(String jsonPayload) {
        if (jsonPayload == null || jsonPayload.trim().isEmpty()) {
            Log.w(TAG, "enqueue payload 为空，忽略");
            return;
        }

        incrementTotalCount();

        QueueItem item = new QueueItem();
        item.jsonPayload = jsonPayload;
        item.retryCount = 0;
        item.nextRetryTime = SystemClock.elapsedRealtime();

        synchronized (retryQueue) {
            if (retryQueue.size() >= MAX_QUEUE_SIZE) {
                QueueItem removed = retryQueue.remove(0);
                Log.w(TAG, "重试队列已满，丢弃最旧任务: " + (removed == null ? "null" : removed.jsonPayload));
            }
            retryQueue.add(item);
            persistQueue();
        }

        attemptUpload(item);
    }

    /**
     * 从持久化恢复重试队列并重新触发上传。
     */
    public void restoreFromPersistence() {
        String queueJson = sharedPreferences.getString(KEY_RETRY_QUEUE, "");
        if (queueJson == null || queueJson.trim().isEmpty()) {
            return;
        }

        List<QueueItem> restoredItems = new ArrayList<>();
        try {
            JSONArray jsonArray = new JSONArray(queueJson);
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject object = jsonArray.optJSONObject(i);
                if (object == null) {
                    continue;
                }

                QueueItem item = new QueueItem();
                item.jsonPayload = object.optString("jsonPayload", "");
                item.retryCount = object.optInt("retryCount", 0);
                item.nextRetryTime = object.optLong("nextRetryTime", SystemClock.elapsedRealtime());

                if (item.jsonPayload == null || item.jsonPayload.trim().isEmpty()) {
                    continue;
                }

                restoredItems.add(item);
            }
        } catch (JSONException e) {
            Log.e(TAG, "恢复重试队列失败", e);
            return;
        }

        synchronized (retryQueue) {
            retryQueue.clear();
            retryQueue.addAll(restoredItems);
        }

        for (QueueItem item : new ArrayList<>(restoredItems)) {
            long delay = item.nextRetryTime - SystemClock.elapsedRealtime();
            if (delay > 0) {
                handler.postDelayed(() -> attemptUpload(item), delay);
            } else {
                attemptUpload(item);
            }
        }
    }

    /**
     * 获取累计成功上传数量。
     */
    public int getUploadedCount() {
        return uploadedCount;
    }

    public int getTotalCount() {
        return totalCount;
    }

    public int getFailedCount() {
        return failedCount;
    }

    /** 本地监听模式下仅累计抓取条数，不上传服务器 */
    public void recordLocalCapture() {
        incrementTotalCount();
    }

    private void incrementTotalCount() {
        totalCount++;
        sharedPreferences.edit()
                .putInt(KEY_TOTAL_COUNT, totalCount)
                .apply();
    }

    private void incrementFailedCount() {
        failedCount++;
        sharedPreferences.edit()
                .putInt(KEY_FAILED_COUNT, failedCount)
                .apply();
    }

    /**
     * 清理回调，通常在 Service 销毁时调用。
     */
    public void destroy() {
        handler.removeCallbacksAndMessages(null);
    }

    private void attemptUpload(final QueueItem item) {
        if (item == null) {
            return;
        }

        if (uploadCallback == null) {
            Log.w(TAG, "uploadCallback 未设置，无法上传");
            return;
        }

        uploadCallback.onUpload(item.jsonPayload, new UploadResultListener() {
            @Override
            public void onSuccess() {
                synchronized (retryQueue) {
                    retryQueue.remove(item);
                    persistQueue();
                }
                uploadedCount++;
                sharedPreferences.edit()
                        .putInt(KEY_UPLOADED_COUNT, uploadedCount)
                        .apply();
            }

            @Override
            public void onFailure(String error) {
                synchronized (retryQueue) {
                    if (!retryQueue.contains(item)) {
                        return;
                    }

                    if (item.retryCount < 3) {
                        long delay = RETRY_DELAYS[Math.min(item.retryCount, RETRY_DELAYS.length - 1)];
                        item.retryCount++;
                        item.nextRetryTime = SystemClock.elapsedRealtime() + delay;
                        handler.postDelayed(() -> attemptUpload(item), delay);
                        persistQueue();
                        Log.w(TAG, "上传失败，准备重试。retryCount=" + item.retryCount + ", error=" + error);
                    } else {
                        retryQueue.remove(item);
                        persistQueue();
                        incrementFailedCount();
                        Log.e(TAG, "上传失败达到上限，丢弃任务: " + error);
                    }
                }
            }
        });
    }

    private void persistQueue() {
        JSONArray jsonArray = new JSONArray();
        synchronized (retryQueue) {
            Iterator<QueueItem> iterator = retryQueue.iterator();
            while (iterator.hasNext()) {
                QueueItem item = iterator.next();
                JSONObject object = new JSONObject();
                try {
                    object.put("jsonPayload", item.jsonPayload);
                    object.put("retryCount", item.retryCount);
                    object.put("nextRetryTime", item.nextRetryTime);
                    jsonArray.put(object);
                } catch (JSONException e) {
                    Log.e(TAG, "序列化重试项失败", e);
                }
            }
        }

        sharedPreferences.edit()
                .putString(KEY_RETRY_QUEUE, jsonArray.toString())
                .apply();
    }
}
