-- Copyright IBM Corp. 2020, 2026
-- SPDX-License-Identifier: BUSL-1.1

begin;
  select plan(39);

  select lives_ok('truncate wh_auth_token_accumulating_fact,
                            wh_user_dimension,
                            wh_session_accumulating_fact,
                            wh_session_connection_accumulating_fact;',
                  'Truncate tables in preparation for testing');

  -- validate the warehouse fact tables are empty
  select is(count(*), 0::bigint, 'wh_auth_token_accumulating_fact is not empty') from wh_auth_token_accumulating_fact;
  select is(count(*), 0::bigint, 'wh_user_dimension is not empty')               from wh_user_dimension;

  -- Create a user dimension for corresponding auth token's user.
  insert into wh_user_dimension (
    user_id,                 user_name,                user_description,
    auth_account_id,         auth_account_type,        auth_account_name,             auth_account_description,
    auth_method_id,          auth_method_type,         auth_method_name,              auth_method_description,
    user_organization_id,    user_organization_name,   user_organization_description,
    current_row_indicator,
    row_effective_time,      row_expiration_time,
    auth_method_external_id, auth_account_external_id, auth_account_full_name,        auth_account_email
  ) values (
    'u_____user1',           'None',                   'None',
    'a______acc1',           'None',                   'None',                        'None',
    'am______am1',           'None',                   'None',                        'None',
    'o______org1',           'None',                   'None',
    'current',
    now(),                   'infinity'::timestamptz,
    'None',                  'None',                   'None',                        'None'
  );

  -- validate view returns 0 active users for last two months
  select results_eq(
            'select * from hcp_billing_monthly_active_users_last_2_months',
            $$
            values (date_trunc('month', now()), date_trunc('hour', now()), 0::bigint),
                   (date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), 0::bigint)
            $$);


  -- Now insert some edge cases to make sure we count them correctly

  -- active_time_range spans start of a month
  with month_range (previous) as (
    select tstzrange(date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), '[)')
  ),
  range (active, valid) as (
    select tstzrange(lower(previous) - interval '5 minutes', lower(previous) + interval '5 minutes', '[]'),
           tstzrange(lower(previous) - interval '5 minutes', 'infinity'::timestamptz)
      from month_range
  ),
  user_key (key) as (
    select key
      from wh_user_dimension
     where user_id = 'u_____user1'
  )
  insert into wh_auth_token_accumulating_fact (
              auth_token_id,                                user_key,
              auth_token_issued_date_key,                   auth_token_issued_time_key,                    auth_token_issued_time,
              auth_token_deleted_date_key,                  auth_token_deleted_time_key,                   auth_token_deleted_time,
              auth_token_approximate_last_access_date_key,  auth_token_approximate_last_access_time_key,   auth_token_approximate_last_access_time,
              auth_token_approximate_active_time_range,
              auth_token_valid_time_range,
              auth_token_count
  )
      select 'at____atok1',                                 user_key.key,
             wh_date_key(lower(range.valid)),               wh_time_key(lower(range.valid)),               lower(range.valid),
             coalesce(wh_date_key(upper(range.valid)), -1), coalesce(wh_time_key(upper(range.valid)), -1), upper(range.valid),
             wh_date_key(upper(range.active)),              wh_time_key(upper(range.active)),              upper(range.active),
             range.active,
             range.valid,
             1
        from range, user_key;

  select is(count(*), 1::bigint, 'wh_auth_token_accumulating_fact is not empty') from wh_auth_token_accumulating_fact;
  select is(count(*), 1::bigint, 'wh_user_dimension is not empty')               from wh_user_dimension;
  select results_eq(
            'select * from hcp_billing_monthly_active_users_last_2_months',
            $$
            values (date_trunc('month', now()),                      date_trunc('hour', now()),  0::bigint),
                   (date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), 1::bigint)
            $$);

  -- active_time_range within start/end of month
  select lives_ok('truncate wh_auth_token_accumulating_fact');
  with month_range (previous) as (
    select tstzrange(date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), '[)')
  ),
  range (active, valid) as (
    select tstzrange(lower(previous) + interval '5 minutes', lower(previous) + interval '10 minutes', '[]'),
           tstzrange(lower(previous) + interval '5 minutes', 'infinity'::timestamptz)
      from month_range
  ),
  user_key (key) as (
    select key
      from wh_user_dimension
     where user_id = 'u_____user1'
  )
  insert into wh_auth_token_accumulating_fact (
              auth_token_id,                                user_key,
              auth_token_issued_date_key,                   auth_token_issued_time_key,                    auth_token_issued_time,
              auth_token_deleted_date_key,                  auth_token_deleted_time_key,                   auth_token_deleted_time,
              auth_token_approximate_last_access_date_key,  auth_token_approximate_last_access_time_key,   auth_token_approximate_last_access_time,
              auth_token_approximate_active_time_range,
              auth_token_valid_time_range,
              auth_token_count
  )
      select 'at____atok1',                                 user_key.key,
             wh_date_key(lower(range.valid)),               wh_time_key(lower(range.valid)),               lower(range.valid),
             coalesce(wh_date_key(upper(range.valid)), -1), coalesce(wh_time_key(upper(range.valid)), -1), upper(range.valid),
             wh_date_key(upper(range.active)),              wh_time_key(upper(range.active)),              upper(range.active),
             range.active,
             range.valid,
             1
        from range, user_key;

  select is(count(*), 1::bigint, 'wh_auth_token_accumulating_fact is not empty') from wh_auth_token_accumulating_fact;
  select is(count(*), 1::bigint, 'wh_user_dimension is not empty')               from wh_user_dimension;
  select results_eq(
            'select * from hcp_billing_monthly_active_users_last_2_months',
            $$
            values (date_trunc('month', now()),                      date_trunc('hour', now()),  0::bigint),
                   (date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), 1::bigint)
            $$);

  -- active_time_range spances end of month
  select lives_ok('truncate wh_auth_token_accumulating_fact');
  with month_range (previous) as (
    select tstzrange(date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), '[)')
  ),
  range (active, valid) as (
    select tstzrange(upper(previous) - interval '5 minutes', upper(previous) + interval '5 minutes', '[]'),
           tstzrange(upper(previous) - interval '5 minutes', 'infinity'::timestamptz)
      from month_range
  ),
  user_key (key) as (
    select key
      from wh_user_dimension
     where user_id = 'u_____user1'
  )
  insert into wh_auth_token_accumulating_fact (
              auth_token_id,                                user_key,
              auth_token_issued_date_key,                   auth_token_issued_time_key,                    auth_token_issued_time,
              auth_token_deleted_date_key,                  auth_token_deleted_time_key,                   auth_token_deleted_time,
              auth_token_approximate_last_access_date_key,  auth_token_approximate_last_access_time_key,   auth_token_approximate_last_access_time,
              auth_token_approximate_active_time_range,
              auth_token_valid_time_range,
              auth_token_count
  )
      select 'at____atok1',                                 user_key.key,
             wh_date_key(lower(range.valid)),               wh_time_key(lower(range.valid)),               lower(range.valid),
             coalesce(wh_date_key(upper(range.valid)), -1), coalesce(wh_time_key(upper(range.valid)), -1), upper(range.valid),
             wh_date_key(upper(range.active)),              wh_time_key(upper(range.active)),              upper(range.active),
             range.active,
             range.valid,
             1
        from range, user_key;

  select is(count(*), 1::bigint, 'wh_auth_token_accumulating_fact is not empty') from wh_auth_token_accumulating_fact;
  select is(count(*), 1::bigint, 'wh_user_dimension is not empty')               from wh_user_dimension;
  select results_eq(
            'select * from hcp_billing_monthly_active_users_last_2_months',
            $$
            values (date_trunc('month', now()),                      date_trunc('hour', now()),  1::bigint),
                   (date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), 1::bigint)
            $$);

  -- active_time_range starts on start of month
  select lives_ok('truncate wh_auth_token_accumulating_fact');
  with month_range (previous) as (
    select tstzrange(date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), '[)')
  ),
  range (active, valid) as (
    select tstzrange(lower(previous), lower(previous) + interval '5 minutes', '[]'),
           tstzrange(lower(previous), 'infinity'::timestamptz)
      from month_range
  ),
  user_key (key) as (
    select key
      from wh_user_dimension
     where user_id = 'u_____user1'
  )
  insert into wh_auth_token_accumulating_fact (
              auth_token_id,                                user_key,
              auth_token_issued_date_key,                   auth_token_issued_time_key,                    auth_token_issued_time,
              auth_token_deleted_date_key,                  auth_token_deleted_time_key,                   auth_token_deleted_time,
              auth_token_approximate_last_access_date_key,  auth_token_approximate_last_access_time_key,   auth_token_approximate_last_access_time,
              auth_token_approximate_active_time_range,
              auth_token_valid_time_range,
              auth_token_count
  )
      select 'at____atok1',                                 user_key.key,
             wh_date_key(lower(range.valid)),               wh_time_key(lower(range.valid)),               lower(range.valid),
             coalesce(wh_date_key(upper(range.valid)), -1), coalesce(wh_time_key(upper(range.valid)), -1), upper(range.valid),
             wh_date_key(upper(range.active)),              wh_time_key(upper(range.active)),              upper(range.active),
             range.active,
             range.valid,
             1
        from range, user_key;

  select is(count(*), 1::bigint, 'wh_auth_token_accumulating_fact is not empty') from wh_auth_token_accumulating_fact;
  select is(count(*), 1::bigint, 'wh_user_dimension is not empty')               from wh_user_dimension;
  select results_eq(
            'select * from hcp_billing_monthly_active_users_last_2_months',
            $$
            values (date_trunc('month', now()),                      date_trunc('hour', now()),  0::bigint),
                   (date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), 1::bigint)
            $$);

  -- active_time_range ends on end of month
  select lives_ok('truncate wh_auth_token_accumulating_fact');
  with month_range (previous) as (
    select tstzrange(date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), '[)')
  ),
  range (active, valid) as (
    -- the resolution on a timestamptz is 1 microsecond, so subtracting one microsecond from the upper bound of
    -- the month range puts us as close to the "end of month" as possible, wthout going over.
    -- https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-DATETIME
    select tstzrange(lower(previous) + interval '5 minutes', upper(previous) - interval '1 microsecond', '[]'),
           tstzrange(lower(previous) + interval '5 minutes', 'infinity'::timestamptz)
      from month_range
  ),
  user_key (key) as (
    select key
      from wh_user_dimension
     where user_id = 'u_____user1'
  )
  insert into wh_auth_token_accumulating_fact (
              auth_token_id,                                user_key,
              auth_token_issued_date_key,                   auth_token_issued_time_key,                    auth_token_issued_time,
              auth_token_deleted_date_key,                  auth_token_deleted_time_key,                   auth_token_deleted_time,
              auth_token_approximate_last_access_date_key,  auth_token_approximate_last_access_time_key,   auth_token_approximate_last_access_time,
              auth_token_approximate_active_time_range,
              auth_token_valid_time_range,
              auth_token_count
  )
      select 'at____atok1',                                 user_key.key,
             wh_date_key(lower(range.valid)),               wh_time_key(lower(range.valid)),               lower(range.valid),
             coalesce(wh_date_key(upper(range.valid)), -1), coalesce(wh_time_key(upper(range.valid)), -1), upper(range.valid),
             wh_date_key(upper(range.active)),              wh_time_key(upper(range.active)),              upper(range.active),
             range.active,
             range.valid,
             1
        from range, user_key;

  select is(count(*), 1::bigint, 'wh_auth_token_accumulating_fact is not empty') from wh_auth_token_accumulating_fact;
  select is(count(*), 1::bigint, 'wh_user_dimension is not empty')               from wh_user_dimension;
  select results_eq(
            'select * from hcp_billing_monthly_active_users_last_2_months',
            $$
            values (date_trunc('month', now()),                      date_trunc('hour', now()),  0::bigint),
                   (date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), 1::bigint)
            $$);

  -- active_time_range starts on end of month
  select lives_ok('truncate wh_auth_token_accumulating_fact');
  with month_range (previous) as (
    select tstzrange(date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), '[)')
  ),
  range (active, valid) as (
    -- the resolution on a timestamptz is 1 microsecond, so subtracting one microsecond from the upper bound of
    -- the month range puts us as close to the "end of month" as possible, wthout going over.
    -- https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-DATETIME
    select tstzrange(upper(previous) - interval '1 microsecond', upper(previous) + '5 minutes', '[]'),
           tstzrange(upper(previous) - interval '1 microsecond', 'infinity'::timestamptz)
      from month_range
  ),
  user_key (key) as (
    select key
      from wh_user_dimension
     where user_id = 'u_____user1'
  )
  insert into wh_auth_token_accumulating_fact (
              auth_token_id,                                user_key,
              auth_token_issued_date_key,                   auth_token_issued_time_key,                    auth_token_issued_time,
              auth_token_deleted_date_key,                  auth_token_deleted_time_key,                   auth_token_deleted_time,
              auth_token_approximate_last_access_date_key,  auth_token_approximate_last_access_time_key,   auth_token_approximate_last_access_time,
              auth_token_approximate_active_time_range,
              auth_token_valid_time_range,
              auth_token_count
  )
      select 'at____atok1',                                 user_key.key,
             wh_date_key(lower(range.valid)),               wh_time_key(lower(range.valid)),               lower(range.valid),
             coalesce(wh_date_key(upper(range.valid)), -1), coalesce(wh_time_key(upper(range.valid)), -1), upper(range.valid),
             wh_date_key(upper(range.active)),              wh_time_key(upper(range.active)),              upper(range.active),
             range.active,
             range.valid,
             1
        from range, user_key;

  select is(count(*), 1::bigint, 'wh_auth_token_accumulating_fact is not empty') from wh_auth_token_accumulating_fact;
  select is(count(*), 1::bigint, 'wh_user_dimension is not empty')               from wh_user_dimension;
  select results_eq(
            'select * from hcp_billing_monthly_active_users_last_2_months',
            $$
            values (date_trunc('month', now()),                      date_trunc('hour', now()),  1::bigint),
                   (date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), 1::bigint)
            $$);

  -- active_time_range ends on start of month
  select lives_ok('truncate wh_auth_token_accumulating_fact');
  with month_range (previous) as (
    select tstzrange(date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), '[)')
  ),
  range (active, valid) as (
    select tstzrange(upper(previous) - interval '5 minutes', upper(previous), '[]'),
           tstzrange(upper(previous) - interval '5 minutes', 'infinity'::timestamptz)
      from month_range
  ),
  user_key (key) as (
    select key
      from wh_user_dimension
     where user_id = 'u_____user1'
  )
  insert into wh_auth_token_accumulating_fact (
              auth_token_id,                                user_key,
              auth_token_issued_date_key,                   auth_token_issued_time_key,                    auth_token_issued_time,
              auth_token_deleted_date_key,                  auth_token_deleted_time_key,                   auth_token_deleted_time,
              auth_token_approximate_last_access_date_key,  auth_token_approximate_last_access_time_key,   auth_token_approximate_last_access_time,
              auth_token_approximate_active_time_range,
              auth_token_valid_time_range,
              auth_token_count
  )
      select 'at____atok1',                                 user_key.key,
             wh_date_key(lower(range.valid)),               wh_time_key(lower(range.valid)),               lower(range.valid),
             coalesce(wh_date_key(upper(range.valid)), -1), coalesce(wh_time_key(upper(range.valid)), -1), upper(range.valid),
             wh_date_key(upper(range.active)),              wh_time_key(upper(range.active)),              upper(range.active),
             range.active,
             range.valid,
             1
        from range, user_key;

  select is(count(*), 1::bigint, 'wh_auth_token_accumulating_fact is not empty') from wh_auth_token_accumulating_fact;
  select is(count(*), 1::bigint, 'wh_user_dimension is not empty')               from wh_user_dimension;
  select results_eq(
            'select * from hcp_billing_monthly_active_users_last_2_months',
            $$
            values (date_trunc('month', now()),                      date_trunc('hour', now()),  1::bigint),
                   (date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), 1::bigint)
            $$);

  -- multiple tokens for a user within month count as single user
  select lives_ok('truncate wh_auth_token_accumulating_fact');
  with token (public_id, active) as (
    select *
      from (values
           ('at____atok1', tstzrange(date_trunc('month', now() - interval '1 month'),
                                     date_trunc('month', now() - interval '1 month') + interval '5 minutes')),
           ('at____atok2', tstzrange(date_trunc('month', now() - interval '1 month') + interval '10 minutes',
                                     date_trunc('month', now() - interval '1 month') + interval '15 minutes'))
           ) as t (public_id, active)
  ),
  user_key (key) as (
    select key
      from wh_user_dimension
     where user_id = 'u_____user1'
  )
  insert into wh_auth_token_accumulating_fact (
              auth_token_id,                                 user_key,
              auth_token_issued_date_key,                    auth_token_issued_time_key,                     auth_token_issued_time,
              auth_token_deleted_date_key,                   auth_token_deleted_time_key,                    auth_token_deleted_time,
              auth_token_approximate_last_access_date_key,   auth_token_approximate_last_access_time_key,    auth_token_approximate_last_access_time,
              auth_token_approximate_active_time_range,
              auth_token_valid_time_range,
              auth_token_count
  )
      select token.public_id,                                user_key.key,
             wh_date_key(lower(token.active)),               wh_time_key(lower(token.active)),               lower(token.active),
             coalesce(wh_date_key(upper(token.active)), -1), coalesce(wh_time_key(upper(token.active)), -1), upper(token.active),
             wh_date_key(upper(token.active)),               wh_time_key(upper(token.active)),               upper(token.active),
             token.active,
             token.active,
             1
        from token, user_key;

  select is(count(*), 2::bigint, 'wh_auth_token_accumulating_fact is not empty') from wh_auth_token_accumulating_fact;
  select is(count(*), 1::bigint, 'wh_user_dimension is not empty')               from wh_user_dimension;
  select results_eq(
            'select * from hcp_billing_monthly_active_users_last_2_months',
            $$
            values (date_trunc('month', now()),                      date_trunc('hour', now()),  0::bigint),
                   (date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), 1::bigint)
            $$);

  -- multiple tokens for multiple users should get counted correctly
  -- Create a user dimension for corresponding auth token's user.
  insert into wh_user_dimension (
    user_id,                 user_name,                user_description,
    auth_account_id,         auth_account_type,        auth_account_name,             auth_account_description,
    auth_method_id,          auth_method_type,         auth_method_name,              auth_method_description,
    user_organization_id,    user_organization_name,   user_organization_description,
    current_row_indicator,
    row_effective_time,      row_expiration_time,
    auth_method_external_id, auth_account_external_id, auth_account_full_name,        auth_account_email
  ) values (
    'u_____user2',           'None',                   'None',
    'a______acc2',           'None',                   'None',                        'None',
    'am______am1',           'None',                   'None',                        'None',
    'o______org1',           'None',                   'None',
    'current',
    now(),                   'infinity'::timestamptz,
    'None',                  'None',                   'None',                        'None'
  ),(
    'u_____user3',           'None',                   'None',
    'a______acc3',           'None',                   'None',                        'None',
    'am______am1',           'None',                   'None',                        'None',
    'o______org1',           'None',                   'None',
    'current',
    now(),                   'infinity'::timestamptz,
    'None',                  'None',                   'None',                        'None'
  );
  select lives_ok('truncate wh_auth_token_accumulating_fact');
  with token (user_id, public_id, active) as (
    select *
      from (values
           ('u_____user1', 'at___u1tok1', tstzrange(date_trunc('month', now() - interval '1 month'),
                                                    date_trunc('month', now() - interval '1 month') + interval '5 minutes')),
           ('u_____user1', 'at___u1tok2', tstzrange(date_trunc('month', now() - interval '1 month') + interval '10 minutes',
                                                    date_trunc('month', now() - interval '1 month') + interval '15 minutes')),
           ('u_____user2', 'at___u2tok1', tstzrange(date_trunc('month', now() - interval '1 month'),
                                                    date_trunc('month', now() - interval '1 month') + interval '5 minutes')),
           ('u_____user2', 'at___u2tok2', tstzrange(date_trunc('month', now() - interval '1 month') + interval '10 minutes',
                                                    date_trunc('month', now() - interval '1 month') + interval '15 minutes')),
           ('u_____user3', 'at___u3tok1', tstzrange(date_trunc('month', now() - interval '1 month'),
                                                    date_trunc('month', now() - interval '1 month') + interval '5 minutes')),
           ('u_____user3', 'at___u3tok2', tstzrange(date_trunc('month', now() - interval '1 month') + interval '10 minutes',
                                                    date_trunc('month', now() - interval '1 month') + interval '15 minutes')),
           ('u_____user3', 'at___u3tok3', tstzrange(date_trunc('month', now() - interval '1 month') + interval '10 minutes',
                                                    date_trunc('month', now() - interval '1 month') + interval '15 minutes'))
           ) as t (user_id, public_id, active)
  ),
  token_key (user_key, public_id, active) as (
    select whud.key, token.public_id, token.active
      from wh_user_dimension as whud
      join token
        on whud.user_id = token.user_id
  )
  insert into wh_auth_token_accumulating_fact (
              auth_token_id,                                 user_key,
              auth_token_issued_date_key,                    auth_token_issued_time_key,                     auth_token_issued_time,
              auth_token_deleted_date_key,                   auth_token_deleted_time_key,                    auth_token_deleted_time,
              auth_token_approximate_last_access_date_key,   auth_token_approximate_last_access_time_key,    auth_token_approximate_last_access_time,
              auth_token_approximate_active_time_range,
              auth_token_valid_time_range,
              auth_token_count
  )
      select token_key.public_id,                                token_key.user_key,
             wh_date_key(lower(token_key.active)),               wh_time_key(lower(token_key.active)),               lower(token_key.active),
             coalesce(wh_date_key(upper(token_key.active)), -1), coalesce(wh_time_key(upper(token_key.active)), -1), upper(token_key.active),
             wh_date_key(upper(token_key.active)),               wh_time_key(upper(token_key.active)),               upper(token_key.active),
             token_key.active,
             token_key.active,
             1
        from token_key;

  select is(count(*), 7::bigint, 'wh_auth_token_accumulating_fact is not empty') from wh_auth_token_accumulating_fact;
  select is(count(*), 3::bigint, 'wh_user_dimension is not empty')               from wh_user_dimension;
  select results_eq(
            'select * from hcp_billing_monthly_active_users_last_2_months',
            $$
            values (date_trunc('month', now()),                      date_trunc('hour', now()),  0::bigint),
                   (date_trunc('month', now() - interval '1 month'), date_trunc('month', now()), 3::bigint)
            $$);

  select * from finish();
rollback;
