-- ============================================================
-- Migration: 033_analytics_expansion.sql
-- Description: Rozbudowa systemu analityki użytkowników
-- Author: Claude
-- Date: 2026-01-30
-- ============================================================

BEGIN;

-- ============================================================
-- 1. UTM PARAMETERS - Dodanie do user_sessions
-- ============================================================

ALTER TABLE user_sessions ADD COLUMN IF NOT EXISTS utm_source VARCHAR(255);
ALTER TABLE user_sessions ADD COLUMN IF NOT EXISTS utm_medium VARCHAR(255);
ALTER TABLE user_sessions ADD COLUMN IF NOT EXISTS utm_campaign VARCHAR(255);
ALTER TABLE user_sessions ADD COLUMN IF NOT EXISTS utm_term VARCHAR(255);
ALTER TABLE user_sessions ADD COLUMN IF NOT EXISTS utm_content VARCHAR(255);

-- Indeks dla raportowania kampanii
CREATE INDEX IF NOT EXISTS idx_user_sessions_utm_source ON user_sessions(utm_source) WHERE utm_source IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_user_sessions_utm_campaign ON user_sessions(utm_campaign) WHERE utm_campaign IS NOT NULL;

COMMENT ON COLUMN user_sessions.utm_source IS 'Źródło ruchu: google, facebook, newsletter';
COMMENT ON COLUMN user_sessions.utm_medium IS 'Medium: cpc, email, social, organic';
COMMENT ON COLUMN user_sessions.utm_campaign IS 'Nazwa kampanii marketingowej';
COMMENT ON COLUMN user_sessions.utm_term IS 'Słowo kluczowe (dla reklam PPC)';
COMMENT ON COLUMN user_sessions.utm_content IS 'Wariant reklamy/linku';

-- ============================================================
-- 2. SCROLL DEPTH - Dodanie do page_views
-- ============================================================

ALTER TABLE page_views ADD COLUMN IF NOT EXISTS scroll_depth_percent INTEGER;

COMMENT ON COLUMN page_views.scroll_depth_percent IS 'Maksymalny % przewinięcia strony (0-100)';

-- ============================================================
-- 3. SEARCH QUERIES - Nowa tabela
-- ============================================================

