package com.cloudhandson.vpdbackoffice.service;

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

import com.fasterxml.jackson.databind.ObjectMapper;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.jupiter.api.Test;
import org.mockito.InOrder;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;

class JdbcHmmAiAgentToolRunnerTest {

  @Test
  void setsAndClearsHMMContextOnTheSameConnection() throws Exception {
    JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
    Connection connection = mock(Connection.class);
    CallableStatement setContext = mock(CallableStatement.class);
    CallableStatement clearContext = mock(CallableStatement.class);
    PreparedStatement runTool = mock(PreparedStatement.class);
    ResultSet resultSet = mock(ResultSet.class);
    Clob clob = mock(Clob.class);

    when(jdbcTemplate.execute(any(ConnectionCallback.class))).thenAnswer(invocation -> {
      ConnectionCallback<?> callback = invocation.getArgument(0);
      return callback.doInConnection(connection);
    });
    when(connection.prepareCall(
        "BEGIN ADMIN.HMM_ACCESS_CTX_PKG.SET_USER_BY_BEARER(?); END;"))
        .thenReturn(setContext);
    when(connection.prepareCall("BEGIN ADMIN.HMM_ACCESS_CTX_PKG.CLEAR_USER; END;"))
        .thenReturn(clearContext);
    when(connection.prepareStatement(any(String.class))).thenReturn(runTool);
    when(runTool.executeQuery()).thenReturn(resultSet);
    when(resultSet.next()).thenReturn(true);
    when(resultSet.getClob(1)).thenReturn(clob);
    when(clob.length()).thenReturn(15L);
    when(clob.getSubString(1, 15)).thenReturn("{\"status\":\"ok\"}");

    var runner = new JdbcHmmAiAgentToolRunner(jdbcTemplate, new ObjectMapper());
    var result = runner.run(
        "HMM_HR_TERM_RESOLVER",
        new ObjectMapper().createObjectNode().put("P_TERM", "annual leave"),
        "opaque-user-token");

    assertThat(result.path("status").asText()).isEqualTo("ok");
    InOrder order = inOrder(connection, setContext, runTool, clearContext);
    order.verify(connection).prepareCall(
        "BEGIN ADMIN.HMM_ACCESS_CTX_PKG.SET_USER_BY_BEARER(?); END;");
    order.verify(setContext).setString(1, "opaque-user-token");
    order.verify(setContext).execute();
    order.verify(connection).prepareStatement(any(String.class));
    order.verify(runTool).executeQuery();
    order.verify(connection).prepareCall("BEGIN ADMIN.HMM_ACCESS_CTX_PKG.CLEAR_USER; END;");
    order.verify(clearContext).execute();
  }
}
