-- =============================================================================
-- Migration 044: external market source / offer normalization
-- MOMO PRO / PChome revenue growth automation
-- 2026-06-15 Taipei
-- =============================================================================
-- Notes:
--   Additive only. This migration does not drop, truncate, or rewrite existing
--   competitor_prices / competitor_price_history / market_* tables.
-- =============================================================================

CREATE TABLE IF NOT EXISTS external_market_sources (
    id BIGSERIAL PRIMARY KEY,
    code VARCHAR(80) NOT NULL UNIQUE,
    display_name VARCHAR(160) NOT NULL,
    platform_code VARCHAR(80) NOT NULL,
    source_kind VARCHAR(60) NOT NULL,
    status VARCHAR(40) NOT NULL DEFAULT 'paused',
    enabled BOOLEAN NOT NULL DEFAULT FALSE,
    write_enabled BOOLEAN NOT NULL DEFAULT FALSE,
    allowed_input_methods_json TEXT,
    quality_policy_json TEXT,
    plain_note TEXT,
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_external_market_sources_code
    ON external_market_sources (code);
CREATE INDEX IF NOT EXISTS idx_external_market_sources_platform_code
    ON external_market_sources (platform_code);
CREATE INDEX IF NOT EXISTS idx_external_market_sources_source_kind
    ON external_market_sources (source_kind);
CREATE INDEX IF NOT EXISTS idx_external_market_sources_status
    ON external_market_sources (status, enabled);

CREATE TABLE IF NOT EXISTS external_offers (
    id BIGSERIAL PRIMARY KEY,
    source_code VARCHAR(80) NOT NULL REFERENCES external_market_sources(code),
    platform_code VARCHAR(80) NOT NULL,
    source_product_id VARCHAR(220) NOT NULL,
    source_offer_key VARCHAR(260) NOT NULL,
    title TEXT NOT NULL,
    brand VARCHAR(180),
    category_text VARCHAR(320),
    product_url TEXT,
    image_url TEXT,
    price DOUBLE PRECISION,
    original_price DOUBLE PRECISION,
    currency VARCHAR(12) NOT NULL DEFAULT 'TWD',
    stock_status VARCHAR(80),
    sold_count INTEGER,
    rating DOUBLE PRECISION,
    review_count INTEGER,
    observed_at TIMESTAMP NOT NULL DEFAULT NOW(),
    expires_at TIMESTAMP,
    ingestion_method VARCHAR(60) NOT NULL,
    connector_key VARCHAR(120),
    pchome_product_id VARCHAR(120),
    momo_sku VARCHAR(80),
    match_status VARCHAR(40) NOT NULL DEFAULT 'unmatched',
    quality_score DOUBLE PRECISION NOT NULL DEFAULT 0,
    data_quality_status VARCHAR(40) NOT NULL DEFAULT 'needs_review',
    quality_notes_json TEXT,
    raw_payload_json TEXT,
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
    CONSTRAINT uq_external_offer_source_product_observed
        UNIQUE (source_code, source_product_id, observed_at, ingestion_method)
);

CREATE INDEX IF NOT EXISTS idx_external_offers_source_code
    ON external_offers (source_code);
CREATE INDEX IF NOT EXISTS idx_external_offers_platform_code
    ON external_offers (platform_code);
CREATE INDEX IF NOT EXISTS idx_external_offers_source_product_id
    ON external_offers (source_product_id);
CREATE INDEX IF NOT EXISTS idx_external_offers_brand
    ON external_offers (brand);
CREATE INDEX IF NOT EXISTS idx_external_offers_category_text
    ON external_offers (category_text);
CREATE INDEX IF NOT EXISTS idx_external_offers_stock_status
    ON external_offers (stock_status);
CREATE INDEX IF NOT EXISTS idx_external_offers_observed_at
    ON external_offers (observed_at);
CREATE INDEX IF NOT EXISTS idx_external_offers_expires_at
    ON external_offers (expires_at);
CREATE INDEX IF NOT EXISTS idx_external_offers_ingestion_method
    ON external_offers (ingestion_method);
CREATE INDEX IF NOT EXISTS idx_external_offers_connector_key
    ON external_offers (connector_key);
CREATE INDEX IF NOT EXISTS idx_external_offers_pchome_product_id
    ON external_offers (pchome_product_id);
CREATE INDEX IF NOT EXISTS idx_external_offers_momo_sku
    ON external_offers (momo_sku);
CREATE INDEX IF NOT EXISTS idx_external_offers_match_status
    ON external_offers (match_status);
CREATE INDEX IF NOT EXISTS idx_external_offers_data_quality_status
    ON external_offers (data_quality_status);
CREATE INDEX IF NOT EXISTS idx_external_offers_source_seen
    ON external_offers (source_code, observed_at);
CREATE INDEX IF NOT EXISTS idx_external_offers_platform_product
    ON external_offers (platform_code, source_product_id);
CREATE INDEX IF NOT EXISTS idx_external_offers_pchome_product
    ON external_offers (pchome_product_id, source_code);
CREATE INDEX IF NOT EXISTS idx_external_offers_match_quality
    ON external_offers (match_status, data_quality_status, quality_score);

INSERT INTO external_market_sources (
    code,
    display_name,
    platform_code,
    source_kind,
    status,
    enabled,
    write_enabled,
    allowed_input_methods_json,
    quality_policy_json,
    plain_note
) VALUES
    (
        'momo_reference',
        'MOMO 外部價格參考',
        'momo',
        'legacy_bridge',
        'active',
        TRUE,
        FALSE,
        '["legacy_competitor_cache","manual_csv","provider_api"]',
        '{"minimum_match_status":"verified","minimum_quality_score":76}',
        '目前只採用已確認同款的 MOMO 參考價。'
    ),
    (
        'shopee',
        '蝦皮',
        'shopee',
        'connector_contract',
        'paused',
        FALSE,
        FALSE,
        '["official_api","provider_api","manual_csv"]',
        '{"minimum_match_status":"verified","manual_review_required":true}',
        '先暫停，不進告警；未來可接官方 API、供應商資料或手動 CSV。'
    ),
    (
        'coupang',
        '酷澎',
        'coupang',
        'connector_contract',
        'paused',
        FALSE,
        FALSE,
        '["official_api","provider_api","manual_csv"]',
        '{"minimum_match_status":"verified","manual_review_required":true}',
        '先暫停，不進告警；未來可接官方 API、供應商資料或手動 CSV。'
    )
ON CONFLICT (code) DO UPDATE SET
    display_name = EXCLUDED.display_name,
    platform_code = EXCLUDED.platform_code,
    source_kind = EXCLUDED.source_kind,
    status = EXCLUDED.status,
    enabled = EXCLUDED.enabled,
    allowed_input_methods_json = EXCLUDED.allowed_input_methods_json,
    quality_policy_json = EXCLUDED.quality_policy_json,
    plain_note = EXCLUDED.plain_note,
    updated_at = NOW();

GRANT ALL PRIVILEGES ON external_market_sources TO momo;
GRANT ALL PRIVILEGES ON external_offers TO momo;
GRANT USAGE, SELECT ON SEQUENCE external_market_sources_id_seq TO momo;
GRANT USAGE, SELECT ON SEQUENCE external_offers_id_seq TO momo;

DO $$
BEGIN
    RAISE NOTICE 'Migration 044 complete: external market source and offer normalization is ready';
END $$;
