-- V014: prediction에서 참조하는 누락 테이블 추가
-- fleet_vessels, fleet_tracking_snapshot, gear_identity_log,
-- gear_correlation_scores, gear_correlation_raw_metrics, correlation_param_models,
-- group_polygon_snapshots, gear_group_episodes, gear_group_episode_snapshots,
-- gear_group_parent_candidate_snapshots, gear_parent_label_tracking_cycles, system_config

-- ===== 1. fleet_vessels =====
CREATE TABLE IF NOT EXISTS kcg.fleet_vessels (
    id BIGSERIAL PRIMARY KEY,
    company_id BIGINT NOT NULL REFERENCES kcg.fleet_companies(id),
    permit_no VARCHAR(50),
    name_cn VARCHAR(100),
    name_en VARCHAR(100),
    tonnage NUMERIC(10,2),
    gear_code VARCHAR(20),
    fleet_role VARCHAR(20) DEFAULT 'CREW',  -- MAIN, CREW, TRANSPORT, NOISE
    pair_vessel_id BIGINT,
    mmsi VARCHAR(20),
    match_confidence NUMERIC(4,3),
    match_method VARCHAR(30),  -- NAME_EXACT, NAME_PARENT
    last_seen_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ DEFAULT now(),
    updated_at TIMESTAMPTZ DEFAULT now()
);

CREATE INDEX idx_fleet_vessels_company ON kcg.fleet_vessels(company_id);
CREATE INDEX idx_fleet_vessels_mmsi ON kcg.fleet_vessels(mmsi);
CREATE INDEX idx_fleet_vessels_name_cn ON kcg.fleet_vessels(name_cn);

-- ===== 2. fleet_tracking_snapshot =====
CREATE TABLE IF NOT EXISTS kcg.fleet_tracking_snapshot (
    id BIGSERIAL PRIMARY KEY,
    company_id BIGINT NOT NULL REFERENCES kcg.fleet_companies(id),
    snapshot_time TIMESTAMPTZ NOT NULL,
    total_vessels INT NOT NULL DEFAULT 0,
    active_vessels INT NOT NULL DEFAULT 0,
    center_lat NUMERIC(9,6),
    center_lon NUMERIC(10,6)
);

CREATE INDEX idx_fleet_snapshot_company ON kcg.fleet_tracking_snapshot(company_id, snapshot_time DESC);

-- ===== 3. gear_identity_log =====
CREATE TABLE IF NOT EXISTS kcg.gear_identity_log (
    id BIGSERIAL PRIMARY KEY,
    mmsi VARCHAR(20) NOT NULL,
    name VARCHAR(200) NOT NULL,
    parent_name VARCHAR(100),
    parent_mmsi VARCHAR(20),
    parent_vessel_id BIGINT,
    gear_index_1 INT,
    gear_index_2 INT,
    lat NUMERIC(9,6),
    lon NUMERIC(10,6),
    match_method VARCHAR(30),
    match_confidence NUMERIC(4,3),
    first_seen_at TIMESTAMPTZ NOT NULL,
    last_seen_at TIMESTAMPTZ NOT NULL,
    is_active BOOLEAN NOT NULL DEFAULT TRUE
);

CREATE INDEX idx_gear_identity_mmsi ON kcg.gear_identity_log(mmsi, is_active);
CREATE INDEX idx_gear_identity_name ON kcg.gear_identity_log(name, is_active);

-- ===== 4. correlation_param_models =====
CREATE TABLE IF NOT EXISTS kcg.correlation_param_models (
    id BIGSERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    params JSONB NOT NULL DEFAULT '{}',
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    is_default BOOLEAN NOT NULL DEFAULT FALSE,
    created_at TIMESTAMPTZ DEFAULT now()
);

