-- RTGS 권위 원장 스키마 (PostgreSQL, 강한 일관성). 엔티티: common/ledger/Entities.kt 와 정합.
-- ddl-auto=none 이므로 이 스크립트가 스키마를 생성한다(컨테이너 최초 기동 시 1회).

CREATE TABLE IF NOT EXISTS account (
    code    VARCHAR(4)  PRIMARY KEY,
    name    VARCHAR(64) NOT NULL,
    balance BIGINT      NOT NULL DEFAULT 0
);

CREATE TABLE IF NOT EXISTS transfer (
    bmi            VARCHAR(22) PRIMARY KEY,
    global_seq     BIGINT,
    status         VARCHAR(8)  NOT NULL,
    sender_code    VARCHAR(4),
    receiver_code  VARCHAR(4),
    amount         BIGINT      NOT NULL,
    origin_center  VARCHAR(8),
    created_at     BIGINT,
    updated_at     BIGINT,
    reason         VARCHAR(255)
);
CREATE INDEX IF NOT EXISTS idx_transfer_seq ON transfer (global_seq);
CREATE INDEX IF NOT EXISTS idx_transfer_status ON transfer (status);

-- 선(先)저널(write-ahead) 로그: 무손실 승계·감사
CREATE TABLE IF NOT EXISTS journal_log (
    global_seq       BIGINT  PRIMARY KEY,
    bmi              VARCHAR(22),
    seq_epoch_millis BIGINT,
    applied          BOOLEAN NOT NULL DEFAULT FALSE
);

-- 원전문 저장 (로컬 PostgreSQL text; 클라우드/BMT는 문서형 DB(MongoDB)).
CREATE TABLE IF NOT EXISTS raw_message (
    bmi           VARCHAR(22) PRIMARY KEY,
    msg_type      VARCHAR(32),
    raw_xml       TEXT,
    orig_hash     VARCHAR(64),
    received_at   BIGINT,
    origin_center VARCHAR(8)
);

-- 조회 전용 사본 (로컬 PostgreSQL; 클라우드/BMT는 문서형 DB).
CREATE TABLE IF NOT EXISTS settlement_view (
    bmi                    VARCHAR(22) PRIMARY KEY,
    global_seq             BIGINT,
    final_status           VARCHAR(8),
    sender_code            VARCHAR(4),
    receiver_code          VARCHAR(4),
    amount                 BIGINT,
    origin_center          VARCHAR(8),
    processed_center       VARCHAR(8),
    debtor_balance_after   BIGINT,
    creditor_balance_after BIGINT,
    finalized_at           BIGINT
);

-- 결과통보 아웃박스 — 접수센터(Chanel)가 신청/수취기관 앞 송부한 결과 전문(pacs.002).
CREATE TABLE IF NOT EXISTS notification (
    id            VARCHAR(32) PRIMARY KEY,   -- bmi:수신기관
    bmi           VARCHAR(22),
    to_org        VARCHAR(4),                -- 수신 대상 기관
    role          VARCHAR(12),               -- APPLICANT(신청) / BENEFICIARY(수취)
    final_status  VARCHAR(8),
    pacs002_xml   TEXT,
    origin_center VARCHAR(8),
    reason        TEXT,
    delivered     BOOLEAN NOT NULL DEFAULT FALSE,
    attempts      INTEGER NOT NULL DEFAULT 0,
    created_at    BIGINT,
    delivered_at  BIGINT
);
ALTER TABLE notification ADD COLUMN IF NOT EXISTS attempts INTEGER NOT NULL DEFAULT 0;
CREATE INDEX IF NOT EXISTS idx_notification_bmi ON notification (bmi);
CREATE INDEX IF NOT EXISTS idx_notification_pending ON notification (delivered);

-- Gucci 콜백 레지스트리 — 기관별 결과통보 수신 URL. Gucci(관문)가 pacs.002를 여기로 송부(재시도/ACK).
-- 로컬 데모는 Gucci 자체 sink(:8095/gucci/sink/{org})로 자기수신해 왕복을 시연.
CREATE TABLE IF NOT EXISTS institution_endpoint (
    org_code     VARCHAR(4) PRIMARY KEY,
    callback_url VARCHAR(256),
    active       BOOLEAN NOT NULL DEFAULT TRUE,
    created_at   BIGINT
);
INSERT INTO institution_endpoint(org_code, callback_url, active, created_at) VALUES
  ('1001','http://localhost:8095/gucci/sink/1001',TRUE,0),
  ('1002','http://localhost:8095/gucci/sink/1002',TRUE,0),
  ('1008','http://localhost:8095/gucci/sink/1008',TRUE,0),
  ('1010','http://localhost:8095/gucci/sink/1010',TRUE,0)
