-- ============================================================================
-- zioinfo-esn ESL 통합 플랫폼 — PostgreSQL 스키마 (esn_db)
-- 레거시 Spring Boot 1.5 / Java 8 6개 프로젝트 → 단일 플랫폼
-- 멀티테넌트: LGINNOTEK / LGIT / EMART / ZIOINFO
-- ============================================================================

-- ── 테넌트 ──────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS esn_tenant (
    id          BIGSERIAL PRIMARY KEY,
    tenant_code VARCHAR(20)  UNIQUE NOT NULL,
    tenant_name VARCHAR(200) NOT NULL,
    description TEXT,
    is_active   BOOLEAN DEFAULT TRUE,
    created_at  TIMESTAMP DEFAULT NOW()
);

INSERT INTO esn_tenant (tenant_code, tenant_name, description) VALUES
  ('LGINNOTEK', 'LG 이노텍', 'LG 이노텍 ESL 관리'),
  ('LGIT',      'LG IT',    'LG IT 서비스 ESL'),
  ('EMART',     '이마트',   '이마트 전자가격표 시스템'),
  ('ZIOINFO',   '지오정보기술', '지오정보기술 자체 ESL')
ON CONFLICT (tenant_code) DO NOTHING;

-- ── 매장 그룹 ────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS esn_store_group (
    id          BIGSERIAL PRIMARY KEY,
    tenant_code VARCHAR(20)  NOT NULL REFERENCES esn_tenant(tenant_code),
    group_code  VARCHAR(50)  NOT NULL,
    group_name  VARCHAR(200) NOT NULL,
    description TEXT,
    is_active   BOOLEAN DEFAULT TRUE,
    created_at  TIMESTAMP DEFAULT NOW(),
    UNIQUE (tenant_code, group_code)
);

INSERT INTO esn_store_group (tenant_code, group_code, group_name) VALUES
  ('LGINNOTEK', 'GRP-LGI-01', 'LG이노텍 구미공장'),
  ('LGIT',      'GRP-LGIT-01','LG IT 본사'),
  ('EMART',     'GRP-EM-SEOUL', '이마트 서울권'),
  ('EMART',     'GRP-EM-GYEONG','이마트 경기권'),
  ('ZIOINFO',   'GRP-ZIO-01', '지오정보기술 본사')
ON CONFLICT (tenant_code, group_code) DO NOTHING;

-- ── 매장 ─────────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS esn_store (
    id             BIGSERIAL PRIMARY KEY,
    tenant_code    VARCHAR(20)  NOT NULL REFERENCES esn_tenant(tenant_code),
    store_code     VARCHAR(50)  NOT NULL,
    store_name     VARCHAR(200) NOT NULL,
    address        VARCHAR(500),
    phone          VARCHAR(50),
    store_group_id BIGINT REFERENCES esn_store_group(id),
    manager_name   VARCHAR(100),
    is_active      BOOLEAN DEFAULT TRUE,
    created_at     TIMESTAMP DEFAULT NOW(),
    UNIQUE (tenant_code, store_code)
);

INSERT INTO esn_store (tenant_code, store_code, store_name, address, manager_name, store_group_id)
SELECT 'LGINNOTEK', 'LGI-001', 'LG이노텍 구미 1라인', '경북 구미시 공단동 1', '김철수', g.id
FROM esn_store_group g WHERE g.group_code = 'GRP-LGI-01' AND g.tenant_code = 'LGINNOTEK'
ON CONFLICT (tenant_code, store_code) DO NOTHING;

INSERT INTO esn_store (tenant_code, store_code, store_name, address, manager_name, store_group_id)
SELECT 'EMART', 'EM-001', '이마트 강남점', '서울 강남구 삼성동', '박영희', g.id
FROM esn_store_group g WHERE g.group_code = 'GRP-EM-SEOUL' AND g.tenant_code = 'EMART'
ON CONFLICT (tenant_code, store_code) DO NOTHING;