CREATE TABLE IF NOT EXISTS search_queries (
    id SERIAL PRIMARY KEY,
    session_id INTEGER REFERENCES user_sessions(id) ON DELETE SET NULL,
    user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,

    -- Zapytanie
    query VARCHAR(500) NOT NULL,
    query_normalized VARCHAR(500),  -- lowercase, bez znaków specjalnych

    -- Wyniki
    results_count INTEGER DEFAULT 0,
    has_results BOOLEAN DEFAULT TRUE,

    -- Interakcja z wynikami
    clicked_result_position INTEGER,  -- Która pozycja była kliknięta (1-based)
    clicked_company_id INTEGER REFERENCES companies(id) ON DELETE SET NULL,

    -- Kontekst
    search_type VARCHAR(50) DEFAULT 'main',  -- main, chat, autocomplete
    filters_used JSONB,  -- {"category": "IT", "city": "Wejherowo"}

    -- Timing
    searched_at TIMESTAMP NOT NULL DEFAULT NOW(),
    time_to_click_ms INTEGER,  -- Czas od wyświetlenia do kliknięcia

    created_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_search_queries_query ON search_queries(query_normalized);
CREATE INDEX IF NOT EXISTS idx_search_queries_searched_at ON search_queries(searched_at);
CREATE INDEX IF NOT EXISTS idx_search_queries_session ON search_queries(session_id);
CREATE INDEX IF NOT EXISTS idx_search_queries_has_results ON search_queries(has_results) WHERE has_results = FALSE;

COMMENT ON TABLE search_queries IS 'Historia wyszukiwań użytkowników w portalu';

-- ============================================================
-- 4. CONVERSION EVENTS - Nowa tabela
-- ============================================================

CREATE TABLE IF NOT EXISTS conversion_events (
    id SERIAL PRIMARY KEY,
    session_id INTEGER REFERENCES user_sessions(id) ON DELETE SET NULL,
    user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,

    -- Typ konwersji
    event_type VARCHAR(50) NOT NULL,  -- register, login, contact_click, rsvp, message, classified
    event_category VARCHAR(50),  -- engagement, acquisition, activation

    -- Kontekst
    company_id INTEGER REFERENCES companies(id) ON DELETE SET NULL,  -- Dla contact_click
    target_type VARCHAR(50),  -- email, phone, website, rsvp_event, etc.
    target_value VARCHAR(500),  -- np. adres email, id eventu

    -- Źródło konwersji
    source_page VARCHAR(500),  -- URL strony na której nastąpiła konwersja
    referrer VARCHAR(500),

    -- Dodatkowe dane
    event_metadata JSONB,  -- Elastyczne dane kontekstowe

    -- Timing
    converted_at TIMESTAMP NOT NULL DEFAULT NOW(),

    created_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_conversion_events_type ON conversion_events(event_type);
CREATE INDEX IF NOT EXISTS idx_conversion_events_converted_at ON conversion_events(converted_at);
CREATE INDEX IF NOT EXISTS idx_conversion_events_session ON conversion_events(session_id);
CREATE INDEX IF NOT EXISTS idx_conversion_events_user ON conversion_events(user_id);
CREATE INDEX IF NOT EXISTS idx_conversion_events_company ON conversion_events(company_id) WHERE company_id IS NOT NULL;

COMMENT ON TABLE conversion_events IS 'Kluczowe konwersje: rejestracje, kontakty, RSVP';

-- ============================================================
-- 5. JS ERRORS - Nowa tabela
-- ============================================================

CREATE TABLE IF NOT EXISTS js_errors (
    id SERIAL PRIMARY KEY,
    session_id INTEGER REFERENCES user_sessions(id) ON DELETE SET NULL,

    -- Błąd
    message TEXT NOT NULL,
    source VARCHAR(500),  -- URL pliku JS
    lineno INTEGER,
    colno INTEGER,
    stack TEXT,  -- Stack trace

    -- Kontekst
    url VARCHAR(2000),  -- URL strony gdzie wystąpił błąd
    user_agent VARCHAR(500),

    -- Agregacja
    error_hash VARCHAR(64),  -- SHA256 z message+source+lineno dla grupowania

    occurred_at TIMESTAMP NOT NULL DEFAULT NOW(),
    created_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_js_errors_hash ON js_errors(error_hash);
CREATE INDEX IF NOT EXISTS idx_js_errors_occurred_at ON js_errors(occurred_at);
CREATE INDEX IF NOT EXISTS idx_js_errors_source ON js_errors(source);

COMMENT ON TABLE js_errors IS 'Błędy JavaScript zgłaszane z przeglądarek użytkowników';

-- ============================================================
-- 6. PERFORMANCE METRICS - Dodanie do page_views
-- ============================================================

ALTER TABLE page_views ADD COLUMN IF NOT EXISTS dom_content_loaded_ms INTEGER;
ALTER TABLE page_views ADD COLUMN IF NOT EXISTS load_time_ms INTEGER;
ALTER TABLE page_views ADD COLUMN IF NOT EXISTS first_paint_ms INTEGER;
ALTER TABLE page_views ADD COLUMN IF NOT EXISTS first_contentful_paint_ms INTEGER;

COMMENT ON COLUMN page_views.dom_content_loaded_ms IS 'Czas do DOMContentLoaded (ms)';
COMMENT ON COLUMN page_views.load_time_ms IS 'Pełny czas ładowania strony (ms)';
COMMENT ON COLUMN page_views.first_paint_ms IS 'Czas do First Paint (ms)';
COMMENT ON COLUMN page_views.first_contentful_paint_ms IS 'Czas do First Contentful Paint (ms)';

-- ============================================================
-- 7. AGREGATY DZIENNE - Rozszerzenie analytics_daily
-- ============================================================

-- Bounce rate (już istnieje, ale upewniamy się)
ALTER TABLE analytics_daily ADD COLUMN IF NOT EXISTS bounce_rate NUMERIC(5,2);

-- Nowe metryki
ALTER TABLE analytics_daily ADD COLUMN IF NOT EXISTS conversions_count INTEGER DEFAULT 0;
ALTER TABLE analytics_daily ADD COLUMN IF NOT EXISTS searches_count INTEGER DEFAULT 0;
ALTER TABLE analytics_daily ADD COLUMN IF NOT EXISTS searches_no_results INTEGER DEFAULT 0;
ALTER TABLE analytics_daily ADD COLUMN IF NOT EXISTS avg_scroll_depth NUMERIC(5,2);
ALTER TABLE analytics_daily ADD COLUMN IF NOT EXISTS js_errors_count INTEGER DEFAULT 0;

-- UTM breakdown (JSONB dla elastyczności)
ALTER TABLE analytics_daily ADD COLUMN IF NOT EXISTS utm_breakdown JSONB;

-- Konwersje wg typu
ALTER TABLE analytics_daily ADD COLUMN IF NOT EXISTS conversions_breakdown JSONB;

COMMENT ON COLUMN analytics_daily.bounce_rate IS 'Procent sesji z 1 pageview lub <10s';
COMMENT ON COLUMN analytics_daily.conversions_count IS 'Łączna liczba konwersji';
COMMENT ON COLUMN analytics_daily.searches_count IS 'Liczba wyszukiwań';
COMMENT ON COLUMN analytics_daily.searches_no_results IS 'Wyszukiwania bez wyników';
COMMENT ON COLUMN analytics_daily.avg_scroll_depth IS 'Średnia głębokość scrollowania (%)';
COMMENT ON COLUMN analytics_daily.utm_breakdown IS 'Rozkład sesji wg UTM source';
COMMENT ON COLUMN analytics_daily.conversions_breakdown IS 'Rozkład konwersji wg typu';

-- ============================================================
-- 8. POPULAR SEARCHES - Agregat dzienny
-- ============================================================

CREATE TABLE IF NOT EXISTS popular_searches_daily (
    id SERIAL PRIMARY KEY,
    date DATE NOT NULL,
    query_normalized VARCHAR(500) NOT NULL,

    search_count INTEGER DEFAULT 0,
    unique_users INTEGER DEFAULT 0,
    click_count INTEGER DEFAULT 0,  -- Ile razy kliknięto wynik
    avg_results_count NUMERIC(10,2),

    UNIQUE(date, query_normalized)
);

CREATE INDEX IF NOT EXISTS idx_popular_searches_date ON popular_searches_daily(date);

COMMENT ON TABLE popular_searches_daily IS 'Popularne wyszukiwania - dzienne agregaty';

-- ============================================================
-- 9. HOURLY ACTIVITY - Dla wzorców czasowych
-- ============================================================

CREATE TABLE IF NOT EXISTS hourly_activity (
    id SERIAL PRIMARY KEY,
    date DATE NOT NULL,
    hour INTEGER NOT NULL CHECK (hour >= 0 AND hour <= 23),

    sessions_count INTEGER DEFAULT 0,
    page_views_count INTEGER DEFAULT 0,
    unique_users INTEGER DEFAULT 0,

    UNIQUE(date, hour)
);

CREATE INDEX IF NOT EXISTS idx_hourly_activity_date ON hourly_activity(date);

COMMENT ON TABLE hourly_activity IS 'Aktywność wg godziny - dla analizy wzorców czasowych';

-- ============================================================
-- 10. UPRAWNIENIA
-- ============================================================

-- Nadanie uprawnień dla roli nordabiz_app
GRANT ALL ON TABLE search_queries TO nordabiz_app;
GRANT ALL ON TABLE conversion_events TO nordabiz_app;
GRANT ALL ON TABLE js_errors TO nordabiz_app;
GRANT ALL ON TABLE popular_searches_daily TO nordabiz_app;
GRANT ALL ON TABLE hourly_activity TO nordabiz_app;

GRANT USAGE, SELECT ON SEQUENCE search_queries_id_seq TO nordabiz_app;
GRANT USAGE, SELECT ON SEQUENCE conversion_events_id_seq TO nordabiz_app;
GRANT USAGE, SELECT ON SEQUENCE js_errors_id_seq TO nordabiz_app;
GRANT USAGE, SELECT ON SEQUENCE popular_searches_daily_id_seq TO nordabiz_app;
GRANT USAGE, SELECT ON SEQUENCE hourly_activity_id_seq TO nordabiz_app;

COMMIT;

-- ============================================================
-- WERYFIKACJA
-- ============================================================

-- Sprawdź czy wszystkie tabele istnieją
DO $$
BEGIN
    RAISE NOTICE 'Weryfikacja migracji 033_analytics_expansion:';
    RAISE NOTICE '- search_queries: %', (SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'search_queries');
    RAISE NOTICE '- conversion_events: %', (SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'conversion_events');
    RAISE NOTICE '- js_errors: %', (SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'js_errors');
    RAISE NOTICE '- popular_searches_daily: %', (SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'popular_searches_daily');
    RAISE NOTICE '- hourly_activity: %', (SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'hourly_activity');
    RAISE NOTICE 'Migracja 033 zakończona pomyślnie!';
END $$;