ON CONFLICT (org_code) DO NOTHING;
COMMENT ON COLUMN notification.bmi          IS '거래식별자(BMI)';
COMMENT ON COLUMN notification.to_org       IS '통보대상기관';
COMMENT ON COLUMN notification.role         IS '대상역할(신청/수취)';
COMMENT ON COLUMN notification.final_status IS '최종상태';
COMMENT ON COLUMN notification.pacs002_xml  IS '결과전문(pacs.002)';
COMMENT ON COLUMN notification.delivered    IS '송부여부';
COMMENT ON COLUMN notification.created_at   IS '생성시각';

-- 참가기관 당좌계좌 시드 (19개). 초기 잔액 10억원(부하테스트 1~200원 이체가 고갈되지 않도록).
INSERT INTO account (code, name, balance) VALUES
    ('1001', 'KOOKMIN',        1000000000),
    ('1002', 'SHINHAN',        1000000000),
    ('1003', 'WOORI',          1000000000),
    ('1004', 'HANA',           1000000000),
    ('1005', 'NONGHYUP',       1000000000),
    ('1006', 'IBK',            1000000000),
    ('1007', 'SC',             1000000000),
    ('1008', 'CITI',           1000000000),
    ('1009', 'KDB',            1000000000),
    ('1010', 'SUHYUP',         1000000000),
    ('1011', 'DGB',            1000000000),
    ('1012', 'BNK_BUSAN',      1000000000),
    ('1013', 'BNK_KYONGNAM',   1000000000),
    ('1014', 'KWANGJU',        1000000000),
    ('1015', 'JEONBUK',        1000000000),
    ('1016', 'JEJU',           1000000000),
    ('1017', 'KAKAOBANK',      1000000000),
    ('1018', 'KBANK',          1000000000),
    ('1019', 'TOSSBANK',       1000000000)
ON CONFLICT (code) DO NOTHING;

-- 데이터 사전: 컬럼 한글명(코멘트) — 화면 라벨의 단일 출처
COMMENT ON COLUMN transfer.bmi           IS '거래식별자(BMI)';
COMMENT ON COLUMN transfer.global_seq    IS '전역순번';
COMMENT ON COLUMN transfer.status        IS '처리상태';
COMMENT ON COLUMN transfer.sender_code   IS '송신기관코드';
COMMENT ON COLUMN transfer.receiver_code IS '수신기관코드';
COMMENT ON COLUMN transfer.amount        IS '이체금액(원)';
COMMENT ON COLUMN transfer.origin_center IS '접수센터';
COMMENT ON COLUMN transfer.created_at    IS '접수시각';
COMMENT ON COLUMN transfer.updated_at    IS '최종수정시각';
COMMENT ON COLUMN transfer.reason        IS '사유';
COMMENT ON COLUMN account.code    IS '기관코드';
COMMENT ON COLUMN account.name    IS '기관명';
COMMENT ON COLUMN account.balance IS '당좌계좌잔액(원)';

-- 사용자·권한 관리 마스터(Louis Vuitton). role: ADMIN/ORG_S/ORG_R. (로그인 강제는 후속)
CREATE TABLE IF NOT EXISTS app_user (
  username     VARCHAR(32) PRIMARY KEY,
  display_name VARCHAR(64),
  role         VARCHAR(16) NOT NULL,
  org_code     VARCHAR(4),
  secret       VARCHAR(128),          -- Gucci 로그인 자격증명. 시드는 평문 dev값, 기동 시 Gucci가 BCrypt 해시로 승격
  created_at   BIGINT
);
-- 기존 DB 호환: secret 컬럼 추가(있으면 무시)
ALTER TABLE app_user ADD COLUMN IF NOT EXISTS secret VARCHAR(128);
COMMENT ON COLUMN app_user.username IS '사용자ID';
COMMENT ON COLUMN app_user.display_name IS '사용자명';
COMMENT ON COLUMN app_user.role IS '역할(ADMIN/ORG_S/ORG_R)';
COMMENT ON COLUMN app_user.org_code IS '매핑기관코드';
INSERT INTO app_user(username,display_name,role,org_code,secret,created_at) VALUES
  ('admin','시스템관리자','ADMIN',NULL,'admin-secret',0),
  ('kookmin_s','국민은행 송신담당','ORG_S','1001','kookmin-secret',0),
  ('shinhan_r','신한은행 수신담당','ORG_R','1002','shinhan-secret',0)
ON CONFLICT (username) DO NOTHING;
-- 기존 행에 dev 시크릿 보정(널인 경우만)
UPDATE app_user SET secret = 'admin-secret'   WHERE username='admin'     AND secret IS NULL;
UPDATE app_user SET secret = 'kookmin-secret' WHERE username='kookmin_s' AND secret IS NULL;
UPDATE app_user SET secret = 'shinhan-secret' WHERE username='shinhan_r' AND secret IS NULL;
COMMENT ON COLUMN app_user.secret IS 'Gucci로그인비밀키';
