package com.writeoff.module.notification.service;

import com.writeoff.common.api.PageResult;
import com.writeoff.common.exception.BusinessException;
import com.writeoff.module.notification.dto.CreateNotificationPolicyRequest;
import com.writeoff.module.notification.dto.UpdateNotificationPolicyRequest;
import com.writeoff.module.notification.model.NotificationPolicyInfo;
import com.writeoff.security.AuthContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class NotificationPolicyService {
    private final JdbcTemplate jdbcTemplate;

    private static final RowMapper<NotificationPolicyInfo> POLICY_ROW_MAPPER = (rs, n) -> new NotificationPolicyInfo(
            rs.getLong("id"),
            rs.getString("policy_name"),
            rs.getString("event_code"),
            rs.getString("channel"),
            rs.getString("receiver_type"),
            rs.getLong("template_id"),
            rs.getString("variables_json"),
            rs.getString("status")
    );

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

    public PageResult<NotificationPolicyInfo> list(int pageNo, int pageSize) {
        int safePage = Math.max(pageNo, 1);
        int safeSize = Math.min(Math.max(pageSize, 1), 100);
        int offset = (safePage - 1) * safeSize;

        Integer total = jdbcTemplate.queryForObject(
                "SELECT COUNT(1) FROM notification_policy WHERE tenant_id=? AND is_deleted=0",
                Integer.class,
                tenantId()
        );
        long totalCount = total == null ? 0 : total;

        List<NotificationPolicyInfo> list = jdbcTemplate.query(
                "SELECT * FROM notification_policy WHERE tenant_id=? AND is_deleted=0 ORDER BY id DESC LIMIT ? OFFSET ?",
                POLICY_ROW_MAPPER,
                tenantId(),
                safeSize,
                offset
        );
        return new PageResult<NotificationPolicyInfo>(list, totalCount, safePage, safeSize);
    }

    @Transactional(rollbackFor = Exception.class)
    public NotificationPolicyInfo create(CreateNotificationPolicyRequest request) {
        validateTextTemplateExists(request.getTemplateId());
        String status = normalizeStatus(request.getStatus());
        jdbcTemplate.update(
                "INSERT INTO notification_policy (tenant_id, policy_name, event_code, channel, receiver_type, template_id, variables_json, status, created_by, updated_by) " +
                        "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
                tenantId(),
                request.getPolicyName(),
                request.getEventCode(),
                request.getChannel(),
                request.getReceiverType(),
                request.getTemplateId(),
                request.getVariablesJson(),
                status,
                safeUserId(),
                safeUserId()
        );
        Long id = jdbcTemplate.queryForObject("SELECT IFNULL(MAX(id),0) FROM notification_policy WHERE tenant_id=?", Long.class, tenantId());
        Long policyId = id == null ? 0L : id;
        upsertPolicyEvent(policyId, request.getEventCode(), status);
        return findById(policyId);
    }

    @Transactional(rollbackFor = Exception.class)
    public NotificationPolicyInfo update(Long id, UpdateNotificationPolicyRequest request) {
        assertExists(id);
        validateTextTemplateExists(request.getTemplateId());
        String status = normalizeStatus(request.getStatus());
        jdbcTemplate.update(
                "UPDATE notification_policy SET policy_name=?, event_code=?, channel=?, receiver_type=?, template_id=?, variables_json=?, status=?, updated_at=CURRENT_TIMESTAMP, updated_by=? " +
                        "WHERE tenant_id=? AND id=?",
                request.getPolicyName(),
                request.getEventCode(),
                request.getChannel(),
                request.getReceiverType(),
                request.getTemplateId(),
                request.getVariablesJson(),
                status,
                safeUserId(),
                tenantId(),
                id
        );
        upsertPolicyEvent(id, request.getEventCode(), status);
        return findById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    public NotificationPolicyInfo bindEvents(Long id, String eventCode) {
        assertExists(id);
        String normalizedEventCode = eventCode == null ? "" : eventCode.trim();
        if (normalizedEventCode.isEmpty()) {
            throw new BusinessException(10001, "事件编码不能为空");
        }
        NotificationPolicyInfo policy = findById(id);
        jdbcTemplate.update(
                "UPDATE notification_policy SET event_code=?, updated_at=CURRENT_TIMESTAMP, updated_by=? WHERE tenant_id=? AND id=?",
                normalizedEventCode,
                safeUserId(),
                tenantId(),
                id
        );
        upsertPolicyEvent(id, normalizedEventCode, policy.getStatus());
        return findById(id);
    }

    public NotificationPolicyInfo enable(Long id) {
        return updateStatus(id, "ENABLED");
    }

    public NotificationPolicyInfo disable(Long id) {
        return updateStatus(id, "DISABLED");
    }

    @Transactional(rollbackFor = Exception.class)
    public void softDelete(Long id) {
        assertExists(id);
        NotificationPolicyInfo policy = findById(id);
        if ("ENABLED".equals(policy.getStatus())) {
            throw new BusinessException(10001, "请先停用通知策略再删除");
        }
        jdbcTemplate.update(
                "UPDATE notification_policy SET is_deleted=1, updated_at=CURRENT_TIMESTAMP, updated_by=? WHERE tenant_id=? AND id=?",
                safeUserId(), tenantId(), id);
        // 同步清除策略事件绑定
        jdbcTemplate.update(
                "UPDATE notification_policy_event SET status='DISABLED', updated_at=CURRENT_TIMESTAMP, updated_by=? WHERE tenant_id=? AND policy_id=?",
                safeUserId(), tenantId(), id);
    }

    private NotificationPolicyInfo updateStatus(Long id, String status) {
        assertExists(id);
        jdbcTemplate.update(
                "UPDATE notification_policy SET status=?, updated_at=CURRENT_TIMESTAMP, updated_by=? WHERE tenant_id=? AND id=?",
                status,
                safeUserId(),
                tenantId(),
                id
        );
        jdbcTemplate.update(
                "UPDATE notification_policy_event SET status=?, updated_at=CURRENT_TIMESTAMP, updated_by=? WHERE tenant_id=? AND policy_id=?",
                status,
                safeUserId(),
                tenantId(),
                id
        );
        return findById(id);
    }

    private void upsertPolicyEvent(Long policyId, String eventCode, String status) {
        Integer count = jdbcTemplate.queryForObject(
                "SELECT COUNT(1) FROM notification_policy_event WHERE tenant_id=? AND policy_id=?",
                Integer.class,
                tenantId(),
                policyId
        );
        if (count == null || count == 0) {
            jdbcTemplate.update(
                "INSERT INTO notification_policy_event (tenant_id, policy_id, event_code, status, created_by, updated_by) VALUES (?, ?, ?, ?, ?, ?)",
                tenantId(), policyId, eventCode, status, safeUserId(), safeUserId()
            );
        } else {
            jdbcTemplate.update(
                "UPDATE notification_policy_event SET event_code=?, status=?, updated_at=CURRENT_TIMESTAMP, updated_by=? WHERE tenant_id=? AND policy_id=?",
                eventCode, status, safeUserId(), tenantId(), policyId
            );
        }
    }

    private String normalizeStatus(String status) {
        String val = status == null ? "ENABLED" : status.trim().toUpperCase();
        if (!"ENABLED".equals(val) && !"DISABLED".equals(val)) {
            throw new BusinessException(10001, "状态仅支持 ENABLED/DISABLED");
        }
        return val;
    }

    private void validateTextTemplateExists(Long templateId) {
        Integer count = jdbcTemplate.queryForObject(
                "SELECT COUNT(1) FROM notification_text_template WHERE tenant_id=? AND id=? AND is_deleted=0",
                Integer.class,
                tenantId(),
                templateId
        );
        if (count == null || count == 0) {
            throw new BusinessException(10003, "文案模板不存在");
        }
    }

    private NotificationPolicyInfo findById(Long id) {
        List<NotificationPolicyInfo> list = jdbcTemplate.query(
                "SELECT * FROM notification_policy WHERE tenant_id=? AND id=? AND is_deleted=0",
                POLICY_ROW_MAPPER,
                tenantId(),
                id
        );
        if (list.isEmpty()) {
            throw new BusinessException(10003, "通知策略不存在");
        }
        return list.get(0);
    }

    private void assertExists(Long id) {
        Integer count = jdbcTemplate.queryForObject(
                "SELECT COUNT(1) FROM notification_policy WHERE tenant_id=? AND id=? AND is_deleted=0",
                Integer.class,
                tenantId(),
                id
        );
        if (count == null || count == 0) {
            throw new BusinessException(10003, "通知策略不存在");
        }
    }

    private Long safeUserId() {
        Long userId = AuthContext.userId();
        return userId == null ? 0L : userId;
    }

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