-- SGMP QA example vector store.
--
-- Run as SGMP_POC after scripts/setup-sgmp-qa-vector.sh has registered the
-- DBMS_VECTOR credential and granted the HTTPS ACL.  No API key material is
-- stored in this file.
--
-- Cohere Embed 4 is intentionally fixed to 1536 dimensions.  Stored examples
-- use search_document; incoming questions use search_query.

DECLARE
  v_count PLS_INTEGER;
BEGIN
  SELECT COUNT(*) INTO v_count
    FROM user_tables
   WHERE table_name = 'SG_QA_VECTOR_CONFIG';

  IF v_count = 0 THEN
    EXECUTE IMMEDIATE q'[
      CREATE TABLE sg_qa_vector_config (
        config_key   VARCHAR2(64) PRIMARY KEY,
        config_value VARCHAR2(4000) NOT NULL,
        updated_at   TIMESTAMP(6) DEFAULT SYSTIMESTAMP NOT NULL
      )]';
  END IF;
END;
/

MERGE INTO sg_qa_vector_config c
USING (
  SELECT 'CREDENTIAL_NAME' AS config_key, 'SGMP_POC_QA_VECTOR_CRED' AS config_value FROM dual
  UNION ALL SELECT 'ENDPOINT_URL', 'https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/actions/embedText' FROM dual
  UNION ALL SELECT 'MODEL_NAME', 'cohere.embed-v4.0' FROM dual
  UNION ALL SELECT 'DIMENSION', '1536' FROM dual
) s
ON (c.config_key = s.config_key)
WHEN MATCHED THEN UPDATE SET c.config_value = s.config_value, c.updated_at = SYSTIMESTAMP
WHEN NOT MATCHED THEN INSERT (config_key, config_value) VALUES (s.config_key, s.config_value);
/

DECLARE
  v_count PLS_INTEGER;
BEGIN
  SELECT COUNT(*) INTO v_count
    FROM user_tables
   WHERE table_name = 'SG_QA_VECTOR_EXAMPLE';

  IF v_count = 0 THEN
    EXECUTE IMMEDIATE q'[
      CREATE TABLE sg_qa_vector_example (
        example_id       NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
        question         CLOB NOT NULL,
        answer_sql       CLOB NOT NULL,
        answer_text      CLOB,
        embedding_input  CLOB NOT NULL,
        embedding        VECTOR(1536, FLOAT32) NOT NULL,
        embedding_model  VARCHAR2(128) DEFAULT 'cohere.embed-v4.0' NOT NULL,
        created_at       TIMESTAMP(6) DEFAULT SYSTIMESTAMP NOT NULL,
        updated_at       TIMESTAMP(6) DEFAULT SYSTIMESTAMP NOT NULL
      )]';
  END IF;
END;
/

CREATE OR REPLACE FUNCTION sg_qa_vector_params(p_input_type IN VARCHAR2)
  RETURN CLOB
AUTHID DEFINER
IS
  v_credential VARCHAR2(4000);
  v_endpoint   VARCHAR2(4000);
  v_model      VARCHAR2(4000);
BEGIN
  SELECT MAX(CASE WHEN config_key = 'CREDENTIAL_NAME' THEN config_value END),
         MAX(CASE WHEN config_key = 'ENDPOINT_URL' THEN config_value END),
         MAX(CASE WHEN config_key = 'MODEL_NAME' THEN config_value END)
    INTO v_credential, v_endpoint, v_model
    FROM sg_qa_vector_config;

  IF v_credential IS NULL OR v_endpoint IS NULL OR v_model IS NULL THEN
    RAISE_APPLICATION_ERROR(-20001, 'SG QA vector configuration is incomplete.');
  END IF;

  RETURN TO_CLOB('{"provider":"ocigenai","credential_name":"')
      || v_credential
      || '","url":"' || v_endpoint
      || '","model":"' || v_model
      || '","truncate":"END"}';
END;
/

CREATE OR REPLACE FUNCTION sg_qa_vector_store(
  p_question   IN CLOB,
  p_answer_sql IN CLOB,
  p_answer     IN CLOB DEFAULT NULL
) RETURN NUMBER
AUTHID DEFINER
IS
  v_input      CLOB;
  v_embedding  VECTOR;
  v_example_id NUMBER;