-- 기본 모델 시드
INSERT INTO kcg.correlation_param_models (name, params, is_active, is_default) VALUES
    ('default', '{"ema_alpha": 0.3, "proximity_weight": 0.25, "visit_weight": 0.2, "activity_sync_weight": 0.15, "heading_weight": 0.15, "dtw_weight": 0.1, "speed_weight": 0.1, "drift_weight": 0.05}', TRUE, TRUE)
ON CONFLICT DO NOTHING;

-- ===== 5. gear_correlation_scores =====
CREATE TABLE IF NOT EXISTS kcg.gear_correlation_scores (
    model_id BIGINT NOT NULL REFERENCES kcg.correlation_param_models(id),
    group_key VARCHAR(255) NOT NULL,
    sub_cluster_id INT NOT NULL,
    target_mmsi VARCHAR(20) NOT NULL,
    target_type VARCHAR(20),           -- VESSEL, GEAR_BUOY
    target_name VARCHAR(200),
    current_score NUMERIC(6,4) DEFAULT 0,
    proximity_ratio NUMERIC(6,4),
    visit_score NUMERIC(6,4),
    heading_coherence NUMERIC(6,4),
    streak_count INT DEFAULT 0,
    freeze_state VARCHAR(20) DEFAULT 'ACTIVE',  -- ACTIVE, FREEZE, SIGNAL_LOSS
    observation_count INT DEFAULT 0,
    first_observed_at TIMESTAMPTZ,
    last_observed_at TIMESTAMPTZ,
    updated_at TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (model_id, group_key, sub_cluster_id, target_mmsi)
);

CREATE INDEX idx_corr_scores_group ON kcg.gear_correlation_scores(group_key, sub_cluster_id);
CREATE INDEX idx_corr_scores_target ON kcg.gear_correlation_scores(target_mmsi);

-- ===== 6. gear_correlation_raw_metrics =====
CREATE TABLE IF NOT EXISTS kcg.gear_correlation_raw_metrics (
    id BIGSERIAL PRIMARY KEY,
    observed_at TIMESTAMPTZ NOT NULL,
    group_key VARCHAR(255) NOT NULL,
    sub_cluster_id INT NOT NULL,
    target_mmsi VARCHAR(20) NOT NULL,
    target_type VARCHAR(20),
    target_name VARCHAR(200),
    proximity_ratio NUMERIC(6,4),
    visit_score NUMERIC(6,4),
    activity_sync NUMERIC(6,4),
    dtw_similarity NUMERIC(6,4),
    speed_correlation NUMERIC(6,4),
    heading_coherence NUMERIC(6,4),
    drift_similarity NUMERIC(6,4),
    shadow_stay BOOLEAN DEFAULT FALSE,
    shadow_return BOOLEAN DEFAULT FALSE,
    gear_group_active_ratio NUMERIC(6,4)
);

CREATE INDEX idx_raw_metrics_observed ON kcg.gear_correlation_raw_metrics(observed_at);
CREATE INDEX idx_raw_metrics_group ON kcg.gear_correlation_raw_metrics(group_key, sub_cluster_id, observed_at);

-- ===== 7. group_polygon_snapshots =====
CREATE TABLE IF NOT EXISTS kcg.group_polygon_snapshots (
    id BIGSERIAL PRIMARY KEY,
    group_type VARCHAR(30) NOT NULL,       -- FLEET, GEAR_IN_ZONE, GEAR_OUT_ZONE
    group_key VARCHAR(255) NOT NULL,
    group_label VARCHAR(255),
    sub_cluster_id INT NOT NULL DEFAULT 0,
    resolution VARCHAR(10) DEFAULT '6h',   -- 6h, 1h
    snapshot_time TIMESTAMPTZ NOT NULL,
    polygon GEOMETRY(Polygon, 4326),
    center_point GEOMETRY(Point, 4326),
    area_sq_nm NUMERIC(12,4),
    member_count INT DEFAULT 0,
    zone_id VARCHAR(50),
    zone_name VARCHAR(100),
    members JSONB,
    color VARCHAR(20)
);

