package com.writeoff.security;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

class PermissionServiceDelegationTest {

    @AfterEach
    void tearDown() {
        AuthContext.clear();
    }

    @Test
    void shouldInheritPermissionFromPrincipalWhenDelegationEnabled() {
        JdbcTemplate jdbcTemplate = Mockito.mock(JdbcTemplate.class);
        PermissionService permissionService = new PermissionService(jdbcTemplate);
        AuthContext.set(2001L, 1L);

        Mockito.when(jdbcTemplate.queryForObject(
                Mockito.eq("SELECT COUNT(1) FROM user_role ur " +
                        "JOIN role_permission rp ON ur.role_id=rp.role_id AND ur.tenant_id=rp.tenant_id " +
                        "JOIN permission p ON rp.permission_id=p.id " +
                        "WHERE ur.user_id=? AND ur.tenant_id=? AND p.permission_code=?"),
                Mockito.eq(Integer.class),
                Mockito.eq(2001L),
                Mockito.eq(1L),
                Mockito.eq("meeting.approve")
        )).thenReturn(0);

        Mockito.when(jdbcTemplate.queryForList(
                Mockito.eq("SELECT user_id FROM user_delegation " +
                        "WHERE tenant_id=? AND delegate_user_id=? AND is_deleted=0 AND status='ENABLED' " +
                        "AND effective_from<=CURRENT_TIMESTAMP AND effective_to>=CURRENT_TIMESTAMP"),
                Mockito.eq(Long.class),
                Mockito.eq(1L),
                Mockito.eq(2001L)
        )).thenReturn(Collections.singletonList(1001L));

        Mockito.when(jdbcTemplate.queryForObject(
                Mockito.eq("SELECT COUNT(1) FROM user_role ur " +
                        "JOIN role_permission rp ON ur.role_id=rp.role_id AND ur.tenant_id=rp.tenant_id " +
                        "JOIN permission p ON rp.permission_id=p.id " +
                        "WHERE ur.user_id=? AND ur.tenant_id=? AND p.permission_code=?"),
                Mockito.eq(Integer.class),
                Mockito.eq(1001L),
                Mockito.eq(1L),
                Mockito.eq("meeting.approve")
        )).thenReturn(1);

        boolean ok = permissionService.hasPermission(2001L, "meeting.approve");
        Assertions.assertTrue(ok);
    }

    @Test
    void shouldMergePermissionsFromSelfAndDelegationWithoutDuplicates() {
        JdbcTemplate jdbcTemplate = Mockito.mock(JdbcTemplate.class);
        PermissionService permissionService = new PermissionService(jdbcTemplate);
        AuthContext.set(2001L, 1L);

        Mockito.when(jdbcTemplate.queryForList(
                Mockito.eq("SELECT DISTINCT p.permission_code FROM user_role ur " +
                        "JOIN role_permission rp ON ur.role_id=rp.role_id AND ur.tenant_id=rp.tenant_id " +
                        "JOIN permission p ON rp.permission_id=p.id " +
                        "WHERE ur.user_id=? AND ur.tenant_id=?"),
                Mockito.eq(String.class),
                Mockito.eq(2001L),
                Mockito.eq(1L)
        )).thenReturn(Arrays.asList("user.read", "user.delegation.manage"));

        Mockito.when(jdbcTemplate.queryForList(
                Mockito.eq("SELECT user_id FROM user_delegation " +
                        "WHERE tenant_id=? AND delegate_user_id=? AND is_deleted=0 AND status='ENABLED' " +
                        "AND effective_from<=CURRENT_TIMESTAMP AND effective_to>=CURRENT_TIMESTAMP"),
                Mockito.eq(Long.class),
                Mockito.eq(1L),
                Mockito.eq(2001L)
        )).thenReturn(Collections.singletonList(1001L));

        Mockito.when(jdbcTemplate.queryForList(
                Mockito.eq("SELECT DISTINCT p.permission_code FROM user_role ur " +
                        "JOIN role_permission rp ON ur.role_id=rp.role_id AND ur.tenant_id=rp.tenant_id " +
                        "JOIN permission p ON rp.permission_id=p.id " +
                        "WHERE ur.user_id=? AND ur.tenant_id=?"),
                Mockito.eq(String.class),
                Mockito.eq(1001L),
                Mockito.eq(1L)
        )).thenReturn(Arrays.asList("meeting.approve", "user.read"));

        List<String> perms = permissionService.getPermissions(2001L);
        Assertions.assertTrue(perms.contains("user.read"));
        Assertions.assertTrue(perms.contains("user.delegation.manage"));
        Assertions.assertTrue(perms.contains("meeting.approve"));
        Assertions.assertEquals(3, perms.size());
    }
}