INSERT INTO esn_store (tenant_code, store_code, store_name, address, manager_name, store_group_id)
SELECT 'EMART', 'EM-002', '이마트 수원점', '경기 수원시 팔달구', '이민수', g.id
FROM esn_store_group g WHERE g.group_code = 'GRP-EM-GYEONG' AND g.tenant_code = 'EMART'
ON CONFLICT (tenant_code, store_code) DO NOTHING;

-- ── ESL 템플릿 ───────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS esn_template (
    id            BIGSERIAL PRIMARY KEY,
    tenant_code   VARCHAR(20)  NOT NULL REFERENCES esn_tenant(tenant_code),
    template_code VARCHAR(50)  NOT NULL,
    template_name VARCHAR(200) NOT NULL,
    template_type VARCHAR(50)  DEFAULT 'PRICE',  -- PRICE, INFO, PROMO, CUSTOM
    width         INTEGER,
    height        INTEGER,
    description   TEXT,
    layout_json   TEXT,
    is_active     BOOLEAN DEFAULT TRUE,
    created_at    TIMESTAMP DEFAULT NOW(),
    UNIQUE (tenant_code, template_code)
);

INSERT INTO esn_template (tenant_code, template_code, template_name, template_type, width, height, description) VALUES
  ('EMART', 'EM-PRICE-STD', '이마트 표준 가격표', 'PRICE', 152, 76, '표준 2.9인치 ESL 템플릿'),
  ('EMART', 'EM-PROMO',     '이마트 프로모션', 'PROMO', 296, 128, '5인치 프로모션 표시'),
  ('LGINNOTEK', 'LGI-INFO', 'LG이노텍 부품 정보', 'INFO', 152, 76, '부품 코드·수량 표시')
ON CONFLICT (tenant_code, template_code) DO NOTHING;

