package com.cloudhandson.vpdbackoffice.service;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import com.cloudhandson.vpdbackoffice.domain.vpd.VpdFunctionOption;
import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyFormOptions;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;

class VpdPolicyServiceTest {

  @Test
  void protectsTheDynamicPermissionFunctionFromManualOverwrite() {
    RecordingJdbcTemplate jdbcTemplate = new RecordingJdbcTemplate();
    VpdPolicyService service = new VpdPolicyService(null, jdbcTemplate, null);

    assertThatThrownBy(() -> service.saveFilterFunction(
        "ADMIN",
        "CB_AGENT_DOC_VPD_FILTER",
        "1=1"
    ))
        .isInstanceOf(AppException.class)
        .hasMessageContaining("권한체계")
        .hasMessageContaining("수정할 수 없습니다");

    assertThat(jdbcTemplate.updateCount).isZero();
  }

  @Test
  void defaultApplyAlwaysUsesTheDynamicPermissionFunction() {
    RecordingJdbcTemplate jdbcTemplate = new RecordingJdbcTemplate();
    VpdPolicyService service = new VpdPolicyService(null, jdbcTemplate, null) {
      @Override
      public VpdPolicyFormOptions formOptions() {
        return new VpdPolicyFormOptions(
            List.of(),
            List.of("ADMIN"),
            List.of("ADMIN"),
            List.of(new VpdFunctionOption("ADMIN", null, "CB_AGENT_DOC_VPD_FILTER", "FUNCTION")),
            List.of(),
            List.of("SELECT")
        );
      }
    };

    service.createDefaultPermissionPolicy("ADMIN.DOCUMENTS");

    assertThat(jdbcTemplate.lastSql).contains("DBMS_RLS.ADD_POLICY").contains("DBMS_RLS.DYNAMIC");
    assertThat(jdbcTemplate.lastArgs).containsExactly(
        "ADMIN",
        "DOCUMENTS",
        "CB_PERMISSION_SELECT_POLICY",
        "ADMIN",
        "CB_AGENT_DOC_VPD_FILTER",
        "SELECT"
    );
  }

  @Test
  void defaultApplyFailsClosedWhenPermissionFunctionIsNotInstalled() {
    VpdPolicyService service = new VpdPolicyService(null, new RecordingJdbcTemplate(), null) {
      @Override
      public VpdPolicyFormOptions formOptions() {
        return new VpdPolicyFormOptions(
            List.of(), List.of(), List.of(), List.of(), List.of(), List.of("SELECT")
        );
      }
    };

    assertThatThrownBy(() -> service.createDefaultPermissionPolicy("ADMIN.DOCUMENTS"))
        .isInstanceOf(AppException.class)
        .hasMessageContaining("동적 권한 필터")
        .hasMessageContaining("설치");
  }

  private static class RecordingJdbcTemplate extends JdbcTemplate {
    private String lastSql;
    private Object[] lastArgs = new Object[0];
    private int updateCount;

    @Override
    public <T> T queryForObject(String sql, Class<T> requiredType) {
      return requiredType.cast("ADMIN");
    }

    @Override
    public int update(String sql, Object... args) {
      lastSql = sql;
      lastArgs = args;
      updateCount++;
      return 1;
    }
  }
}
