-- 012: 어구 그룹 모선 추론 저장소 + sub_cluster/resolution 스키마 정합성

SET search_path TO kcg, public;

-- ── live lab과 repo 마이그레이션 정합성 맞추기 ─────────────────────

ALTER TABLE kcg.group_polygon_snapshots
    ADD COLUMN IF NOT EXISTS sub_cluster_id SMALLINT NOT NULL DEFAULT 0;

ALTER TABLE kcg.group_polygon_snapshots
    ADD COLUMN IF NOT EXISTS resolution VARCHAR(20) NOT NULL DEFAULT '6h';

CREATE INDEX IF NOT EXISTS idx_gps_type_res_time
    ON kcg.group_polygon_snapshots(group_type, resolution, snapshot_time DESC);

CREATE INDEX IF NOT EXISTS idx_gps_key_res_time
    ON kcg.group_polygon_snapshots(group_key, resolution, snapshot_time DESC);

CREATE INDEX IF NOT EXISTS idx_gps_key_sub_time
    ON kcg.group_polygon_snapshots(group_key, sub_cluster_id, snapshot_time DESC);

ALTER TABLE kcg.gear_correlation_raw_metrics
    ADD COLUMN IF NOT EXISTS sub_cluster_id SMALLINT NOT NULL DEFAULT 0;

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

ALTER TABLE kcg.gear_correlation_scores
    ADD COLUMN IF NOT EXISTS sub_cluster_id SMALLINT NOT NULL DEFAULT 0;

ALTER TABLE kcg.gear_correlation_scores
    DROP CONSTRAINT IF EXISTS gear_correlation_scores_model_id_group_key_target_mmsi_key;

DROP INDEX IF EXISTS kcg.gear_correlation_scores_model_id_group_key_target_mmsi_key;

DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1
        FROM pg_constraint
        WHERE connamespace = 'kcg'::regnamespace
          AND conrelid = 'kcg.gear_correlation_scores'::regclass
          AND conname = 'gear_correlation_scores_unique'
    ) THEN
        ALTER TABLE kcg.gear_correlation_scores
            ADD CONSTRAINT gear_correlation_scores_unique
            UNIQUE (model_id, group_key, sub_cluster_id, target_mmsi);
    END IF;
END;
$$ LANGUAGE plpgsql;

CREATE INDEX IF NOT EXISTS idx_gc_model_group_sub
    ON kcg.gear_correlation_scores(model_id, group_key, sub_cluster_id, current_score DESC);

-- ── 그룹 단위 모선 추론 저장소 ─────────────────────────────────────

CREATE TABLE IF NOT EXISTS kcg.gear_group_parent_candidate_snapshots (
    id BIGSERIAL PRIMARY KEY,
    observed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    group_key VARCHAR(100) NOT NULL,
    sub_cluster_id SMALLINT NOT NULL DEFAULT 0,
    parent_name TEXT NOT NULL,
    candidate_mmsi VARCHAR(20) NOT NULL,
    candidate_name VARCHAR(200),
    candidate_vessel_id INT REFERENCES kcg.fleet_vessels(id) ON DELETE SET NULL,
    rank INT NOT NULL,
    candidate_source VARCHAR(100) NOT NULL,
    model_id INT REFERENCES kcg.correlation_param_models(id) ON DELETE SET NULL,
    model_name VARCHAR(100),
    base_corr_score DOUBLE PRECISION DEFAULT 0,
    name_match_score DOUBLE PRECISION DEFAULT 0,
    track_similarity_score DOUBLE PRECISION DEFAULT 0,
    visit_score_6h DOUBLE PRECISION DEFAULT 0,
    proximity_score_6h DOUBLE PRECISION DEFAULT 0,
    activity_sync_score_6h DOUBLE PRECISION DEFAULT 0,
    stability_score DOUBLE PRECISION DEFAULT 0,
    registry_bonus DOUBLE PRECISION DEFAULT 0,
    final_score DOUBLE PRECISION DEFAULT 0,
    margin_from_top DOUBLE PRECISION DEFAULT 0,
    evidence JSONB NOT NULL DEFAULT '{}'::jsonb,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    UNIQUE (observed_at, group_key, sub_cluster_id, candidate_mmsi)
);

