package com.cloudhandson.ddsbackoffice.config;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.time.Duration;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;

class DdsPropertiesTest {

  @Test
  void normalizesObjectsAndUserKeys() {
    var properties = new DdsProperties(
        "jdbc:test",
        Duration.ofSeconds(5),
        "admin.v_dds_customers_pg",
        "admin.v_dds_customers_my",
        Map.of("MY", new DdsProperties.User("MY", "source", "ddsuser_my", "secret"))
    );

    assertEquals("ADMIN.V_DDS_CUSTOMERS_PG", properties.objectFor("pg"));
    assertEquals("ADMIN.V_DDS_CUSTOMERS_MY", properties.objectFor("MY"));
    assertEquals("ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS", properties.vectorObject());
    assertTrue(properties.users().containsKey("my"));
    assertTrue(properties.users().get("my").configured());
  }

  @Test
  void rejectsUnsafeObjectNames() {
    assertThrows(IllegalArgumentException.class, () -> new DdsProperties(
        "jdbc:test", Duration.ofSeconds(5), "ADMIN.VIEW;DROP", "ADMIN.VIEW", Map.of()
    ));
  }

  @Test
  void bindsApplicationUserAndDataRoleForDdsProvisioning() {
    var source = new MapConfigurationPropertySource(Map.of(
        "dds.users.my.label", "MY",
        "dds.users.my.description", "source",
        "dds.users.my.username", "ddsuser_my",
        "dds.users.my.password", "secret",
        "dds.users.my.application-user-id", "101",
        "dds.users.my.data-role", "dds_demo_my_role"
    ));

    var properties = new Binder(source)
        .bind("dds", Bindable.of(DdsProperties.class))
        .orElseThrow(() -> new AssertionError("dds properties did not bind"));

    assertEquals(101L, properties.users().get("my").applicationUserId());
    assertEquals("dds_demo_my_role", properties.users().get("my").dataRole());
    assertTrue(properties.users().get("my").mapped());
  }

  @Test
  void bindsTokenTechnicalUserSeparatelyFromApplicationUsers() {
    var source = new MapConfigurationPropertySource(Map.of(
        "dds.token.username", "dds_demo_token",
        "dds.token.password", "secret",
        "dds.token.data-role", "cb_dds_token_role"
    ));

    var properties = new Binder(source)
        .bind("dds", Bindable.of(DdsProperties.class))
        .orElseThrow(() -> new AssertionError("dds token properties did not bind"));

    assertEquals("dds_demo_token", properties.token().username());
    assertEquals("cb_dds_token_role", properties.token().dataRole());
    assertTrue(properties.token().configured());
  }
}