BEGIN
  IF p_question IS NULL OR p_answer_sql IS NULL THEN
    RAISE_APPLICATION_ERROR(-20002, 'question and answer_sql are required.');
  END IF;

  v_input := TO_CLOB('Question: ') || p_question
          || TO_CLOB(CHR(10) || 'Answer SQL: ') || p_answer_sql
          || CASE WHEN p_answer IS NULL THEN NULL ELSE TO_CLOB(CHR(10) || 'Answer: ') || p_answer END;
  v_embedding := DBMS_VECTOR.UTL_TO_EMBEDDING(
    v_input,
    JSON(sg_qa_vector_params('search_document'))
  );

  INSERT INTO sg_qa_vector_example (
    question, answer_sql, answer_text, embedding_input, embedding, embedding_model
  ) VALUES (
    p_question, p_answer_sql, p_answer, v_input, v_embedding, 'cohere.embed-v4.0'
  ) RETURNING example_id INTO v_example_id;

  RETURN v_example_id;
END;
/

CREATE OR REPLACE FUNCTION sg_qa_vector_search(
  p_question IN CLOB,
  p_top_k    IN PLS_INTEGER DEFAULT 3
) RETURN SYS_REFCURSOR
AUTHID DEFINER
IS
  v_query_vector VECTOR;
  v_results      SYS_REFCURSOR;
BEGIN
  IF p_question IS NULL THEN
    RAISE_APPLICATION_ERROR(-20003, 'question is required.');
  END IF;
  IF p_top_k IS NULL OR p_top_k < 1 OR p_top_k > 20 THEN
    RAISE_APPLICATION_ERROR(-20004, 'top_k must be between 1 and 20.');
  END IF;

  v_query_vector := DBMS_VECTOR.UTL_TO_EMBEDDING(
    p_question,
    JSON(sg_qa_vector_params('search_query'))
  );

  OPEN v_results FOR
    SELECT example_id,
           question,
           answer_sql,
           answer_text,
           embedding_model,
           vector_distance(embedding, v_query_vector, COSINE) AS cosine_distance
      FROM sg_qa_vector_example
     ORDER BY vector_distance(embedding, v_query_vector, COSINE), example_id
     FETCH FIRST p_top_k ROWS ONLY;
  RETURN v_results;
END;
/

CREATE OR REPLACE FUNCTION sg_qa_vector_context(
  p_question IN CLOB,
  p_top_k    IN PLS_INTEGER DEFAULT 3
) RETURN CLOB
AUTHID DEFINER
IS
  v_results SYS_REFCURSOR;
  v_id      NUMBER;
  v_q       CLOB;
  v_sql     CLOB;
  v_answer  CLOB;
  v_model   VARCHAR2(128);
  v_dist    NUMBER;
  v_context CLOB := EMPTY_CLOB();
BEGIN
  v_results := sg_qa_vector_search(p_question, p_top_k);
  LOOP
    FETCH v_results INTO v_id, v_q, v_sql, v_answer, v_model, v_dist;
    EXIT WHEN v_results%NOTFOUND;
    v_context := v_context
      || CASE WHEN DBMS_LOB.GETLENGTH(v_context) = 0 THEN NULL ELSE CHR(10) || CHR(10) END
      || '[Example ' || v_id || ', cosine_distance=' || TO_CHAR(v_dist, 'FM0D000000') || ']' || CHR(10)
      || 'Question: ' || v_q || CHR(10)
      || 'Answer SQL: ' || v_sql
      || CASE WHEN v_answer IS NULL THEN NULL ELSE CHR(10) || 'Answer: ' || v_answer END;
  END LOOP;
  CLOSE v_results;
  RETURN v_context;
END;
/

COMMENT ON TABLE sg_qa_vector_example IS
  'Question-to-SQL QA examples embedded with OCI GenAI Cohere Embed 4 for retrieval-augmented prompt context.';

COMMENT ON COLUMN sg_qa_vector_example.embedding IS
  '1536-dimensional Cohere Embed 4 document embedding; generated through the dedicated SGMP vector API credential.';