CREATE INDEX idx_polygon_snap_group ON kcg.group_polygon_snapshots(group_key, sub_cluster_id, snapshot_time DESC);
CREATE INDEX idx_polygon_snap_time ON kcg.group_polygon_snapshots(snapshot_time);
CREATE INDEX idx_polygon_snap_geom ON kcg.group_polygon_snapshots USING GIST (polygon);

-- ===== 8. gear_group_episodes =====
CREATE TABLE IF NOT EXISTS kcg.gear_group_episodes (
    episode_id VARCHAR(50) PRIMARY KEY,   -- 'ep-{12hex}'
    lineage_key VARCHAR(255) NOT NULL,
    group_key VARCHAR(255) NOT NULL,
    normalized_parent_name VARCHAR(100),
    current_sub_cluster_id INT,
    status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',  -- ACTIVE, EXPIRED, MERGED
    continuity_source VARCHAR(30),         -- NEW, CONTINUED, SPLIT_NEW, SPLIT_CONTINUE, MERGE_NEW
    continuity_score NUMERIC(6,4),
    first_seen_at TIMESTAMPTZ,
    last_seen_at TIMESTAMPTZ,
    last_snapshot_time TIMESTAMPTZ,
    current_member_count INT DEFAULT 0,
    current_member_mmsis JSONB,
    current_center_point GEOMETRY(Point, 4326),
    split_from_episode_id VARCHAR(50),
    merged_from_episode_ids JSONB,
    merged_into_episode_id VARCHAR(50),
    metadata JSONB,
    updated_at TIMESTAMPTZ DEFAULT now()
);

CREATE INDEX idx_episodes_lineage ON kcg.gear_group_episodes(lineage_key, status);
CREATE INDEX idx_episodes_group ON kcg.gear_group_episodes(group_key, status);
CREATE INDEX idx_episodes_snapshot ON kcg.gear_group_episodes(last_snapshot_time);

-- ===== 9. gear_group_episode_snapshots =====
CREATE TABLE IF NOT EXISTS kcg.gear_group_episode_snapshots (
    episode_id VARCHAR(50) NOT NULL,
    lineage_key VARCHAR(255),
    group_key VARCHAR(255) NOT NULL,
    normalized_parent_name VARCHAR(100),
    sub_cluster_id INT NOT NULL,
    observed_at TIMESTAMPTZ NOT NULL,
    member_count INT DEFAULT 0,
    member_mmsis JSONB,
    center_point GEOMETRY(Point, 4326),
    continuity_source VARCHAR(30),
    continuity_score NUMERIC(6,4),
    parent_episode_ids JSONB,
    top_candidate_mmsi VARCHAR(20),
    top_candidate_score NUMERIC(6,4),
    resolution_status VARCHAR(30),
    metadata JSONB,
    PRIMARY KEY (episode_id, observed_at)
);

CREATE INDEX idx_ep_snap_group ON kcg.gear_group_episode_snapshots(group_key, sub_cluster_id, observed_at DESC);

-- ===== 10. gear_group_parent_candidate_snapshots =====
CREATE TABLE IF NOT EXISTS kcg.gear_group_parent_candidate_snapshots (
    id BIGSERIAL PRIMARY KEY,
    observed_at TIMESTAMPTZ NOT NULL,
    group_key VARCHAR(255) NOT NULL,
    sub_cluster_id INT NOT NULL,
    parent_name VARCHAR(100),
    normalized_parent_name VARCHAR(100),
    episode_id VARCHAR(50),
    candidate_mmsi VARCHAR(20) NOT NULL,
    candidate_name VARCHAR(200),
    candidate_vessel_id BIGINT,
    rank INT,
    candidate_source VARCHAR(30),
    model_id BIGINT,
    model_name VARCHAR(100),
    base_corr_score NUMERIC(6,4),
    name_match_score NUMERIC(6,4),
    track_similarity_score NUMERIC(6,4),
    visit_score_6h NUMERIC(6,4),
    proximity_score_6h NUMERIC(6,4),
    activity_sync_score_6h NUMERIC(6,4),
    stability_score NUMERIC(6,4),
    registry_bonus NUMERIC(6,4),
    episode_prior_bonus NUMERIC(6,4),
    lineage_prior_bonus NUMERIC(6,4),
    label_prior_bonus NUMERIC(6,4),
    final_score NUMERIC(6,4),
    margin_from_top NUMERIC(6,4),
    evidence JSONB
);

