package cn.novalon.gym.manage.sys.core.service.impl;

import cn.novalon.gym.manage.common.util.StatusConstants;
import cn.novalon.gym.manage.sys.audit.AuditLogHelper;
import cn.novalon.gym.manage.sys.audit.service.IAuditLogService;
import cn.novalon.gym.manage.sys.core.domain.SysPermission;
import cn.novalon.gym.manage.sys.core.domain.SysRolePermission;
import cn.novalon.gym.manage.sys.core.repository.ISysPermissionRepository;
import cn.novalon.gym.manage.sys.core.repository.ISysRolePermissionRepository;
import cn.novalon.gym.manage.sys.core.service.ISysPermissionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 系统权限服务实现类
 * 
 * @author 张翔
 * @date 2026-03-25
 */
@Service
public class SysPermissionService implements ISysPermissionService {

    private static final Logger logger = LoggerFactory.getLogger(SysPermissionService.class);

    private final ISysPermissionRepository permissionRepository;
    private final ISysRolePermissionRepository rolePermissionRepository;
    private final IAuditLogService auditLogService;

    public SysPermissionService(ISysPermissionRepository permissionRepository, 
                                ISysRolePermissionRepository rolePermissionRepository,
                                IAuditLogService auditLogService) {
        this.permissionRepository = permissionRepository;
        this.rolePermissionRepository = rolePermissionRepository;
        this.auditLogService = auditLogService;
    }

    @Override
    public Mono<SysPermission> findById(Long id) {
        return permissionRepository.findById(id);
    }

    @Override
    public Flux<SysPermission> findAll() {
        return permissionRepository.findAll();
    }

    @Override
    public Flux<SysPermission> findAll(Sort sort) {
        return permissionRepository.findAll(sort);
    }

    @Override
    public Mono<SysPermission> findByPermissionCode(String permissionCode) {
        return permissionRepository.findByPermissionCode(permissionCode);
    }

    @Override
    public Mono<Long> count() {
        return permissionRepository.count();
    }

    @Override
    public Mono<SysPermission> createPermission(SysPermission permission) {
        if (permission.getStatus() == null) {
            permission.setStatus(StatusConstants.ENABLED);
        }
        return permissionRepository.save(permission)
                .flatMap(saved -> AuditLogHelper.record(auditLogService, "Permission", saved.getId(), "CREATE", saved)
                        .doOnError(e -> logger.error("Audit log failed for Permission CREATE id={}: {}", saved.getId(), e.getMessage()))
                        .thenReturn(saved));
    }

    @Override
    public Mono<SysPermission> updatePermission(SysPermission permission) {
        permission.setUpdatedAt(LocalDateTime.now());
        return permissionRepository.findById(permission.getId())
                .flatMap(before -> permissionRepository.updatePermission(permission)
                        .flatMap(saved -> AuditLogHelper.record(auditLogService, "Permission", saved.getId(), "UPDATE", before, saved)
                                .thenReturn(saved)));
    }

    @Override
    public Mono<Void> deletePermission(Long id) {
        return permissionRepository.findById(id)
                .flatMap(permission -> {
                    SysPermission before = new SysPermission();
                    before.setId(permission.getId());
                    before.setPermissionName(permission.getPermissionName());
                    before.setPermissionCode(permission.getPermissionCode());
                    before.setResource(permission.getResource());
                    before.setAction(permission.getAction());
                    before.setStatus(permission.getStatus());
                    before.setCreatedAt(permission.getCreatedAt());
                    before.setUpdatedAt(permission.getUpdatedAt());
                    before.setDeletedAt(permission.getDeletedAt());
                    permission.delete();
                    return permissionRepository.updatePermission(permission)
                            .flatMap(saved -> AuditLogHelper.record(auditLogService, "Permission", id, "DELETE", before, saved))
                            .then(rolePermissionRepository.deleteByPermissionId(id));
                });
    }

    @Override
    public Mono<Boolean> existsByPermissionCode(String permissionCode) {
        return permissionRepository.existsByPermissionCode(permissionCode);
    }

    @Override
    public Flux<SysPermission> findByRoleId(Long roleId) {
        return permissionRepository.findByRoleId(roleId);
    }

    @Override
    public Flux<SysPermission> findByRoleIds(List<Long> roleIds) {
        return permissionRepository.findByRoleIds(roleIds);
    }

    @Override
    @Transactional(transactionManager = "connectionFactoryTransactionManager")
    public Mono<Void> assignPermissionsToRole(Long roleId, List<Long> permissionIds) {
        return rolePermissionRepository.deleteByRoleId(roleId)
                .then(Flux.fromIterable(permissionIds)
                        .flatMap(permissionId -> {
                            SysRolePermission rolePermission = new SysRolePermission();
                            rolePermission.setRoleId(roleId);
                            rolePermission.setPermissionId(permissionId);
                            return rolePermissionRepository.save(rolePermission);
                        })
                        .then());
    }

    @Override
    public Flux<SysPermission> getPermissionsByRoleId(Long roleId) {
        return permissionRepository.findByRoleId(roleId);
    }
}