-- ============================================================
-- V012: prediction 산출 테이블 (이벤트 허브 + 알림 + 통계)
-- prediction이 write, backend가 상태만 update
-- ============================================================

-- ============================================================
-- 분석 결과 확장 (vessel_analysis_results)
-- prediction이 직접 INSERT. 기존 iran 28컬럼 + 확장
-- ============================================================
CREATE TABLE kcg.vessel_analysis_results (
    id                  BIGSERIAL    NOT NULL,
    mmsi                VARCHAR(20)  NOT NULL,
    analyzed_at         TIMESTAMPTZ  NOT NULL,
    -- 분류
    vessel_type         VARCHAR(30),
    confidence          NUMERIC(5,4),
    fishing_pct         NUMERIC(5,4),
    cluster_id          INT,
    season              VARCHAR(20),
    -- 위치
    lat                 DOUBLE PRECISION,
    lon                 DOUBLE PRECISION,
    zone_code           VARCHAR(30),               -- zone_polygon_master FK
    dist_to_baseline_nm NUMERIC(8,2),
    -- 행동 분석
    activity_state      VARCHAR(20),               -- STATIONARY, FISHING, SAILING
    ucaf_score          NUMERIC(5,4),
    ucft_score          NUMERIC(5,4),
    -- 위협 탐지
    is_dark             BOOLEAN      DEFAULT false,
    gap_duration_min    INT,
    dark_pattern        VARCHAR(30),               -- code_master DARK_PATTERN 참조
    spoofing_score      NUMERIC(5,4),
    bd09_offset_m       NUMERIC(8,2),
    speed_jump_count    INT,
    -- 환적
    transship_suspect   BOOLEAN      DEFAULT false,
    transship_pair_mmsi VARCHAR(20),
    transship_duration_min INT,
    -- 선단
    fleet_cluster_id    INT,
    fleet_role          VARCHAR(20),               -- LEADER, FOLLOWER, NOISE
    fleet_is_leader     BOOLEAN      DEFAULT false,
    -- 위험도
    risk_score          INT,                       -- 0~100
    risk_level          VARCHAR(20),               -- CRITICAL, HIGH, MEDIUM, LOW
    -- ★ 확장 컬럼
    gear_code           VARCHAR(20),               -- gear_type_master FK (분류 결과)
    violation_categories TEXT[],                    -- code_master VIOLATION_TYPE 참조
    gear_judgment       VARCHAR(30),               -- code_master GEAR_JUDGMENT 참조
    permit_status       VARCHAR(20),               -- 분석 시점 허가 상태 스냅샷
    -- 특징 벡터 (선택)
    features            JSONB,
    -- 메타
    created_at          TIMESTAMPTZ  DEFAULT now(),
    PRIMARY KEY (id, analyzed_at)
) PARTITION BY RANGE (analyzed_at);

-- 파티션 (prediction partition_manager가 자동 생성하지만, 초기 1개 생성)
CREATE TABLE kcg.vessel_analysis_results_default PARTITION OF kcg.vessel_analysis_results DEFAULT;

CREATE INDEX idx_var_mmsi      ON kcg.vessel_analysis_results(mmsi, analyzed_at DESC);
CREATE INDEX idx_var_risk      ON kcg.vessel_analysis_results(risk_level, analyzed_at DESC);
CREATE INDEX idx_var_dark      ON kcg.vessel_analysis_results(is_dark) WHERE is_dark = true;
CREATE INDEX idx_var_zone      ON kcg.vessel_analysis_results(zone_code, analyzed_at DESC);
CREATE INDEX idx_var_gear      ON kcg.vessel_analysis_results(gear_code) WHERE gear_code IS NOT NULL;
CREATE INDEX idx_var_violation  ON kcg.vessel_analysis_results USING GIN(violation_categories);

