package com.writeoff.module.auth.service;

import com.writeoff.common.exception.BusinessException;
import com.writeoff.common.exception.ErrorCodes;
import com.writeoff.module.auth.model.PlatformAuthSessionInfo;
import com.writeoff.security.AuthScope;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service
public class PlatformAuthSessionService {
    private final JdbcTemplate jdbcTemplate;

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

    public List<PlatformAuthSessionInfo> list(String scope, String status, Long userId, Long tenantId) {
        StringBuilder sql = new StringBuilder();
        List<Object> args = new ArrayList<Object>();
        sql.append("SELECT t.id, t.user_id, t.tenant_id, t.scope, t.status, ");
        sql.append("CASE WHEN t.scope='TENANT' THEN su.user_name ELSE pu.user_name END AS user_name, ");
        sql.append("CASE WHEN t.scope='TENANT' THEN su.phone ELSE pu.phone END AS phone, ");
        sql.append("te.tenant_name, ");
        sql.append("DATE_FORMAT(t.issued_at, '%Y-%m-%d %H:%i:%s') AS issued_at, ");
        sql.append("DATE_FORMAT(t.expires_at, '%Y-%m-%d %H:%i:%s') AS expires_at, ");
        sql.append("DATE_FORMAT(t.last_used_at, '%Y-%m-%d %H:%i:%s') AS last_used_at, ");
        sql.append("DATE_FORMAT(t.revoked_at, '%Y-%m-%d %H:%i:%s') AS revoked_at, ");
        sql.append("t.revoked_reason ");
        sql.append("FROM auth_refresh_token t ");
        sql.append("LEFT JOIN sys_user su ON t.scope='TENANT' AND su.id=t.user_id AND su.tenant_id=t.tenant_id ");
        sql.append("LEFT JOIN tenant te ON te.id=t.tenant_id ");
        sql.append("LEFT JOIN platform_user pu ON t.scope='PLATFORM' AND pu.id=t.user_id ");
        sql.append("WHERE t.is_deleted=0 ");
        if (scope != null && !scope.trim().isEmpty()) {
            sql.append("AND t.scope=? ");
            args.add(scope.trim().toUpperCase());
        }
        if (status != null && !status.trim().isEmpty()) {
            sql.append("AND t.status=? ");
            args.add(status.trim().toUpperCase());
        }
        if (userId != null && userId > 0) {
            sql.append("AND t.user_id=? ");
            args.add(userId);
        }
        if (tenantId != null && tenantId > 0) {
            sql.append("AND t.tenant_id=? ");
            args.add(tenantId);
        }
        sql.append("ORDER BY t.id DESC LIMIT 500");
        List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql.toString(), args.toArray());
        List<PlatformAuthSessionInfo> list = new ArrayList<PlatformAuthSessionInfo>();
        for (Map<String, Object> row : rows) {
            list.add(new PlatformAuthSessionInfo(
                    ((Number) row.get("id")).longValue(),
                    ((Number) row.get("user_id")).longValue(),
                    row.get("tenant_id") == null ? null : ((Number) row.get("tenant_id")).longValue(),
                    str(row.get("scope")),
                    str(row.get("status")),
                    str(row.get("user_name")),
                    str(row.get("phone")),
                    str(row.get("tenant_name")),
                    str(row.get("issued_at")),
                    str(row.get("expires_at")),
                    str(row.get("last_used_at")),
                    str(row.get("revoked_at")),
                    str(row.get("revoked_reason"))
            ));
        }
        return list;
    }

    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> revokeBySessionId(Long sessionId) {
        List<Map<String, Object>> rows = jdbcTemplate.queryForList(
                "SELECT id, status FROM auth_refresh_token WHERE id=? AND is_deleted=0 LIMIT 1",
                sessionId
        );
        if (rows.isEmpty()) {
            throw new BusinessException(ErrorCodes.RESOURCE_NOT_FOUND, "会话不存在");
        }
        jdbcTemplate.update(
                "UPDATE auth_refresh_token SET status='REVOKED', revoked_at=CURRENT_TIMESTAMP, revoked_reason='ADMIN_REVOKE', updated_at=CURRENT_TIMESTAMP " +
                        "WHERE id=? AND status='ACTIVE'",
                sessionId
        );
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("sessionId", sessionId);
        data.put("ok", Boolean.TRUE);
        return data;
    }

    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> revokeByPrincipal(Long userId, Long tenantId, String scopeRaw) {
        AuthScope scope = AuthScope.fromClaim(scopeRaw);
        if (scope == AuthScope.TENANT && (tenantId == null || tenantId <= 0)) {
            throw new BusinessException(ErrorCodes.VALIDATION_ERROR, "租户会话撤销时tenantId不能为空");
        }
        int affected;
        if (scope == AuthScope.TENANT) {
            affected = jdbcTemplate.update(
                    "UPDATE auth_refresh_token SET status='REVOKED', revoked_at=CURRENT_TIMESTAMP, revoked_reason='ADMIN_REVOKE_PRINCIPAL', updated_at=CURRENT_TIMESTAMP " +
                            "WHERE user_id=? AND tenant_id=? AND scope='TENANT' AND status='ACTIVE' AND is_deleted=0",
                    userId,
                    tenantId
            );
        } else {
            affected = jdbcTemplate.update(
                    "UPDATE auth_refresh_token SET status='REVOKED', revoked_at=CURRENT_TIMESTAMP, revoked_reason='ADMIN_REVOKE_PRINCIPAL', updated_at=CURRENT_TIMESTAMP " +
                            "WHERE user_id=? AND tenant_id IS NULL AND scope='PLATFORM' AND status='ACTIVE' AND is_deleted=0",
                    userId
            );
        }
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("affected", affected);
        data.put("ok", Boolean.TRUE);
        return data;
    }

    private String str(Object value) {
        return value == null ? "" : String.valueOf(value);
    }
}