CREATE INDEX idx_candidate_snap_group ON kcg.gear_group_parent_candidate_snapshots(group_key, sub_cluster_id, observed_at DESC);
CREATE INDEX idx_candidate_snap_episode ON kcg.gear_group_parent_candidate_snapshots(episode_id, observed_at DESC);
CREATE INDEX idx_candidate_snap_norm ON kcg.gear_group_parent_candidate_snapshots(normalized_parent_name);

-- ===== 11. gear_parent_label_tracking_cycles =====
CREATE TABLE IF NOT EXISTS kcg.gear_parent_label_tracking_cycles (
    label_session_id BIGINT NOT NULL REFERENCES kcg.gear_parent_label_sessions(id),
    observed_at TIMESTAMPTZ NOT NULL,
    candidate_snapshot_observed_at TIMESTAMPTZ,
    auto_status VARCHAR(30),
    top_candidate_mmsi VARCHAR(20),
    top_candidate_name VARCHAR(200),
    top_candidate_score NUMERIC(6,4),
    top_candidate_margin NUMERIC(6,4),
    candidate_count INT,
    labeled_candidate_present BOOLEAN,
    labeled_candidate_rank INT,
    labeled_candidate_score NUMERIC(6,4),
    labeled_candidate_pre_bonus_score NUMERIC(6,4),
    labeled_candidate_margin_from_top NUMERIC(6,4),
    matched_top1 BOOLEAN,
    matched_top3 BOOLEAN,
    evidence_summary JSONB,
    PRIMARY KEY (label_session_id, observed_at)
);

-- ===== 12. system_config =====
CREATE TABLE IF NOT EXISTS kcg.system_config (
    key VARCHAR(100) PRIMARY KEY,
    value JSONB,
    description TEXT,
    updated_at TIMESTAMPTZ DEFAULT now()
);

-- 파티션 기본값 시드
INSERT INTO kcg.system_config (key, value, description) VALUES
    ('partition.raw_metrics.retention_days', '7', '원시 메트릭 보관 일수'),
    ('partition.raw_metrics.create_ahead_days', '3', '파티션 사전 생성 일수'),
    ('partition.scores.cleanup_days', '30', '점수 정리 일수')
ON CONFLICT (key) DO NOTHING;

-- ===== fleet_vessels 시드 데이터 (fleet_companies 기반) =====
-- 중국 원양어업 회사 소속 선박 (데모용)
INSERT INTO kcg.fleet_vessels (company_id, permit_no, name_cn, name_en, tonnage, gear_code, fleet_role) VALUES
    (1, 'ZY-2024-001', '鲁荣渔2682', 'LU RONG YU 2682', 450.0, 'TRAWL', 'MAIN'),
    (1, 'ZY-2024-002', '鲁荣渔2683', 'LU RONG YU 2683', 380.0, 'TRAWL', 'CREW'),
    (1, 'ZY-2024-003', '鲁荣渔2680', 'LU RONG YU 2680', 520.0, 'PURSE', 'MAIN'),
    (2, 'ZY-2024-010', '浙岱渔11032', 'ZHE DAI YU 11032', 600.0, 'PURSE', 'MAIN'),
    (2, 'ZY-2024-011', '浙岱渔11033', 'ZHE DAI YU 11033', 550.0, 'PURSE', 'CREW'),
    (2, 'ZY-2024-012', '浙岱渔运108', 'ZHE DAI YU YUN 108', 800.0, 'TRANSPORT', 'TRANSPORT')
ON CONFLICT DO NOTHING;
