package com.bizzan.bitrade.controller.stat;

import com.bizzan.bitrade.util.MessageResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 管理后台首页今日概览统计。
 *
 * <p>GET  /stat/dashboard/today-overview?includeInternal=0  查询当日统计</p>
 * <p>POST /stat/dashboard/today-overview/refresh?includeInternal=0  触发 datacenter 重算并返回</p>
 */
@Slf4j
@RestController
@RequestMapping("/stat/dashboard")
public class DashboardController {

    @Resource
    private JdbcTemplate jdbcTemplate;

    @Resource
    @Qualifier("plainRestTemplate")
    private RestTemplate plainRestTemplate;

    @Value("${datacenter.host}")
    private String datacenterHost;

    // ── 查询 ──────────────────────────────────────────────────────────────────

    @GetMapping("/today-overview")
    public MessageResult getTodayOverview(
            @RequestParam(value = "includeInternal", defaultValue = "0") int includeInternal) {
        return MessageResult.getSuccessInstance("SUCCESS", queryTodayOverview(includeInternal));
    }

    // ── 刷新（触发 datacenter job，两个变体都会重算）────────────────────────────

    @PostMapping("/today-overview/refresh")
    public MessageResult refreshTodayOverview(
            @RequestParam(value = "includeInternal", defaultValue = "0") int includeInternal) {
        try {
            String url = datacenterHost + "/job/run/today-overview?includeInternal=" + includeInternal;
            log.info("[Dashboard] 触发 datacenter 任务: {}", url);
            plainRestTemplate.postForObject(url, null, String.class);
        } catch (Exception e) {
            log.error("[Dashboard] 触发 datacenter 任务失败，返回库中现有数据", e);
        }
        return MessageResult.getSuccessInstance("SUCCESS", queryTodayOverview(includeInternal));
    }

    // ── 合约盈亏 GET/POST ─────────────────────────────────────────────────────

    @GetMapping("/contract-pnl")
    public MessageResult getContractPnl(
            @RequestParam(value = "includeInternal", defaultValue = "0") int includeInternal) {
        return MessageResult.getSuccessInstance("SUCCESS", queryContractPnl(includeInternal));
    }

    @PostMapping("/contract-pnl/refresh")
    public MessageResult refreshContractPnl(
            @RequestParam(value = "includeInternal", defaultValue = "0") int includeInternal) {
        try {
            String url = datacenterHost + "/job/run/contract-pnl?includeInternal=" + includeInternal;
            log.info("[Dashboard] 触发 datacenter 合约盈亏任务: {}", url);
            plainRestTemplate.postForObject(url, null, String.class);
        } catch (Exception e) {
            log.error("[Dashboard] 触发 datacenter 合约盈亏任务失败，返回库中现有数据", e);
        }
        return MessageResult.getSuccessInstance("SUCCESS", queryContractPnl(includeInternal));
    }

    // ── 全量刷新（同时触发 today-overview + contract-pnl 两个 datacenter job）───────
    // datacenter computeAndSaveBoth() 每次都同时存两个变体（includeInternal=0/1），
    // 所以两个 job 各调用一次即可刷新整个首页所有统计数据。

    @PostMapping("/refresh-all")
    public MessageResult refreshAll(
            @RequestParam(value = "includeInternal", defaultValue = "0") int includeInternal) {
        try {
            plainRestTemplate.postForObject(
                    datacenterHost + "/job/run/today-overview?includeInternal=" + includeInternal, null, String.class);
        } catch (Exception e) {
            log.error("[Dashboard] refresh-all: 触发 today-overview 失败", e);
        }
        try {
            plainRestTemplate.postForObject(
                    datacenterHost + "/job/run/contract-pnl?includeInternal=" + includeInternal, null, String.class);
        } catch (Exception e) {
            log.error("[Dashboard] refresh-all: 触发 contract-pnl 失败", e);
        }
        // 返回今日概览（前端各模块会自行二次 GET 拉最新数据）
        return MessageResult.getSuccessInstance("SUCCESS", queryTodayOverview(includeInternal));
    }

    // ── 每日盈亏统计（自主+跟单合计，最近 N 天）────────────────────────────────────

