-- 015: 어구 모선 추론 episode continuity + prior bonus

SET search_path TO kcg, public;

ALTER TABLE kcg.gear_group_parent_candidate_snapshots
    ADD COLUMN IF NOT EXISTS normalized_parent_name VARCHAR(200);

ALTER TABLE kcg.gear_group_parent_candidate_snapshots
    ADD COLUMN IF NOT EXISTS episode_id VARCHAR(64);

ALTER TABLE kcg.gear_group_parent_candidate_snapshots
    ADD COLUMN IF NOT EXISTS episode_prior_bonus DOUBLE PRECISION NOT NULL DEFAULT 0;

ALTER TABLE kcg.gear_group_parent_candidate_snapshots
    ADD COLUMN IF NOT EXISTS lineage_prior_bonus DOUBLE PRECISION NOT NULL DEFAULT 0;

ALTER TABLE kcg.gear_group_parent_candidate_snapshots
    ADD COLUMN IF NOT EXISTS label_prior_bonus DOUBLE PRECISION NOT NULL DEFAULT 0;

UPDATE kcg.gear_group_parent_candidate_snapshots
   SET normalized_parent_name = regexp_replace(upper(COALESCE(parent_name, '')), '[[:space:]_%-]+', '', 'g')
 WHERE normalized_parent_name IS NULL;

CREATE INDEX IF NOT EXISTS idx_ggpcs_episode_time
    ON kcg.gear_group_parent_candidate_snapshots(episode_id, observed_at DESC);

CREATE INDEX IF NOT EXISTS idx_ggpcs_lineage_time
    ON kcg.gear_group_parent_candidate_snapshots(normalized_parent_name, observed_at DESC);

ALTER TABLE kcg.gear_group_parent_resolution
    ADD COLUMN IF NOT EXISTS episode_id VARCHAR(64);

ALTER TABLE kcg.gear_group_parent_resolution
    ADD COLUMN IF NOT EXISTS continuity_source VARCHAR(32);

ALTER TABLE kcg.gear_group_parent_resolution
    ADD COLUMN IF NOT EXISTS continuity_score DOUBLE PRECISION;

ALTER TABLE kcg.gear_group_parent_resolution
    ADD COLUMN IF NOT EXISTS prior_bonus_total DOUBLE PRECISION NOT NULL DEFAULT 0;

CREATE INDEX IF NOT EXISTS idx_ggpr_episode
    ON kcg.gear_group_parent_resolution(episode_id);

ALTER TABLE kcg.gear_parent_label_sessions
    ADD COLUMN IF NOT EXISTS normalized_parent_name VARCHAR(200);

UPDATE kcg.gear_parent_label_sessions
   SET normalized_parent_name = regexp_replace(upper(COALESCE(group_key, '')), '[[:space:]_%-]+', '', 'g')
 WHERE normalized_parent_name IS NULL;

CREATE INDEX IF NOT EXISTS idx_gpls_lineage_active
    ON kcg.gear_parent_label_sessions(normalized_parent_name, active_from DESC);

CREATE TABLE IF NOT EXISTS kcg.gear_group_episodes (
    episode_id VARCHAR(64) PRIMARY KEY,
    lineage_key VARCHAR(200) NOT NULL,
    group_key VARCHAR(100) NOT NULL,
    normalized_parent_name VARCHAR(200) NOT NULL,
    current_sub_cluster_id SMALLINT NOT NULL DEFAULT 0,
    status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
    continuity_source VARCHAR(32) NOT NULL DEFAULT 'NEW',
    continuity_score DOUBLE PRECISION,
    first_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    last_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    last_snapshot_time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    current_member_count INT NOT NULL DEFAULT 0,
    current_member_mmsis JSONB NOT NULL DEFAULT '[]'::jsonb,
    current_center_point geometry(Point, 4326),
    split_from_episode_id VARCHAR(64),
    merged_from_episode_ids JSONB NOT NULL DEFAULT '[]'::jsonb,
    merged_into_episode_id VARCHAR(64),
    metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT chk_gge_status CHECK (status IN ('ACTIVE', 'MERGED', 'EXPIRED')),
    CONSTRAINT chk_gge_continuity CHECK (continuity_source IN ('NEW', 'CONTINUED', 'SPLIT_CONTINUE', 'SPLIT_NEW', 'MERGE_NEW', 'DIRECT_PARENT_MATCH'))
);

CREATE INDEX IF NOT EXISTS idx_gge_lineage_status_time
    ON kcg.gear_group_episodes(lineage_key, status, last_snapshot_time DESC);

CREATE INDEX IF NOT EXISTS idx_gge_group_time
    ON kcg.gear_group_episodes(group_key, current_sub_cluster_id, last_snapshot_time DESC);

CREATE TABLE IF NOT EXISTS kcg.gear_group_episode_snapshots (
    id BIGSERIAL PRIMARY KEY,
    episode_id VARCHAR(64) NOT NULL REFERENCES kcg.gear_group_episodes(episode_id) ON DELETE CASCADE,
    lineage_key VARCHAR(200) NOT NULL,
    group_key VARCHAR(100) NOT NULL,
    normalized_parent_name VARCHAR(200) NOT NULL,
    sub_cluster_id SMALLINT NOT NULL DEFAULT 0,
    observed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    member_count INT NOT NULL DEFAULT 0,
    member_mmsis JSONB NOT NULL DEFAULT '[]'::jsonb,
    center_point geometry(Point, 4326),
    continuity_source VARCHAR(32) NOT NULL,
    continuity_score DOUBLE PRECISION,
    parent_episode_ids JSONB NOT NULL DEFAULT '[]'::jsonb,
    top_candidate_mmsi VARCHAR(20),
    top_candidate_score DOUBLE PRECISION,
    resolution_status VARCHAR(40),
    metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT uq_gges_episode_observed UNIQUE (episode_id, observed_at)
);

CREATE INDEX IF NOT EXISTS idx_gges_lineage_observed
    ON kcg.gear_group_episode_snapshots(lineage_key, observed_at DESC);

CREATE INDEX IF NOT EXISTS idx_gges_group_observed
    ON kcg.gear_group_episode_snapshots(group_key, sub_cluster_id, observed_at DESC);