CREATE INDEX IF NOT EXISTS idx_ggpcs_group_time
    ON kcg.gear_group_parent_candidate_snapshots(group_key, sub_cluster_id, observed_at DESC, rank ASC);

CREATE INDEX IF NOT EXISTS idx_ggpcs_candidate
    ON kcg.gear_group_parent_candidate_snapshots(candidate_mmsi, observed_at DESC);

CREATE TABLE IF NOT EXISTS kcg.gear_group_parent_resolution (
    group_key VARCHAR(100) NOT NULL,
    sub_cluster_id SMALLINT NOT NULL DEFAULT 0,
    parent_name TEXT NOT NULL,
    normalized_parent_name VARCHAR(200),
    status VARCHAR(40) NOT NULL,
    selected_parent_mmsi VARCHAR(20),
    selected_parent_name VARCHAR(200),
    selected_vessel_id INT REFERENCES kcg.fleet_vessels(id) ON DELETE SET NULL,
    confidence DOUBLE PRECISION,
    decision_source VARCHAR(40),
    top_score DOUBLE PRECISION DEFAULT 0,
    second_score DOUBLE PRECISION DEFAULT 0,
    score_margin DOUBLE PRECISION DEFAULT 0,
    stable_cycles INT DEFAULT 0,
    last_evaluated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    last_promoted_at TIMESTAMPTZ,
    approved_by VARCHAR(100),
    approved_at TIMESTAMPTZ,
    manual_comment TEXT,
    rejected_candidate_mmsi VARCHAR(20),
    rejected_at TIMESTAMPTZ,
    evidence_summary JSONB NOT NULL DEFAULT '{}'::jsonb,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    PRIMARY KEY (group_key, sub_cluster_id)
);

CREATE INDEX IF NOT EXISTS idx_ggpr_status
    ON kcg.gear_group_parent_resolution(status, last_evaluated_at DESC);

CREATE INDEX IF NOT EXISTS idx_ggpr_parent
    ON kcg.gear_group_parent_resolution(selected_parent_mmsi);

CREATE TABLE IF NOT EXISTS kcg.gear_group_parent_review_log (
    id BIGSERIAL PRIMARY KEY,
    group_key VARCHAR(100) NOT NULL,
    sub_cluster_id SMALLINT NOT NULL DEFAULT 0,
    action VARCHAR(20) NOT NULL,
    selected_parent_mmsi VARCHAR(20),
    actor VARCHAR(100) NOT NULL,
    comment TEXT,
    payload JSONB NOT NULL DEFAULT '{}'::jsonb,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_ggprl_group_time
    ON kcg.gear_group_parent_review_log(group_key, sub_cluster_id, created_at DESC);

-- ── copied schema 환경의 sequence 정렬 ─────────────────────────────

SELECT setval(
    pg_get_serial_sequence('kcg.fleet_companies', 'id'),
    COALESCE((SELECT MAX(id) FROM kcg.fleet_companies), 1),
    TRUE
);

SELECT setval(
    pg_get_serial_sequence('kcg.fleet_vessels', 'id'),
    COALESCE((SELECT MAX(id) FROM kcg.fleet_vessels), 1),
    TRUE
);

SELECT setval(
    pg_get_serial_sequence('kcg.gear_identity_log', 'id'),
    COALESCE((SELECT MAX(id) FROM kcg.gear_identity_log), 1),
    TRUE
);

SELECT setval(
    pg_get_serial_sequence('kcg.fleet_tracking_snapshot', 'id'),
    COALESCE((SELECT MAX(id) FROM kcg.fleet_tracking_snapshot), 1),
    TRUE
);

SELECT setval(
    pg_get_serial_sequence('kcg.group_polygon_snapshots', 'id'),
    COALESCE((SELECT MAX(id) FROM kcg.group_polygon_snapshots), 1),
    TRUE
);

SELECT setval(
    pg_get_serial_sequence('kcg.gear_correlation_scores', 'id'),
    COALESCE((SELECT MAX(id) FROM kcg.gear_correlation_scores), 1),
    TRUE
);