    @GetMapping("/daily-pnl")
    public MessageResult getDailyPnl(
            @RequestParam(value = "days", defaultValue = "7") int days,
            @RequestParam(value = "includeInternal", defaultValue = "0") int includeInternal) {
        if (days < 1)  days = 1;
        if (days > 30) days = 30;
        String sql = "SELECT stat_date, " +
                     "  self_today_close_profit, self_today_close_loss, " +
                     "  copy_today_close_profit, copy_today_close_loss, " +
                     "  self_today_close_profit + copy_today_close_profit AS total_profit, " +
                     "  self_today_close_loss   + copy_today_close_loss   AS total_loss " +
                     "FROM stat_contract_pnl " +
                     "WHERE include_internal = ? " +
                     "  AND stat_date > DATE_SUB(CURDATE(), INTERVAL ? DAY) " +
                     "  AND stat_date <= CURDATE() " +
                     "ORDER BY stat_date ASC";
        try {
            List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, includeInternal, days);
            rows.forEach(row -> {
                BigDecimal selfProfit  = toBD(row, "self_today_close_profit");
                BigDecimal selfLoss    = toBD(row, "self_today_close_loss");
                BigDecimal copyProfit  = toBD(row, "copy_today_close_profit");
                BigDecimal copyLoss    = toBD(row, "copy_today_close_loss");
                BigDecimal totalProfit = toBD(row, "total_profit");
                BigDecimal totalLoss   = toBD(row, "total_loss");
                row.put("self_today_close_profit", selfProfit.doubleValue());
                row.put("self_today_close_loss",   selfLoss.doubleValue());
                row.put("self_diff",               selfLoss.subtract(selfProfit).doubleValue());
                row.put("copy_today_close_profit", copyProfit.doubleValue());
                row.put("copy_today_close_loss",   copyLoss.doubleValue());
                row.put("copy_diff",               copyLoss.subtract(copyProfit).doubleValue());
                row.put("total_profit",            totalProfit.doubleValue());
                row.put("total_loss",              totalLoss.doubleValue());
                row.put("diff",                    totalLoss.subtract(totalProfit).doubleValue());
                Object d = row.get("stat_date");
                if (d != null) row.put("stat_date", d.toString());
            });
            return MessageResult.getSuccessInstance("SUCCESS", rows);
        } catch (Exception e) {
            log.error("[Dashboard] 获取每日盈亏统计失败", e);
            return MessageResult.getSuccessInstance("SUCCESS", new ArrayList<>());
        }
    }

    // ── 每日盈亏数据回填（触发 datacenter 补算历史）────────────────────────────────

    @PostMapping("/daily-pnl/backfill")
    public MessageResult backfillDailyPnl(
            @RequestParam(value = "days", defaultValue = "30") int days) {
        try {
            String url = datacenterHost + "/job/run/contract-pnl/backfill?days=" + days;
            log.info("[Dashboard] 触发 datacenter 回填任务: {}", url);
            plainRestTemplate.postForObject(url, null, String.class);
        } catch (Exception e) {
            log.error("[Dashboard] 触发 datacenter 回填任务失败", e);
            return MessageResult.getSuccessInstance("FAILED", "回填失败：" + e.getMessage());
        }
        return MessageResult.getSuccessInstance("SUCCESS", "已触发回填 " + days + " 天历史数据");
    }

    // ── 每日充值提现统计（最近 N 天）────────────────────────────────────────────────

    @GetMapping("/daily-recharge")
    public MessageResult getDailyRecharge(
            @RequestParam(value = "days", defaultValue = "7") int days,
            @RequestParam(value = "includeInternal", defaultValue = "0") int includeInternal) {
        if (days < 1)  days = 1;
        if (days > 30) days = 30;
        String sql = "SELECT stat_date, deposit_amount, withdraw_amount " +
                     "FROM stat_today_overview " +
                     "WHERE include_internal = ? " +
                     "  AND stat_date > DATE_SUB(CURDATE(), INTERVAL ? DAY) " +
                     "  AND stat_date <= CURDATE() " +
                     "ORDER BY stat_date ASC";
        try {
            List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, includeInternal, days);
            rows.forEach(row -> {
                row.put("deposit_amount",  toBD(row, "deposit_amount"));
                row.put("withdraw_amount", toBD(row, "withdraw_amount"));
                Object d = row.get("stat_date");
                if (d != null) row.put("stat_date", d.toString());
            });
            return MessageResult.getSuccessInstance("SUCCESS", rows);
        } catch (Exception e) {
            log.error("[Dashboard] 获取每日充值提现统计失败", e);
            return MessageResult.getSuccessInstance("SUCCESS", new ArrayList<>());
        }
    }

    @PostMapping("/daily-recharge/backfill")
    public MessageResult backfillDailyRecharge(
            @RequestParam(value = "days", defaultValue = "30") int days) {
        try {
            String url = datacenterHost + "/job/run/today-overview/backfill?days=" + days;
            log.info("[Dashboard] 触发 datacenter 充提回填任务: {}", url);
            plainRestTemplate.postForObject(url, null, String.class);
        } catch (Exception e) {
            log.error("[Dashboard] 触发 datacenter 充提回填任务失败", e);
            return MessageResult.getSuccessInstance("FAILED", "回填失败：" + e.getMessage());
        }
        return MessageResult.getSuccessInstance("SUCCESS", "已触发回填 " + days + " 天历史数据");
    }

    // ── 每日注册/登录统计（最近 N 天）────────────────────────────────────────────

    @GetMapping("/daily-user-stat")
    public MessageResult getDailyUserStat(
            @RequestParam(value = "days", defaultValue = "7") int days,
            @RequestParam(value = "includeInternal", defaultValue = "0") int includeInternal) {
        if (days < 1)  days = 1;
        if (days > 30) days = 30;
        String sql = "SELECT stat_date, register_count, login_count " +
                     "FROM stat_today_overview " +
                     "WHERE include_internal = ? " +
                     "  AND stat_date > DATE_SUB(CURDATE(), INTERVAL ? DAY) " +
                     "  AND stat_date <= CURDATE() " +
                     "ORDER BY stat_date ASC";
        try {
            List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, includeInternal, days);
            rows.forEach(row -> {
                Object d = row.get("stat_date");
                if (d != null) row.put("stat_date", d.toString());
                row.put("register_count", row.getOrDefault("register_count", 0));
                row.put("login_count",    row.getOrDefault("login_count",    0));
            });
            return MessageResult.getSuccessInstance("SUCCESS", rows);
        } catch (Exception e) {
            log.error("[Dashboard] 获取每日注册/登录统计失败", e);
            return MessageResult.getSuccessInstance("SUCCESS", new ArrayList<>());
        }
    }

    // ── 内部查询 ──────────────────────────────────────────────────────────────

    private Map<String, Object> queryTodayOverview(int includeInternal) {
        String sql = "SELECT profit_loss, deposit_amount, withdraw_amount, " +
                     "       trade_volume, register_count, login_count, updated_time " +
                     "FROM stat_today_overview " +
                     "WHERE stat_date = ? AND include_internal = ? " +
                     "LIMIT 1";
        try {
            Map<String, Object> row = jdbcTemplate.queryForMap(sql, LocalDate.now().toString(), includeInternal);
            // updated_time 可能是 LocalDateTime，Jackson 1.5 不支持，统一转为字符串
            Object updatedTime = row.get("updated_time");
            if (updatedTime instanceof LocalDateTime) {
                row.put("updated_time",
                        ((LocalDateTime) updatedTime).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            } else if (updatedTime != null) {
                row.put("updated_time", updatedTime.toString());
            }
            return row;
        } catch (org.springframework.dao.EmptyResultDataAccessException e) {
            return buildEmptyRow();
        }
    }

    private Map<String, Object> buildEmptyRow() {
        Map<String, Object> empty = new HashMap<>();
        empty.put("profit_loss",     BigDecimal.ZERO);
        empty.put("deposit_amount",  BigDecimal.ZERO);
        empty.put("withdraw_amount", BigDecimal.ZERO);
        empty.put("trade_volume",    BigDecimal.ZERO);
        empty.put("register_count",  0);
        empty.put("login_count",     0);
        empty.put("updated_time",    null);
        return empty;
    }

    private Map<String, Object> queryContractPnl(int includeInternal) {
        String sql = "SELECT self_hold_profit, self_hold_loss, " +
                     "       self_today_close_profit, self_today_close_loss, " +
                     "       self_total_close_profit, self_total_close_loss, " +
                     "       copy_hold_profit, copy_hold_loss, " +
                     "       copy_today_close_profit, copy_today_close_loss, " +
                     "       copy_total_close_profit, copy_total_close_loss, " +
                     "       updated_time " +
                     "FROM stat_contract_pnl " +
                     "WHERE stat_date = ? AND include_internal = ? " +
                     "LIMIT 1";
        try {
            Map<String, Object> row = jdbcTemplate.queryForMap(sql, LocalDate.now().toString(), includeInternal);
            Object updatedTime = row.get("updated_time");
            if (updatedTime instanceof LocalDateTime) {
                row.put("updated_time",
                        ((LocalDateTime) updatedTime).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            } else if (updatedTime != null) {
                row.put("updated_time", updatedTime.toString());
            }
            // 补充差额字段（差额 = 亏损 - 盈利）
            row.put("self_hold_diff",        toBD(row, "self_hold_loss").subtract(toBD(row, "self_hold_profit")));
            row.put("self_today_close_diff", toBD(row, "self_today_close_loss").subtract(toBD(row, "self_today_close_profit")));
            row.put("self_total_close_diff", toBD(row, "self_total_close_loss").subtract(toBD(row, "self_total_close_profit")));
            row.put("copy_hold_diff",        toBD(row, "copy_hold_loss").subtract(toBD(row, "copy_hold_profit")));
            row.put("copy_today_close_diff", toBD(row, "copy_today_close_loss").subtract(toBD(row, "copy_today_close_profit")));
            row.put("copy_total_close_diff", toBD(row, "copy_total_close_loss").subtract(toBD(row, "copy_total_close_profit")));
            return row;
        } catch (org.springframework.dao.EmptyResultDataAccessException e) {
            return buildEmptyContractPnlRow();
        }
    }

    private BigDecimal toBD(Map<String, Object> row, String key) {
        Object v = row.get(key);
        if (v instanceof BigDecimal) return (BigDecimal) v;
        if (v != null) return new BigDecimal(v.toString());
        return BigDecimal.ZERO;
    }

    private Map<String, Object> buildEmptyContractPnlRow() {
        Map<String, Object> empty = new HashMap<>();
        String[] fields = {
            "self_hold_profit", "self_hold_loss", "self_hold_diff",
            "self_today_close_profit", "self_today_close_loss", "self_today_close_diff",
            "self_total_close_profit", "self_total_close_loss", "self_total_close_diff",
            "copy_hold_profit", "copy_hold_loss", "copy_hold_diff",
            "copy_today_close_profit", "copy_today_close_loss", "copy_today_close_diff",
            "copy_total_close_profit", "copy_total_close_loss", "copy_total_close_diff"
        };
        for (String f : fields) empty.put(f, BigDecimal.ZERO);
        empty.put("updated_time", null);
        return empty;
    }

    // ── 平台每日盈亏统计 ──────────────────────────────────────────────────────────

    /**
     * 按日期范围查询平台每日盈亏明细。
     * GET /stat/dashboard/platform-daily-pnl?startDate=yyyy-MM-dd&endDate=yyyy-MM-dd&includeInternal=0
     * startDate/endDate 均可缺省（缺省则查全部历史）。
     */
    @GetMapping("/platform-daily-pnl")
    public MessageResult getPlatformDailyPnl(
            @RequestParam(value = "startDate",       required = false) String startDate,
            @RequestParam(value = "endDate",         required = false) String endDate,
            @RequestParam(value = "includeInternal", defaultValue = "0") int includeInternal) {
        try {
            StringBuilder sql = new StringBuilder(
                "SELECT stat_date, deposit_amount, withdraw_amount, " +
                "  self_open_count, self_open_amount, self_close_profit, self_close_loss, self_close_diff, self_fee, self_funding_fee, " +
                "  copy_open_count, copy_open_amount, copy_close_profit, copy_close_loss, copy_close_diff, copy_fee, copy_funding_fee " +
                "FROM stat_platform_daily_pnl " +
                "WHERE include_internal = ? ");
            List<Object> args = new ArrayList<>();
            args.add(includeInternal);
            if (startDate != null && !startDate.isEmpty()) {
                sql.append("AND stat_date >= ? ");
                args.add(startDate);
            }
            if (endDate != null && !endDate.isEmpty()) {
                sql.append("AND stat_date <= ? ");
                args.add(endDate);
            }
            sql.append("ORDER BY stat_date DESC");
            List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql.toString(), args.toArray());
            rows.forEach(row -> {
                Object d = row.get("stat_date");
                if (d != null) row.put("stat_date", d.toString());
            });
            return MessageResult.getSuccessInstance("SUCCESS", rows);
        } catch (Exception e) {
            log.error("[Dashboard] 获取平台每日盈亏统计失败", e);
            return MessageResult.getSuccessInstance("SUCCESS", new ArrayList<>());
        }
    }

    /**
     * 触发 datacenter 补算平台每日盈亏历史数据。
     * POST /stat/dashboard/platform-daily-pnl/backfill?days=30
     */
    @PostMapping("/platform-daily-pnl/backfill")
    public MessageResult backfillPlatformDailyPnl(
            @RequestParam(value = "days", defaultValue = "30") int days) {
        try {
            String url = datacenterHost + "/job/run/platform-daily-pnl/backfill?days=" + days;
            log.info("[Dashboard] 触发 datacenter 平台每日盈亏回填: {}", url);
            plainRestTemplate.postForObject(url, null, String.class);
        } catch (Exception e) {
            log.error("[Dashboard] 触发平台每日盈亏回填失败", e);
            return MessageResult.getSuccessInstance("FAILED", "回填失败：" + e.getMessage());
        }
        return MessageResult.getSuccessInstance("SUCCESS", "已触发回填 " + days + " 天历史数据");
    }
}