-- ============================================================
-- 이벤트 허브 (★ 모든 운영 흐름의 단일 진입점)
-- prediction event_generator가 INSERT, backend가 status만 UPDATE
-- ============================================================
CREATE TABLE kcg.prediction_events (
    id              BIGSERIAL    PRIMARY KEY,
    event_uid       VARCHAR(50)  UNIQUE NOT NULL,   -- EVT-YYYYMMDD-NNNN
    occurred_at     TIMESTAMPTZ  NOT NULL,
    level           VARCHAR(20)  NOT NULL,          -- CRITICAL, HIGH, MEDIUM, LOW
    category        VARCHAR(50)  NOT NULL,          -- code_master EVENT_CATEGORY 참조
    title           VARCHAR(200) NOT NULL,
    detail          TEXT,
    -- 대상 선박
    vessel_mmsi     VARCHAR(20),
    vessel_name     VARCHAR(100),
    -- 위치
    area_name       VARCHAR(100),
    zone_code       VARCHAR(30),
    lat             DOUBLE PRECISION,
    lon             DOUBLE PRECISION,
    speed_kn        NUMERIC(5,2),
    -- 분석 출처
    source_type     VARCHAR(50),                    -- VESSEL_ANALYSIS, GEAR_GROUP, TRANSSHIP, FLEET
    source_ref_id   BIGINT,                         -- 원본 분석결과 PK
    ai_confidence   NUMERIC(5,4),
    -- 운영 상태 (backend가 갱신)
    status          VARCHAR(20)  DEFAULT 'NEW',     -- code_master EVENT_STATUS 참조
    assignee_id     UUID,
    assignee_name   VARCHAR(100),
    acked_at        TIMESTAMPTZ,
    resolved_at     TIMESTAMPTZ,
    resolution_note TEXT,
    -- dedup
    dedup_key       VARCHAR(200),                   -- mmsi + category + window
    -- 메타
    created_at      TIMESTAMPTZ  DEFAULT now(),
    updated_at      TIMESTAMPTZ  DEFAULT now()
);

CREATE INDEX idx_event_status   ON kcg.prediction_events(status, occurred_at DESC);
CREATE INDEX idx_event_level    ON kcg.prediction_events(level, occurred_at DESC);
CREATE INDEX idx_event_category ON kcg.prediction_events(category, occurred_at DESC);
CREATE INDEX idx_event_mmsi     ON kcg.prediction_events(vessel_mmsi, occurred_at DESC);
CREATE INDEX idx_event_dedup    ON kcg.prediction_events(dedup_key, occurred_at DESC);

-- ============================================================
-- 이벤트 처리 워크플로우 (상태 변경 이력)
-- ============================================================
CREATE TABLE kcg.event_workflow (
    id              BIGSERIAL    PRIMARY KEY,
    event_id        BIGINT       NOT NULL REFERENCES kcg.prediction_events(id),
    prev_status     VARCHAR(20),
    new_status      VARCHAR(20)  NOT NULL,
    actor_id        UUID,
    actor_name      VARCHAR(100),
    comment         TEXT,
    created_at      TIMESTAMPTZ  DEFAULT now()
);

CREATE INDEX idx_ew_event ON kcg.event_workflow(event_id, created_at DESC);

-- ============================================================
-- AI 알림 발송 이력
-- ============================================================
CREATE TABLE kcg.prediction_alerts (
    id              BIGSERIAL    PRIMARY KEY,
    event_id        BIGINT       NOT NULL REFERENCES kcg.prediction_events(id),
    channel         VARCHAR(20)  NOT NULL,          -- DASHBOARD, MOBILE, SMS, EMAIL
    recipient       VARCHAR(200),
    sent_at         TIMESTAMPTZ  DEFAULT now(),
    delivery_status VARCHAR(20)  DEFAULT 'SENT',    -- SENT, DELIVERED, READ, FAILED
    ai_confidence   NUMERIC(5,4),
    metadata        JSONB
);

CREATE INDEX idx_alert_event ON kcg.prediction_alerts(event_id);

-- ============================================================
-- 사전 집계 통계 — 시간별 (최근 48h 보존)
-- ============================================================
CREATE TABLE kcg.prediction_stats_hourly (
    stat_hour           TIMESTAMPTZ PRIMARY KEY,
    total_detections    INT          DEFAULT 0,
    by_category         JSONB,                      -- {"EEZ_VIOLATION": 3, "DARK_VESSEL": 1, ...}
    by_zone             JSONB,                      -- {"NLL": 5, "EEZ_KR": 8, ...}
    by_risk_level       JSONB,                      -- {"CRITICAL": 2, "HIGH": 5, ...}
    event_count         INT          DEFAULT 0,
    critical_count      INT          DEFAULT 0,
    updated_at          TIMESTAMPTZ  DEFAULT now()
);