-- ── POS 가격 변환 ─────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS esn_pos_cvt (
    id            BIGSERIAL PRIMARY KEY,
    tenant_code   VARCHAR(20)  NOT NULL REFERENCES esn_tenant(tenant_code),
    store_id      BIGINT REFERENCES esn_store(id),
    pos_code      VARCHAR(100),
    product_code  VARCHAR(100) NOT NULL,
    product_name  VARCHAR(300),
    price         NUMERIC(12,2),
    sale_price    NUMERIC(12,2),
    currency      VARCHAR(10)  DEFAULT 'KRW',
    status        VARCHAR(20)  DEFAULT 'PENDING',  -- PENDING, PROCESSED, ERROR, IGNORED
    error_message TEXT,
    processed_at  TIMESTAMP,
    created_at    TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_pos_cvt_tenant ON esn_pos_cvt(tenant_code, status);
CREATE INDEX IF NOT EXISTS idx_pos_cvt_store  ON esn_pos_cvt(store_id, status);

-- ── 알람 ─────────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS esn_alarm (
    id          BIGSERIAL PRIMARY KEY,
    tenant_code VARCHAR(20) NOT NULL REFERENCES esn_tenant(tenant_code),
    store_id    BIGINT REFERENCES esn_store(id),
    alarm_type  VARCHAR(50) NOT NULL,   -- DEVICE, NETWORK, BATTERY, FIRMWARE, SYSTEM
    alarm_code  VARCHAR(100),
    severity    VARCHAR(20) NOT NULL,   -- CRITICAL, HIGH, MEDIUM, LOW
    message     TEXT,
    status      VARCHAR(20) DEFAULT 'OPEN',  -- OPEN, ACKNOWLEDGED, RESOLVED
    resolved_by VARCHAR(100),
    resolution  TEXT,
    resolved_at TIMESTAMP,
    created_at  TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_alarm_tenant   ON esn_alarm(tenant_code, status);
CREATE INDEX IF NOT EXISTS idx_alarm_severity ON esn_alarm(severity, status);

-- 샘플 알람
INSERT INTO esn_alarm (tenant_code, store_id, alarm_type, alarm_code, severity, message, status)
SELECT 'EMART', s.id, 'DEVICE', 'DEV-OFFLINE', 'HIGH', 'ESL 장치 오프라인 감지 — 매장 내 점검 필요', 'OPEN'
FROM esn_store s WHERE s.store_code = 'EM-001' LIMIT 1;

INSERT INTO esn_alarm (tenant_code, store_id, alarm_type, alarm_code, severity, message, status)
SELECT 'EMART', s.id, 'BATTERY', 'BAT-LOW', 'MEDIUM', 'ESL 배터리 잔량 15% 미만 — 배터리 교체 예정', 'OPEN'
FROM esn_store s WHERE s.store_code = 'EM-002' LIMIT 1;

-- ── HCore 장치 (게이트웨이/허브/ESL) ─────────────────────────────────────────
CREATE TABLE IF NOT EXISTS esn_hcore_device (
    id               BIGSERIAL PRIMARY KEY,
    tenant_code      VARCHAR(20)  NOT NULL REFERENCES esn_tenant(tenant_code),
    store_id         BIGINT REFERENCES esn_store(id),
    device_type      VARCHAR(50)  NOT NULL,   -- GATEWAY, HUB, ESL_DEVICE
    device_id        VARCHAR(100) NOT NULL,
    ip_address       VARCHAR(50),
    mac_address      VARCHAR(50),
    firmware_version VARCHAR(50),
    status           VARCHAR(20)  DEFAULT 'ONLINE', -- ONLINE, OFFLINE, ERROR, UPDATING
    battery_level    INTEGER,
    signal_strength  VARCHAR(20),
    last_seen_at     TIMESTAMP DEFAULT NOW(),
    created_at       TIMESTAMP DEFAULT NOW(),
    UNIQUE (device_id)
);
CREATE INDEX IF NOT EXISTS idx_hcore_tenant ON esn_hcore_device(tenant_code, status);
CREATE INDEX IF NOT EXISTS idx_hcore_store  ON esn_hcore_device(store_id, status);

-- 샘플 HCore 장치
INSERT INTO esn_hcore_device (tenant_code, store_id, device_type, device_id, ip_address, firmware_version, status)
SELECT 'EMART', s.id, 'GATEWAY', 'GW-EM-001-001', '192.168.1.1', '2.1.5', 'ONLINE'
FROM esn_store s WHERE s.store_code = 'EM-001' LIMIT 1
ON CONFLICT (device_id) DO NOTHING;

INSERT INTO esn_hcore_device (tenant_code, store_id, device_type, device_id, ip_address, firmware_version, status, battery_level)
SELECT 'EMART', s.id, 'ESL_DEVICE', 'ESL-EM-001-0001', NULL, '1.8.2', 'ONLINE', 85
FROM esn_store s WHERE s.store_code = 'EM-001' LIMIT 1
ON CONFLICT (device_id) DO NOTHING;

INSERT INTO esn_hcore_device (tenant_code, store_id, device_type, device_id, ip_address, firmware_version, status, battery_level)
SELECT 'EMART', s.id, 'ESL_DEVICE', 'ESL-EM-001-0002', NULL, '1.8.2', 'OFFLINE', 8
FROM esn_store s WHERE s.store_code = 'EM-001' LIMIT 1
ON CONFLICT (device_id) DO NOTHING;

-- ── 작업 이력 ────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS esn_work_history (
    id           BIGSERIAL PRIMARY KEY,
    tenant_code  VARCHAR(20)  NOT NULL REFERENCES esn_tenant(tenant_code),
    store_id     BIGINT REFERENCES esn_store(id),
    work_type    VARCHAR(50)  NOT NULL,  -- INSTALL, MAINTENANCE, FIRMWARE_UPDATE, REPLACEMENT, INSPECTION
    work_content TEXT,
    worker_name  VARCHAR(100),
    status       VARCHAR(20)  DEFAULT 'SCHEDULED',  -- SCHEDULED, IN_PROGRESS, COMPLETED, CANCELLED
    remarks      TEXT,
    started_at   TIMESTAMP,
    completed_at TIMESTAMP,
    created_at   TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_work_tenant ON esn_work_history(tenant_code, status);

-- ── 펌웨어 ───────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS esn_firmware (
    id               BIGSERIAL PRIMARY KEY,
    tenant_code      VARCHAR(20)  NOT NULL REFERENCES esn_tenant(tenant_code),
    firmware_version VARCHAR(50)  NOT NULL,
    device_type      VARCHAR(50)  NOT NULL,
    file_name        VARCHAR(300),
    file_path        VARCHAR(500),
    file_size        BIGINT,
    checksum         VARCHAR(200),
    description      TEXT,
    is_latest        BOOLEAN DEFAULT FALSE,
    created_at       TIMESTAMP DEFAULT NOW()
);

INSERT INTO esn_firmware (tenant_code, firmware_version, device_type, file_name, description, is_latest) VALUES
  ('EMART', '2.1.5', 'GATEWAY',    'gw_v2.1.5.bin', 'EMART 게이트웨이 최신 펌웨어', true),
  ('EMART', '1.8.2', 'ESL_DEVICE', 'esl_v1.8.2.bin', 'EMART ESL 디바이스 최신 펌웨어', true)
ON CONFLICT DO NOTHING;

-- ── 사용자 ───────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS esn_user (
    id            BIGSERIAL PRIMARY KEY,
    tenant_code   VARCHAR(20)  REFERENCES esn_tenant(tenant_code),
    username      VARCHAR(200) UNIQUE NOT NULL,
    password_hash VARCHAR(500) NOT NULL,
    role          VARCHAR(50)  DEFAULT 'USER',   -- ADMIN, MANAGER, USER
    email         VARCHAR(300),
    phone         VARCHAR(50),
    is_active     BOOLEAN DEFAULT TRUE,
    last_login_at TIMESTAMP,
    created_at    TIMESTAMP DEFAULT NOW()
);

-- 기본 관리자 (비밀번호: admin123 / BCrypt)
INSERT INTO esn_user (tenant_code, username, password_hash, role)
VALUES (NULL, 'admin', '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LnCWh7Vz.Xm', 'ADMIN')
ON CONFLICT (username) DO NOTHING;

INSERT INTO esn_user (tenant_code, username, password_hash, role)
VALUES ('EMART', 'emart_manager', '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LnCWh7Vz.Xm', 'MANAGER')
ON CONFLICT (username) DO NOTHING;

INSERT INTO esn_user (tenant_code, username, password_hash, role)
VALUES ('LGINNOTEK', 'lgi_manager', '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LnCWh7Vz.Xm', 'MANAGER')
ON CONFLICT (username) DO NOTHING;

-- ── 상품 ─────────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS esn_product (
    id           BIGSERIAL PRIMARY KEY,
    tenant_code  VARCHAR(20)  NOT NULL REFERENCES esn_tenant(tenant_code),
    store_id     BIGINT REFERENCES esn_store(id),
    product_code VARCHAR(100) NOT NULL,
    product_name VARCHAR(300) NOT NULL,
    category     VARCHAR(100),
    price        NUMERIC(12,2),
    sale_price   NUMERIC(12,2),
    currency     VARCHAR(10)  DEFAULT 'KRW',
    is_active    BOOLEAN DEFAULT TRUE,
    updated_at   TIMESTAMP DEFAULT NOW(),
    created_at   TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_product_store ON esn_product(store_id, product_code);

-- 샘플 상품
INSERT INTO esn_product (tenant_code, store_id, product_code, product_name, category, price, sale_price)
SELECT 'EMART', s.id, 'P-001', '신라면', '라면/면류', 850, 800
FROM esn_store s WHERE s.store_code = 'EM-001' LIMIT 1
ON CONFLICT DO NOTHING;

-- ── 태그 위치/상품 바인딩 ──────────────────────────────────────────────────────
-- e-paper 태그와 선반 위치 + 상품을 연결하는 핵심 테이블
CREATE TABLE IF NOT EXISTS esn_tag_binding (
    id            BIGSERIAL PRIMARY KEY,
    tenant_code   VARCHAR(20)  NOT NULL REFERENCES esn_tenant(tenant_code),
    store_id      BIGINT       NOT NULL REFERENCES esn_store(id),
    device_id     VARCHAR(100) NOT NULL,              -- ESL_DEVICE device_id
    product_code  VARCHAR(100),                       -- 현재 표시 중인 상품
    location_code VARCHAR(100),                       -- 선반 위치코드 (예: A01-03, 통로A-1단)
    template_code VARCHAR(50),                        -- 적용 템플릿
    display_data  TEXT,                               -- 현재 화면에 표시된 데이터 (JSON)
    last_price    NUMERIC(12,2),                      -- 마지막으로 전송된 가격
    last_updated_at TIMESTAMP,                        -- 마지막 화면 갱신 시각
    bind_status   VARCHAR(20) DEFAULT 'ACTIVE',       -- ACTIVE, UNBOUND, ERROR
    created_at    TIMESTAMP DEFAULT NOW(),
    UNIQUE (device_id)
);
CREATE INDEX IF NOT EXISTS idx_binding_store   ON esn_tag_binding(store_id, bind_status);
CREATE INDEX IF NOT EXISTS idx_binding_product ON esn_tag_binding(tenant_code, product_code);
CREATE INDEX IF NOT EXISTS idx_binding_loc     ON esn_tag_binding(store_id, location_code);

-- 샘플 바인딩 (이마트 강남점 ESL-EM-001-0001 ↔ 신라면)
INSERT INTO esn_tag_binding (tenant_code, store_id, device_id, product_code, location_code, template_code, last_price)
SELECT 'EMART', s.id, 'ESL-EM-001-0001', 'P-001', 'A01-03', 'EM-PRICE-STD', 850
FROM esn_store s WHERE s.store_code = 'EM-001' LIMIT 1
ON CONFLICT (device_id) DO NOTHING;

-- ── 가격 업데이트 전파 큐 ────────────────────────────────────────────────────────
-- POS 가격 변경이 e-paper 태그에 도달하는 전 과정을 추적
CREATE TABLE IF NOT EXISTS esn_update_queue (
    id              BIGSERIAL PRIMARY KEY,
    tenant_code     VARCHAR(20)  NOT NULL REFERENCES esn_tenant(tenant_code),
    store_id        BIGINT       REFERENCES esn_store(id),
    binding_id      BIGINT       REFERENCES esn_tag_binding(id),
    device_id       VARCHAR(100) NOT NULL,
    product_code    VARCHAR(100),
    new_price       NUMERIC(12,2),
    new_sale_price  NUMERIC(12,2),
    template_code   VARCHAR(50),
    render_data     TEXT,                             -- 렌더링된 화면 데이터 (JSON)
    priority        INTEGER DEFAULT 5,                -- 1(긴급) ~ 10(일반)
    status          VARCHAR(20) DEFAULT 'PENDING',    -- PENDING, SENDING, SENT, CONFIRMED, FAILED, CANCELLED
    retry_count     INTEGER DEFAULT 0,
    max_retry       INTEGER DEFAULT 3,
    error_message   TEXT,
    sent_at         TIMESTAMP,
    confirmed_at    TIMESTAMP,
    pos_cvt_id      BIGINT REFERENCES esn_pos_cvt(id),
    created_at      TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_queue_device ON esn_update_queue(device_id, status);
CREATE INDEX IF NOT EXISTS idx_queue_store  ON esn_update_queue(store_id, status, created_at);
CREATE INDEX IF NOT EXISTS idx_queue_pend   ON esn_update_queue(status, priority, created_at) WHERE status = 'PENDING';

-- ── 감사 로그 ─────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS esn_audit_log (
    id          BIGSERIAL PRIMARY KEY,
    tenant_code VARCHAR(20),
    username    VARCHAR(200),
    action      VARCHAR(200) NOT NULL,
    resource    VARCHAR(200),
    resource_id VARCHAR(100),
    detail      TEXT,
    ip_address  VARCHAR(50),
    user_agent  VARCHAR(500),
    success     BOOLEAN DEFAULT TRUE,
    created_at  TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_audit_created ON esn_audit_log(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_audit_tenant ON esn_audit_log(tenant_code, created_at DESC);
