package de.votian.services.service;

import de.votian.services.config.ParameterKeys;
import de.votian.services.entity.CostCenter;
import de.votian.services.entity.Customer;
import de.votian.services.entity.Employee;
import de.votian.services.entity.User;
import de.votian.services.repository.CostCenterRepository;
import de.votian.services.repository.CustomerRepository;
import de.votian.services.repository.EmployeeRepository;
import de.votian.services.repository.UserRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@SuppressWarnings("null")
class LegacyXmlCustomerAuthServiceTest {

    private CustomerRepository customerRepository;
    private UserRepository userRepository;
    private EmployeeRepository employeeRepository;
    private CostCenterRepository costCenterRepository;
    private JdbcTemplate jdbcTemplate;
    private ParameterService parameterService;
    private LegacyXmlCustomerAuthService service;

    @BeforeEach
    void setUp() {
        customerRepository = mock(CustomerRepository.class);
        userRepository = mock(UserRepository.class);
        employeeRepository = mock(EmployeeRepository.class);
        costCenterRepository = mock(CostCenterRepository.class);
        jdbcTemplate = mock(JdbcTemplate.class);
        parameterService = mock(ParameterService.class);
        service = new LegacyXmlCustomerAuthService(
                customerRepository,
                userRepository,
                employeeRepository,
                costCenterRepository,
                jdbcTemplate,
                parameterService
        );
    }

    @Test
    void authenticateAcceptsCustomerUserWithMatchingSessionHash() {
        Customer customer = new Customer();
        customer.setId(7L);
        customer.setEid("AG-100");
        customer.setCostCenterPayerId(70L);

        User user = new User();
        user.setId(9L);
        user.setAccount("api-user");

        Employee employee = new Employee();
        employee.setUserId(9L);
        employee.setCostCenterId(70L);

        CostCenter payerCostCenter = new CostCenter();
        payerCostCenter.setId(70L);
        payerCostCenter.setCustomerId(7L);

        when(customerRepository.findByEid("AG-100")).thenReturn(Optional.of(customer));
        when(userRepository.authenticate("api-user", "secret")).thenReturn(Optional.of(user));
        when(employeeRepository.findByUserId(9L)).thenReturn(Optional.of(employee));
        when(costCenterRepository.findById(70L)).thenReturn(Optional.of(payerCostCenter));
        when(parameterService.getParameterValue(ParameterKeys.GLOBAL_UNIQUE_DB_INSTANCE_NO, 0L)).thenReturn("100");
        when(jdbcTemplate.queryForObject(any(String.class), eq(Integer.class), eq("100"), eq(9L), eq("HASH")))
                .thenReturn(1);

        LegacyXmlCustomerAuthService.AuthContext result = service.authenticate(
                new LegacyXmlCustomerAuthService.AuthRequest("cs", "AG-100", "api-user", "secret", "HASH", "")
        );

        assertThat(result.customer().getId()).isEqualTo(7L);
        assertThat(result.user().getId()).isEqualTo(9L);
        assertThat(result.effectiveCostCenter()).isNotNull();
        assertThat(result.effectiveCostCenter().getId()).isEqualTo(70L);
    }

    @Test
    void authenticateRejectsUserOutsideCustomerScope() {
        Customer customer = new Customer();
        customer.setId(7L);
        customer.setEid("AG-100");

        User user = new User();
        user.setId(9L);

        Employee employee = new Employee();
        employee.setUserId(9L);
        employee.setCostCenterId(70L);

        CostCenter foreignCostCenter = new CostCenter();
        foreignCostCenter.setId(70L);
        foreignCostCenter.setCustomerId(99L);

        when(customerRepository.findByEid("AG-100")).thenReturn(Optional.of(customer));
        when(userRepository.authenticate("api-user", "secret")).thenReturn(Optional.of(user));
        when(employeeRepository.findByUserId(9L)).thenReturn(Optional.of(employee));
        when(costCenterRepository.findById(70L)).thenReturn(Optional.of(foreignCostCenter));

        assertThatThrownBy(() -> service.authenticate(
                new LegacyXmlCustomerAuthService.AuthRequest("", "AG-100", "api-user", "secret", "HASH", "")
        ))
                .isInstanceOf(LegacyXmlRequestException.class)
                .extracting("errorCode")
                .isEqualTo("101");
    }
}
