-- ============================================================================
-- JellyStat API Functions
-- Parameterized database functions callable by the API layer as:
--   SELECT * FROM fn_user_watch_history('user_id_here', 10080);
--   SELECT * FROM fn_user_genre_summary('user_id_here', 10080);
--   SELECT * FROM fn_user_summary('user_id_here');
-- ============================================================================

-- ----------------------------------------------------------------------------
-- 1. User Watch History
--    Returns every distinct title watched in the last N minutes,
--    grouped and summed by title, ordered by most-watched first.
-- ----------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION public.fn_user_watch_history(
    p_user_id  TEXT,
    p_minutes  INTEGER DEFAULT 10080   -- 7 days in minutes
)
RETURNS TABLE(
    title           TEXT,
    watch_time_sec  NUMERIC,
    media_type      TEXT
)
LANGUAGE sql
STABLE
AS $$
    SELECT
        COALESCE(a."SeriesName", a."NowPlayingItemName") AS title,
        SUM(a."PlaybackDuration")::NUMERIC                 AS watch_time_sec,
        CASE
            WHEN a."SeriesName" IS NOT NULL THEN 'series'
            ELSE 'movie'
        END                                                AS media_type
    FROM jf_playback_activity a
    WHERE a."UserId" = p_user_id
      AND a."ActivityDateInserted"
          >= NOW() - (p_minutes * INTERVAL '1 minute')
    GROUP BY
        COALESCE(a."SeriesName", a."NowPlayingItemName"),
        CASE WHEN a."SeriesName" IS NOT NULL THEN 'series' ELSE 'movie' END
    ORDER BY watch_time_sec DESC;
$$;

-- ----------------------------------------------------------------------------
-- 2. Genre Summary
--    Returns total watch time per genre for a user over the last N minutes.
--    Resolves genres for both movies (directly on the item) and series
--    episodes (via jf_library_episodes → jf_library_items chain).
-- ----------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION public.fn_user_genre_summary(
    p_user_id  TEXT,
    p_minutes  INTEGER DEFAULT 10080
)
RETURNS TABLE(
    genre           TEXT,
    watch_time_sec  NUMERIC
)
LANGUAGE sql
STABLE
AS $$
    WITH movie_genres AS (
        -- Movies: join playback directly to library_items on NowPlayingItemId
        SELECT
            genre_item.value     AS genre,
            SUM(a."PlaybackDuration") AS watch_time_sec
        FROM jf_playback_activity a
        JOIN jf_library_items i
            ON i."Id" = a."NowPlayingItemId"
        CROSS JOIN LATERAL jsonb_array_elements_text(i."Genres") AS genre_item(value)
        WHERE a."UserId" = p_user_id
          AND a."SeriesName" IS NULL          -- movies only
          AND a."ActivityDateInserted"
              >= NOW() - (p_minutes * INTERVAL '1 minute')
          AND i."Genres" IS NOT NULL
          AND jsonb_array_length(i."Genres") > 0
        GROUP BY genre_item.value
    ),
    series_genres AS (
        -- Series: playback → episodes → series item → genres
        SELECT
            genre_item.value     AS genre,
            SUM(a."PlaybackDuration") AS watch_time_sec
        FROM jf_playback_activity a
        JOIN jf_library_episodes e
            ON e."EpisodeId" = a."EpisodeId"
        JOIN jf_library_items i
            ON i."Id" = e."SeriesId"
        CROSS JOIN LATERAL jsonb_array_elements_text(i."Genres") AS genre_item(value)
        WHERE a."UserId" = p_user_id
          AND a."SeriesName" IS NOT NULL      -- TV episodes only
          AND a."ActivityDateInserted"
              >= NOW() - (p_minutes * INTERVAL '1 minute')
          AND i."Genres" IS NOT NULL
          AND jsonb_array_length(i."Genres") > 0
        GROUP BY genre_item.value
    ),
    combined AS (
        SELECT genre, watch_time_sec FROM movie_genres
        UNION ALL
        SELECT genre, watch_time_sec FROM series_genres
    )
    SELECT
        genre,
        SUM(watch_time_sec)::NUMERIC AS watch_time_sec
    FROM combined
    GROUP BY genre
    ORDER BY watch_time_sec DESC;
$$;

