package com.wxq.apsv.worker;

import com.wxq.apsv.model.*;
import com.wxq.apsv.utils.HttpRequest;
import com.wxq.apsv.utils.Order;
import com.wxq.apsv.utils.Settings;
import com.wxq.apsv.utils.Unicode;
import org.apache.commons.lang.StringUtils;

import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.jsoup.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.TimerTask;

/**
 * 抓取分析订单以及推送服务器的定时循环任务
 */
public class ApsvTimerTask extends TimerTask {
    private static final Logger logger = LoggerFactory.getLogger(ApsvTimerTask.class);

    private ApsvTask task;

    public ApsvTimerTask(ApsvTask task) {
        this.task = task;
    }

    @Override
    public void run() {
        logger.info("ApsvTimerTask run at Thread {}", Thread.currentThread().getId());
        if (task == null || StringUtils.isEmpty(task.cookie)) {
            return;
        }

        RunTasksModel runTasksModel = RunTasksModel.getInstance();
        // 先从html分析订单(较快)并显示到表格
        ArrayList<ApsvOrder> orders = findOrders(getPage());
        orders.forEach(o -> {
            logger.info("Add order(has not push) with tradeNo: {}", o.tradeNo);
            runTasksModel.AddOrder(o);
        });

        // 推送订单并刷新表格
        orders = pushOrders(orders);
        orders.forEach(o -> {
            logger.info("Add order(pushed yet) with tradeNo: {}", o.tradeNo);
            runTasksModel.AddOrder(o);
        });
    }

    private String getPage() {
        // 先请求个人主页
        String alipayUserCenterPage = HttpRequest.DoGet(Constants.ALIPAY_UC_URL, task.cookie);
        if (StringUtils.isEmpty(alipayUserCenterPage)) {
            logger.error("Fetch {} failed", Constants.ALIPAY_UC_URL);
            return "";
        }

        // 再请求高级版账单页面
        String orderListPage = HttpRequest.DoGet(Constants.ALIPAY_ADVANCED_ORDERS_URL, task.cookie);
        if (StringUtils.isEmpty(orderListPage)) {
            logger.error("Fetch {} failed", Constants.ALIPAY_ADVANCED_ORDERS_URL);
        }
        return orderListPage;
    }

    private ArrayList<ApsvOrder> findOrders(String html) {
        //logger.info("Html: {}", html);
        ArrayList<ApsvOrder> orders = new ArrayList<>();

        Document doc = Jsoup.parse(html);

        Element ordersForm = doc.getElementById("J-submit-form");
        if (ordersForm == null) {
            logger.error("Cannot find order list form, maybe cookie expires");
            // 标记task status为异常
            // TODO 弹窗提醒cookie异常
            RunTasksModel.getInstance().MarkTaskException(task.id);
            return orders;
        }

        Elements tableBody = doc.select("#tradeRecordsIndex>tbody");
        Elements orderRows = tableBody.select("tr");

        orderRows.forEach(row -> {
            Elements timeNodes = row.select("td.time p");
            String[] orderNoData = row.select("td.tradeNo p").text().split("\\|");
            ApsvOrder order = new ApsvOrder(){
                {
                    taskId = task.id;
                    time = timeNodes.get(0).text() + " " + timeNodes.get(timeNodes.size() - 1).text();
                    description = row.select(".memo-info").text();
                    memo = row.select("td.memo p").text();
                    tradeNo = orderNoData.length > 1 ? orderNoData[1].split(":")[1] : orderNoData[0].split(":")[1];
                    username = Unicode.unicodeToString(row.select("td.other p").text());
                    amount = Float.parseFloat(row.select("td.amount span").text().replaceAll("\\s+", ""));
                    status = row.select("td.status p").text();
                }
            };
            order.sig = Order.Sign(order, task.pushSecret);
            orders.add(order);
        });
        return orders;
    }

    private ArrayList<ApsvOrder> pushOrders(ArrayList<ApsvOrder> orders) {
        ArrayList<ApsvOrder> newOrders = new ArrayList<>();
        orders.forEach(o -> {
            // 查询是否之前已经推送成功了
            if (PushData.IsTradeNumHandled(task.id, o.tradeNo)) {
                o.pushed = true;
                newOrders.add(o);
            } else {
                // 需要推送
                HashMap data = new HashMap<String, Object>();
                data.put("tradeNo", o.tradeNo);
                data.put("time", o.time);
                data.put("description", o.description);
                data.put("memo", o.memo);
                data.put("username", o.username);
                data.put("amount", o.amount);
                data.put("status", o.status);
                data.put("sig", o.sig);
                data.put("version", o.version);
                String code = HttpRequest.DoPost(task.pushApi, "", data);
                logger.info("Push order {} with response body {}", o.tradeNo, code);
                if (StringUtils.equals(code, Settings.getInstance().getPushSuccessBody())) {
                    o.pushed = true;
                    // 保存到已推送成功列表
                    PushData.AddSuccessRecord(o.taskId, o.tradeNo);
                } else {
                    o.pushed = false;
                }
                newOrders.add(o);
            }
        });

        return newOrders;
    }
}