package com.writeoff.module.system.service;

import com.writeoff.common.api.PageResult;
import com.writeoff.common.exception.BusinessException;
import com.writeoff.module.system.dto.CreateUserDelegationRequest;
import com.writeoff.module.system.dto.DisableDelegationRequest;
import com.writeoff.module.system.model.UserDelegationInfo;
import com.writeoff.security.AuthContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

@Service
public class UserDelegationService {
    private final JdbcTemplate jdbcTemplate;

    private static final RowMapper<UserDelegationInfo> ROW_MAPPER = (rs, n) -> new UserDelegationInfo(
            rs.getLong("id"),
            rs.getLong("user_id"),
            rs.getLong("delegate_user_id"),
            rs.getString("effective_from"),
            rs.getString("effective_to"),
            rs.getString("status"),
            rs.getString("reason"),
            rs.getString("disabled_reason"),
            rs.getString("created_at")
    );

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

    public PageResult<UserDelegationInfo> listByUserId(Long userId) {
        assertUserExists(userId);
        markAutoExpiredByTenant();
        List<UserDelegationInfo> list = jdbcTemplate.query(
                "SELECT id, user_id, delegate_user_id, " +
                        "DATE_FORMAT(effective_from, '%Y-%m-%d %H:%i:%s') AS effective_from, " +
                        "DATE_FORMAT(effective_to, '%Y-%m-%d %H:%i:%s') AS effective_to, " +
                        "status, reason, disabled_reason, DATE_FORMAT(created_at, '%Y-%m-%d %H:%i:%s') AS created_at " +
                        "FROM user_delegation WHERE tenant_id=? AND user_id=? AND is_deleted=0 ORDER BY id DESC",
                ROW_MAPPER,
                tenantId(),
                userId
        );
        return new PageResult<>(list, list.size(), 1, 50);
    }

    public UserDelegationInfo create(Long userId, CreateUserDelegationRequest request) {
        assertUserExists(userId);
        assertUserExists(request.getDelegateUserId());
        if (userId.equals(request.getDelegateUserId())) {
            throw new BusinessException(10001, "代理人不能与被代理人相同");
        }
        Timestamp from = parseTimestamp(request.getEffectiveFrom());
        Timestamp to = parseTimestamp(request.getEffectiveTo());
        if (!to.after(from)) {
            throw new BusinessException(10001, "失效时间必须晚于生效时间");
        }
        String status = from.toLocalDateTime().isAfter(LocalDateTime.now()) ? "PENDING" : "ENABLED";
        jdbcTemplate.update(
                "INSERT INTO user_delegation (tenant_id, user_id, delegate_user_id, effective_from, effective_to, status, reason, is_deleted, created_by, updated_by) " +
                        "VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?)",
                tenantId(),
                userId,
                request.getDelegateUserId(),
                from,
                to,
                status,
                normalizeNullable(request.getReason()),
                safeUserId(),
                safeUserId()
        );
        Long id = jdbcTemplate.queryForObject("SELECT IFNULL(MAX(id), 0) FROM user_delegation WHERE tenant_id=?", Long.class, tenantId());
        return findById(id == null ? 0L : id);
    }

    public void disable(Long delegationId, DisableDelegationRequest request) {
        markAutoExpiredByTenant();
        UserDelegationInfo item = findById(delegationId);
        if ("DISABLED".equals(item.getStatus()) || "EXPIRED".equals(item.getStatus())) {
            return;
        }
        jdbcTemplate.update(
                "UPDATE user_delegation SET status='DISABLED', disabled_reason=?, updated_by=?, updated_at=CURRENT_TIMESTAMP " +
                        "WHERE tenant_id=? AND id=?",
                request.getReason().trim(),
                safeUserId(),
                tenantId(),
                delegationId
        );
    }

    public void markAutoExpiredByTenant() {
        jdbcTemplate.update(
                "UPDATE user_delegation SET status='EXPIRED', updated_by=?, updated_at=CURRENT_TIMESTAMP " +
                        "WHERE tenant_id=? AND is_deleted=0 AND status IN ('PENDING','ENABLED') AND effective_to < CURRENT_TIMESTAMP",
                safeUserId(),
                tenantId()
        );
        jdbcTemplate.update(
                "UPDATE user_delegation SET status='ENABLED', updated_by=?, updated_at=CURRENT_TIMESTAMP " +
                        "WHERE tenant_id=? AND is_deleted=0 AND status='PENDING' AND effective_from <= CURRENT_TIMESTAMP AND effective_to >= CURRENT_TIMESTAMP",
                safeUserId(),
                tenantId()
        );
    }

    public void markAutoExpiredAllTenants() {
        jdbcTemplate.update(
                "UPDATE user_delegation SET status='EXPIRED', updated_by=0, updated_at=CURRENT_TIMESTAMP " +
                        "WHERE is_deleted=0 AND status IN ('PENDING','ENABLED') AND effective_to < CURRENT_TIMESTAMP"
        );
        jdbcTemplate.update(
                "UPDATE user_delegation SET status='ENABLED', updated_by=0, updated_at=CURRENT_TIMESTAMP " +
                        "WHERE is_deleted=0 AND status='PENDING' AND effective_from <= CURRENT_TIMESTAMP AND effective_to >= CURRENT_TIMESTAMP"
        );
    }

    private UserDelegationInfo findById(Long id) {
        List<UserDelegationInfo> list = jdbcTemplate.query(
                "SELECT id, user_id, delegate_user_id, " +
                        "DATE_FORMAT(effective_from, '%Y-%m-%d %H:%i:%s') AS effective_from, " +
                        "DATE_FORMAT(effective_to, '%Y-%m-%d %H:%i:%s') AS effective_to, " +
                        "status, reason, disabled_reason, DATE_FORMAT(created_at, '%Y-%m-%d %H:%i:%s') AS created_at " +
                        "FROM user_delegation WHERE tenant_id=? AND id=? AND is_deleted=0",
                ROW_MAPPER,
                tenantId(),
                id
        );
        if (list.isEmpty()) {
            throw new BusinessException(10003, "代理授权不存在");
        }
        return list.get(0);
    }

    private void assertUserExists(Long userId) {
        Integer count = jdbcTemplate.queryForObject(
                "SELECT COUNT(1) FROM sys_user WHERE tenant_id=? AND id=? AND is_deleted=0",
                Integer.class,
                tenantId(),
                userId
        );
        if (count == null || count == 0) {
            throw new BusinessException(10003, "用户不存在");
        }
    }

    private Timestamp parseTimestamp(String raw) {
        String value = normalizeDateTimeString(raw);
        return Timestamp.valueOf(LocalDateTime.parse(value, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    }

    private String normalizeDateTimeString(String raw) {
        String value = raw == null ? "" : raw.trim().replace("T", " ");
        if (value.length() == 16) {
            return value + ":00";
        }
        return value;
    }

    private String normalizeNullable(String value) {
        if (value == null) {
            return null;
        }
        String t = value.trim();
        return t.isEmpty() ? null : t;
    }

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

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