-- ============================================================
-- 사전 집계 통계 — 일별
-- ============================================================
CREATE TABLE kcg.prediction_stats_daily (
    stat_date            DATE         PRIMARY KEY,
    total_detections     INT          DEFAULT 0,
    by_category          JSONB,
    by_zone              JSONB,
    by_risk_level        JSONB,
    by_gear_type         JSONB,                     -- {"TRAWL_BOTTOM": 12, "GILLNET": 8, ...}
    by_violation_type    JSONB,                     -- {"EEZ_VIOLATION": 15, ...}
    event_count          INT          DEFAULT 0,
    critical_event_count INT          DEFAULT 0,
    enforcement_count    INT          DEFAULT 0,     -- 단속 건수 (backend가 주입)
    false_positive_count INT          DEFAULT 0,
    ai_accuracy_pct      NUMERIC(5,2),
    manual_confirmed_parents INT     DEFAULT 0,     -- 운영자 모선 확정 건수
    updated_at           TIMESTAMPTZ  DEFAULT now()
);

-- ============================================================
-- 사전 집계 통계 — 월별
-- ============================================================
CREATE TABLE kcg.prediction_stats_monthly (
    stat_month           DATE         PRIMARY KEY,  -- 매월 1일 (2026-04-01)
    total_detections     INT          DEFAULT 0,
    total_enforcements   INT          DEFAULT 0,
    by_category          JSONB,
    by_zone              JSONB,
    by_risk_level        JSONB,
    by_gear_type         JSONB,
    by_violation_type    JSONB,
    event_count          INT          DEFAULT 0,
    critical_event_count INT          DEFAULT 0,
    false_positive_count INT          DEFAULT 0,
    ai_accuracy_pct      NUMERIC(5,2),
    updated_at           TIMESTAMPTZ  DEFAULT now()
);

-- ============================================================
-- 실시간 KPI (프론트엔드 더미 kpiStore 대체)
-- ============================================================
CREATE TABLE kcg.prediction_kpi_realtime (
    kpi_key     VARCHAR(50)  PRIMARY KEY,
    kpi_label   VARCHAR(100) NOT NULL,
    value       INT          DEFAULT 0,
    trend       VARCHAR(10),                        -- up, down, flat
    delta_pct   NUMERIC(5,2),
    updated_at  TIMESTAMPTZ  DEFAULT now()
);

-- 시드: 프론트엔드 kpiStore 기반 6개 KPI
INSERT INTO kcg.prediction_kpi_realtime (kpi_key, kpi_label, value, trend, delta_pct) VALUES
('realtime_detection', '실시간 탐지', 47, 'up',    8.2),
('eez_violation',      'EEZ 침범',    18, 'up',   12.5),
('dark_vessel',        '다크베셀',    12, 'down',  -5.3),
('illegal_transship',  '불법환적 의심',8, 'flat',   0.0),
('tracking_active',    '추적 중',     15, 'up',    3.1),
('captured_inspected', '나포/검문',    3, 'flat',   0.0);

-- ============================================================
-- 위험도 격자 (RiskMap용, 1시간 단위)
-- ============================================================
CREATE TABLE kcg.prediction_risk_grid (
    cell_id     VARCHAR(20)  NOT NULL,              -- 'lat_lon' 형식 (e.g., '3400_12500')
    stat_hour   TIMESTAMPTZ  NOT NULL,
    avg_risk    NUMERIC(5,2),
    max_risk    INT,
    vessel_count INT         DEFAULT 0,
    critical_count INT       DEFAULT 0,
    metadata    JSONB,
    PRIMARY KEY (cell_id, stat_hour)
);

CREATE INDEX idx_grid_hour ON kcg.prediction_risk_grid(stat_hour DESC);

-- ============================================================
-- prediction 학습 피드백 입력 (backend가 write, prediction이 read)
-- ============================================================
CREATE TABLE kcg.prediction_label_input (
    id              BIGSERIAL    PRIMARY KEY,
    input_type      VARCHAR(30)  NOT NULL,          -- PARENT_CONFIRM, PARENT_REJECT, FALSE_POSITIVE, GEAR_CORRECTION
    group_key       VARCHAR(255),
    sub_cluster_id  INT,
    mmsi            VARCHAR(20),
    label_value     VARCHAR(100),                   -- 확정된 모선 MMSI, 수정된 어구 코드 등
    confidence      NUMERIC(5,4),
    actor_id        UUID,
    consumed_at     TIMESTAMPTZ,                    -- prediction이 사용하면 timestamp 기록
    created_at      TIMESTAMPTZ  DEFAULT now()
);

CREATE INDEX idx_label_unconsumed ON kcg.prediction_label_input(consumed_at) WHERE consumed_at IS NULL;
