package com.writeoff.module.dashboard.service;

import com.writeoff.security.AuthContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Service
public class OperationsDashboardService {
    private final JdbcTemplate jdbcTemplate;

    public OperationsDashboardService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public Map<String, Object> summary() {
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("notification", notificationSummary());
        data.put("export", exportSummary());
        data.put("alert", alertSummary());
        data.put("trends", trends());
        data.put("tops", tops());
        return data;
    }

    private Map<String, Object> notificationSummary() {
        Map<String, Object> m = new LinkedHashMap<String, Object>();
        m.put("todayTotal", intVal("SELECT COUNT(1) FROM notification_task WHERE tenant_id=? AND DATE(created_at)=CURDATE()", tenantId()));
        m.put("sentTotal", intVal("SELECT COUNT(1) FROM notification_task WHERE tenant_id=? AND status='SENT'", tenantId()));
        m.put("deliveredTotal", intVal("SELECT COUNT(1) FROM notification_task WHERE tenant_id=? AND status='DELIVERED'", tenantId()));
        m.put("failedTotal", intVal("SELECT COUNT(1) FROM notification_task WHERE tenant_id=? AND status='FAILED'", tenantId()));
        m.put("avgDispatchSeconds", doubleVal(
                "SELECT IFNULL(AVG(TIMESTAMPDIFF(SECOND, created_at, sent_at)),0) FROM notification_task WHERE tenant_id=? AND sent_at IS NOT NULL",
                tenantId()));
        return m;
    }

    private Map<String, Object> exportSummary() {
        Map<String, Object> m = new LinkedHashMap<String, Object>();
        m.put("todayTotal", intVal("SELECT COUNT(1) FROM export_task WHERE tenant_id=? AND DATE(created_at)=CURDATE()", tenantId()));
        m.put("successTotal", intVal("SELECT COUNT(1) FROM export_task WHERE tenant_id=? AND status='SUCCESS'", tenantId()));
        m.put("failedTotal", intVal("SELECT COUNT(1) FROM export_task WHERE tenant_id=? AND status='FAILED'", tenantId()));
        m.put("avgFinishSeconds", doubleVal(
                "SELECT IFNULL(AVG(TIMESTAMPDIFF(SECOND, created_at, finished_at)),0) FROM export_task WHERE tenant_id=? AND finished_at IS NOT NULL",
                tenantId()));
        m.put("expiring24h", intVal(
                "SELECT COUNT(1) FROM export_task WHERE tenant_id=? AND status='SUCCESS' AND download_token_expire_at IS NOT NULL AND download_token_expire_at<=DATE_ADD(NOW(), INTERVAL 24 HOUR) AND download_token_expire_at>=NOW()",
                tenantId()));
        return m;
    }

    private Map<String, Object> alertSummary() {
        Map<String, Object> m = new LinkedHashMap<String, Object>();
        m.put("activeTotal", intVal("SELECT COUNT(1) FROM alert_event WHERE tenant_id=? AND status='ACTIVE'", tenantId()));
        m.put("recoveredToday", intVal("SELECT COUNT(1) FROM alert_event WHERE tenant_id=? AND status='RECOVERED' AND DATE(recovered_at)=CURDATE()", tenantId()));
        m.put("avgRecoverMinutes", doubleVal(
                "SELECT IFNULL(AVG(TIMESTAMPDIFF(MINUTE, created_at, recovered_at)),0) FROM alert_event WHERE tenant_id=? AND status='RECOVERED' AND recovered_at IS NOT NULL",
                tenantId()));
        return m;
    }

    private Map<String, Object> trends() {
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("notification7d", trendRows("SELECT DATE_FORMAT(created_at, '%Y-%m-%d') AS d, COUNT(1) AS c FROM notification_task WHERE tenant_id=? AND created_at>=DATE_SUB(CURDATE(), INTERVAL 6 DAY) GROUP BY DATE_FORMAT(created_at, '%Y-%m-%d') ORDER BY d ASC"));
        data.put("export7d", trendRows("SELECT DATE_FORMAT(created_at, '%Y-%m-%d') AS d, COUNT(1) AS c FROM export_task WHERE tenant_id=? AND created_at>=DATE_SUB(CURDATE(), INTERVAL 6 DAY) GROUP BY DATE_FORMAT(created_at, '%Y-%m-%d') ORDER BY d ASC"));
        data.put("alert7d", trendRows("SELECT DATE_FORMAT(created_at, '%Y-%m-%d') AS d, COUNT(1) AS c FROM alert_event WHERE tenant_id=? AND created_at>=DATE_SUB(CURDATE(), INTERVAL 6 DAY) GROUP BY DATE_FORMAT(created_at, '%Y-%m-%d') ORDER BY d ASC"));
        return data;
    }

    private Map<String, Object> tops() {
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("notificationFailedChannels", jdbcTemplate.queryForList(
                "SELECT channel, COUNT(1) AS cnt FROM notification_task WHERE tenant_id=? AND status='FAILED' GROUP BY channel ORDER BY cnt DESC LIMIT 5",
                tenantId()
        ));
        data.put("exportBizTypeTop", jdbcTemplate.queryForList(
                "SELECT biz_type, COUNT(1) AS cnt FROM export_task WHERE tenant_id=? GROUP BY biz_type ORDER BY cnt DESC LIMIT 5",
                tenantId()
        ));
        data.put("alertRuleTop", jdbcTemplate.queryForList(
                "SELECT rule_code, COUNT(1) AS cnt FROM alert_event WHERE tenant_id=? GROUP BY rule_code ORDER BY cnt DESC LIMIT 5",
                tenantId()
        ));
        return data;
    }

    private List<Map<String, Object>> trendRows(String sql) {
        List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, tenantId());
        List<Map<String, Object>> out = new ArrayList<Map<String, Object>>();
        for (Map<String, Object> row : rows) {
            Map<String, Object> item = new LinkedHashMap<String, Object>();
            item.put("date", row.get("d"));
            item.put("count", row.get("c"));
            out.add(item);
        }
        return out;
    }

    private int intVal(String sql, Object... args) {
        Integer v = jdbcTemplate.queryForObject(sql, Integer.class, args);
        return v == null ? 0 : v;
    }

    private double doubleVal(String sql, Object... args) {
        Double v = jdbcTemplate.queryForObject(sql, Double.class, args);
        return v == null ? 0D : v;
    }

    private Long tenantId() {
        return AuthContext.requireTenantId();
    }
}
