-- ============================================================
-- 62_kb_aso_masking_backoffice_metadata.sql
--
-- Creates the metadata used by the masking-rule backoffice pages.
-- Run as ADMIN with SQLcl. This script does not create a DBMS_REDACT
-- policy; run 63_kb_aso_masking_rule_runtime.sql after rules are
-- connected to protected columns.
-- ============================================================
WHENEVER SQLERROR EXIT SQL.SQLCODE
SET DEFINE OFF
SET FEEDBACK ON

PROMPT === Creating masking-rule metadata tables ===
DECLARE
  PROCEDURE ensure_table(p_name IN VARCHAR2, p_ddl IN CLOB) IS
  BEGIN
    EXECUTE IMMEDIATE p_ddl;
    DBMS_OUTPUT.PUT_LINE('created ' || p_name);
  EXCEPTION
    WHEN OTHERS THEN
      IF SQLCODE = -955 THEN
        DBMS_OUTPUT.PUT_LINE('exists ' || p_name);
      ELSE
        RAISE;
      END IF;
  END;
BEGIN
  ensure_table('CB_MASKING_RULE', q'[
    CREATE TABLE cb_masking_rule (
      rule_id       NUMBER PRIMARY KEY,
      rule_code     VARCHAR2(64) NOT NULL UNIQUE,
      rule_name     VARCHAR2(100) NOT NULL,
      template_code VARCHAR2(30) NOT NULL,
      description   VARCHAR2(400),
      enabled_yn    CHAR(1) DEFAULT 'Y' CHECK (enabled_yn IN ('Y','N')) NOT NULL
    )]');

  ensure_table('CB_COLUMN_MASKING_RULE', q'[
    CREATE TABLE cb_column_masking_rule (
      column_id  NUMBER PRIMARY KEY,
      rule_id    NUMBER NOT NULL,
      updated_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
    )]');

  ensure_table('CB_USER_MASKING_RULE', q'[
    CREATE TABLE cb_user_masking_rule (
      user_id    NUMBER NOT NULL,
      column_id  NUMBER NOT NULL,
      decision   VARCHAR2(10) NOT NULL CHECK (decision IN ('MASK','UNMASK')),
      active_yn  CHAR(1) DEFAULT 'Y' CHECK (active_yn IN ('Y','N')) NOT NULL,
      updated_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,
      CONSTRAINT cb_user_masking_rule_pk PRIMARY KEY (user_id, column_id)
    )]');
END;
/

PROMPT === Seeding curated masking templates ===
DECLARE
  v_next_rule_id NUMBER;

  PROCEDURE ensure_rule(
      p_code        IN VARCHAR2,
      p_name        IN VARCHAR2,
      p_template    IN VARCHAR2,
      p_description IN VARCHAR2
  ) IS
  BEGIN
    MERGE INTO cb_masking_rule dst
    USING (
      SELECT p_code rule_code,
             p_name rule_name,
             p_template template_code,
             p_description description
      FROM dual
    ) src
    ON (dst.rule_code = src.rule_code)
    WHEN NOT MATCHED THEN
      INSERT (rule_id, rule_code, rule_name, template_code, description, enabled_yn)
      VALUES (v_next_rule_id, src.rule_code, src.rule_name, src.template_code, src.description, 'Y');
    v_next_rule_id := v_next_rule_id + 1;
  END;
BEGIN
  SELECT NVL(MAX(rule_id), 0) + 1 INTO v_next_rule_id FROM cb_masking_rule;
  ensure_rule('MASK_NULLIFY', '값 숨김 (NULL)', 'NULLIFY',
    '값을 NULL로 반환하는 기본 마스킹 방식');
  ensure_rule('MASK_FULL', '전체 마스킹', 'FULL',
    '문자형은 공백, 숫자형은 0으로 반환하는 전체 마스킹 방식');
  ensure_rule('MASK_TEXT_PARTIAL', '문자열 일부 마스킹', 'TEXT_PARTIAL',
    '첫 글자만 보이고 나머지는 가리는 문자열 마스킹 방식');
  ensure_rule('MASK_RRN_PARTIAL', '주민등록번호 부분 마스킹', 'RRN_PARTIAL',
    '앞 6자리만 보이고 나머지는 가리는 식별번호 마스킹 방식');
END;
/
COMMIT;

PROMPT === Metadata ready ===
SELECT rule_id, rule_code, rule_name, template_code, enabled_yn
FROM cb_masking_rule
ORDER BY rule_id;
EXIT