-- ----------------------------------------------------------------------------
-- 3. User Summary
--    One-shot dashboard: all-time stats + recent windows + top genres.
--    Returns key-value rows that the API trivially converts to a JSON object
--    with Object.fromEntries() or similar.
-- ----------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION public.fn_user_summary(
    p_user_id  TEXT
)
RETURNS TABLE(
    metric  TEXT,
    value   JSONB
)
LANGUAGE sql
STABLE
AS $$
    -- total_watch_time (all time)
    SELECT 'total_watch_time'::TEXT AS metric,
           to_jsonb(COALESCE(SUM("PlaybackDuration"), 0)::NUMERIC) AS value
    FROM jf_playback_activity
    WHERE "UserId" = p_user_id

    UNION ALL

    -- most_watched_series (by total watch time)
    SELECT 'most_watched_series'::TEXT AS metric,
           COALESCE(
               (SELECT to_jsonb("SeriesName")
                FROM jf_playback_activity
                WHERE "UserId" = p_user_id
                  AND "SeriesName" IS NOT NULL
                GROUP BY "SeriesName"
                ORDER BY SUM("PlaybackDuration") DESC
                LIMIT 1),
               'null'::JSONB
           ) AS value

    UNION ALL

    -- most_watched_movie (by total watch time)
    SELECT 'most_watched_movie'::TEXT AS metric,
           COALESCE(
               (SELECT to_jsonb("NowPlayingItemName")
                FROM jf_playback_activity
                WHERE "UserId" = p_user_id
                  AND "SeriesName" IS NULL
                GROUP BY "NowPlayingItemName"
                ORDER BY SUM("PlaybackDuration") DESC
                LIMIT 1),
               'null'::JSONB
           ) AS value

    UNION ALL

    -- total_watch_time_last_month (last 30 days)
    SELECT 'total_last_30d'::TEXT AS metric,
           to_jsonb(COALESCE(SUM("PlaybackDuration"), 0)::NUMERIC) AS value
    FROM jf_playback_activity
    WHERE "UserId" = p_user_id
      AND "ActivityDateInserted" >= NOW() - INTERVAL '30 days'

    UNION ALL

    -- total_watch_time_last_week (last 7 days)
    SELECT 'total_last_7d'::TEXT AS metric,
           to_jsonb(COALESCE(SUM("PlaybackDuration"), 0)::NUMERIC) AS value
    FROM jf_playback_activity
    WHERE "UserId" = p_user_id
      AND "ActivityDateInserted" >= NOW() - INTERVAL '7 days'

    UNION ALL

    -- top_genres (top 3 all-time, as a JSON array)
    SELECT 'top_genres'::TEXT AS metric,
           COALESCE(
               (SELECT jsonb_agg(genre ORDER BY watch_time_sec DESC)
                FROM (
                    SELECT genre, SUM(watch_time_sec) AS watch_time_sec
                    FROM (
                        -- movies
                        SELECT
                            genre_item.value     AS genre,
                            SUM(a."PlaybackDuration") AS watch_time_sec
                        FROM jf_playback_activity a
                        JOIN jf_library_items i ON i."Id" = a."NowPlayingItemId"
                        CROSS JOIN LATERAL jsonb_array_elements_text(i."Genres") AS genre_item(value)
                        WHERE a."UserId" = p_user_id
                          AND a."SeriesName" IS NULL
                          AND i."Genres" IS NOT NULL
                          AND jsonb_array_length(i."Genres") > 0
                        GROUP BY genre_item.value

                        UNION ALL

                        -- series
                        SELECT
                            genre_item.value     AS genre,
                            SUM(a."PlaybackDuration") AS watch_time_sec
                        FROM jf_playback_activity a
                        JOIN jf_library_episodes e ON e."EpisodeId" = a."EpisodeId"
                        JOIN jf_library_items i ON i."Id" = e."SeriesId"
                        CROSS JOIN LATERAL jsonb_array_elements_text(i."Genres") AS genre_item(value)
                        WHERE a."UserId" = p_user_id
                          AND a."SeriesName" IS NOT NULL
                          AND i."Genres" IS NOT NULL
                          AND jsonb_array_length(i."Genres") > 0
                        GROUP BY genre_item.value
                    ) combined
                    GROUP BY genre
                    ORDER BY SUM(watch_time_sec) DESC
                    LIMIT 3
                ) top3
               ),
               '[]'::JSONB
           ) AS value;
$$;