import {OrganizationFixture} from 'sentry-fixture/organization';

import {MetricHistoryFixture} from 'getsentry-test/fixtures/metricHistory';
import {PlanDetailsLookupFixture} from 'getsentry-test/fixtures/planDetailsLookup';
import {SubscriptionFixture} from 'getsentry-test/fixtures/subscription';

import {DataCategory} from 'sentry/types/core';

import {
  getPlanCategoryName,
  getReservedBudgetDisplayName,
  hasCategoryFeature,
  listDisplayNames,
  sortCategories,
  sortCategoriesWithKeys,
} from 'getsentry/utils/dataCategory';

describe('hasCategoryFeature', function () {
  const organization = OrganizationFixture();
  const subscription = SubscriptionFixture({organization, plan: 'mm2_b_100k'});

  it('returns am1 plan categories', function () {
    const sub = SubscriptionFixture({organization, plan: 'am1_team'});
    expect(hasCategoryFeature(DataCategory.ERRORS, sub, organization)).toBe(true);
    expect(hasCategoryFeature(DataCategory.TRANSACTIONS, sub, organization)).toBe(true);
    expect(hasCategoryFeature(DataCategory.ATTACHMENTS, sub, organization)).toBe(true);
    expect(hasCategoryFeature(DataCategory.REPLAYS, sub, organization)).toBe(true);
    expect(hasCategoryFeature(DataCategory.MONITOR_SEATS, sub, organization)).toBe(true);
  });

  it('returns mm2 plan categories', function () {
    expect(hasCategoryFeature(DataCategory.ERRORS, subscription, organization)).toBe(
      true
    );
    expect(
      hasCategoryFeature(DataCategory.TRANSACTIONS, subscription, organization)
    ).toBe(false);
    expect(hasCategoryFeature(DataCategory.ATTACHMENTS, subscription, organization)).toBe(
      false
    );
    expect(hasCategoryFeature(DataCategory.REPLAYS, subscription, organization)).toBe(
      false
    );
    expect(
      hasCategoryFeature(DataCategory.MONITOR_SEATS, subscription, organization)
    ).toBe(false);
  });

  it('returns mm1 plan categories', function () {
    const sub = SubscriptionFixture({organization, plan: 's1'});
    expect(hasCategoryFeature(DataCategory.ERRORS, sub, organization)).toBe(true);
    expect(hasCategoryFeature(DataCategory.TRANSACTIONS, sub, organization)).toBe(false);
    expect(hasCategoryFeature(DataCategory.ATTACHMENTS, sub, organization)).toBe(false);
    expect(hasCategoryFeature(DataCategory.REPLAYS, subscription, organization)).toBe(
      false
    );
    expect(
      hasCategoryFeature(DataCategory.MONITOR_SEATS, subscription, organization)
    ).toBe(false);
  });

  it('returns org has transactions feature', function () {
    const org = {...organization, features: ['performance-view']};
    expect(hasCategoryFeature(DataCategory.ERRORS, subscription, org)).toBe(true);
    expect(hasCategoryFeature(DataCategory.TRANSACTIONS, subscription, org)).toBe(true);
    expect(hasCategoryFeature(DataCategory.ATTACHMENTS, subscription, org)).toBe(false);
    expect(hasCategoryFeature(DataCategory.REPLAYS, subscription, org)).toBe(false);
    expect(hasCategoryFeature(DataCategory.MONITOR_SEATS, subscription, org)).toBe(false);
  });

  it('returns org has attachments feature', function () {
    const org = {...organization, features: ['event-attachments']};
    expect(hasCategoryFeature(DataCategory.ERRORS, subscription, org)).toBe(true);
    expect(hasCategoryFeature(DataCategory.TRANSACTIONS, subscription, org)).toBe(false);
    expect(hasCategoryFeature(DataCategory.ATTACHMENTS, subscription, org)).toBe(true);
    expect(hasCategoryFeature(DataCategory.REPLAYS, subscription, org)).toBe(false);
    expect(hasCategoryFeature(DataCategory.MONITOR_SEATS, subscription, org)).toBe(false);
  });

  it('returns org has replays feature', function () {
    const org = {...organization, features: ['session-replay']};
    expect(hasCategoryFeature(DataCategory.ERRORS, subscription, org)).toBe(true);
    expect(hasCategoryFeature(DataCategory.TRANSACTIONS, subscription, org)).toBe(false);
    expect(hasCategoryFeature(DataCategory.ATTACHMENTS, subscription, org)).toBe(false);
    expect(hasCategoryFeature(DataCategory.REPLAYS, subscription, org)).toBe(true);
    expect(hasCategoryFeature(DataCategory.MONITOR_SEATS, subscription, org)).toBe(false);
  });

  it('returns org has transactions and attachments features', function () {
    const org = {...organization, features: ['performance-view', 'event-attachments']};
    expect(hasCategoryFeature(DataCategory.ERRORS, subscription, org)).toBe(true);
    expect(hasCategoryFeature(DataCategory.TRANSACTIONS, subscription, org)).toBe(true);
    expect(hasCategoryFeature(DataCategory.ATTACHMENTS, subscription, org)).toBe(true);
    expect(hasCategoryFeature(DataCategory.REPLAYS, subscription, org)).toBe(false);
    expect(hasCategoryFeature(DataCategory.REPLAYS, subscription, org)).toBe(false);
  });

  it('returns org does not have unknown feature', function () {
    const org = {...organization, features: []};
    expect(hasCategoryFeature('unknown', subscription, org)).toBe(false);
  });

  it('returns sorted categories', function () {
    const sub = SubscriptionFixture({organization, plan: 'am1_team'});
    expect(sortCategories(sub.categories)).toStrictEqual([
      MetricHistoryFixture({
        category: DataCategory.ERRORS,
        reserved: 50_000,
        prepaid: 50_000,
        order: 1,
      }),
      MetricHistoryFixture({
        category: DataCategory.TRANSACTIONS,
        reserved: 100_000,
        prepaid: 100_000,
        order: 2,
      }),
      MetricHistoryFixture({
        category: DataCategory.REPLAYS,
        reserved: 500,
        prepaid: 500,
        order: 4,
      }),
      MetricHistoryFixture({
        category: DataCategory.MONITOR_SEATS,
        reserved: 1,
        prepaid: 1,
        order: 7,
      }),
      MetricHistoryFixture({
        category: DataCategory.UPTIME,
        reserved: 1,
        prepaid: 1,
        order: 8,
      }),
      MetricHistoryFixture({
        category: DataCategory.ATTACHMENTS,
        reserved: 1,
        prepaid: 1,
        order: 9,
      }),
    ]);
  });

  it('returns sorted categories with keys', function () {
    const sub = SubscriptionFixture({organization, plan: 'am1_team'});
    expect(sortCategoriesWithKeys(sub.categories)).toStrictEqual([
      [
        'errors',
        MetricHistoryFixture({
          category: DataCategory.ERRORS,
          reserved: 50_000,
          prepaid: 50_000,
          order: 1,
        }),
      ],
      [
        'transactions',
        MetricHistoryFixture({
          category: DataCategory.TRANSACTIONS,
          reserved: 100_000,
          prepaid: 100_000,
          order: 2,
        }),
      ],
      [
        'replays',
        MetricHistoryFixture({
          category: DataCategory.REPLAYS,
          reserved: 500,
          prepaid: 500,
          order: 4,
        }),
      ],
      [
        'monitorSeats',
        MetricHistoryFixture({
          category: DataCategory.MONITOR_SEATS,
          reserved: 1,
          prepaid: 1,
          order: 7,
        }),
      ],
      [
        'uptime',
        MetricHistoryFixture({
          category: DataCategory.UPTIME,
          reserved: 1,
          prepaid: 1,
          order: 8,
        }),
      ],
      [
        'attachments',
        MetricHistoryFixture({
          category: DataCategory.ATTACHMENTS,
          reserved: 1,
          prepaid: 1,
          order: 9,
        }),
      ],
    ]);
  });
});

describe('getPlanCategoryName', function () {
  const plan = PlanDetailsLookupFixture('am3_team');

  it('should capitalize category', function () {
    expect(getPlanCategoryName({plan, category: 'transactions'})).toBe('Transactions');
    expect(getPlanCategoryName({plan, category: 'errors'})).toBe('Errors');
    expect(getPlanCategoryName({plan, category: 'replays'})).toBe('Replays');
    expect(getPlanCategoryName({plan, category: 'spans'})).toBe('Spans');
    expect(getPlanCategoryName({plan, category: 'profiles'})).toBe('Profiles');
    expect(getPlanCategoryName({plan, category: 'monitorSeats'})).toBe('Cron monitors');
  });

  it('should display spans as accepted spans for DS', function () {
    expect(
      getPlanCategoryName({plan, category: 'spans', hadCustomDynamicSampling: true})
    ).toBe('Accepted spans');
  });
});

describe('getReservedBudgetDisplayName', function () {
  const am1Plan = PlanDetailsLookupFixture('am1_team');
  const am2Plan = PlanDetailsLookupFixture('am2_business');
  const am3Plan = PlanDetailsLookupFixture('am3_business');
  const am3DsPlan = PlanDetailsLookupFixture('am3_business_ent_ds_auf');

  it('should oxfordize categories alphabetically for am1', function () {
    expect(
      getReservedBudgetDisplayName({
        plan: am1Plan,
        categories: am1Plan?.categories ?? [],
        hadCustomDynamicSampling: false,
      })
    ).toBe(
      'attachments, cron monitors, errors, replays, transactions, and uptime monitors'
    );
  });

  it('should oxfordize categories alphabetically for am2', function () {
    expect(
      getReservedBudgetDisplayName({
        plan: am2Plan,
        categories: am2Plan?.categories ?? [],
        hadCustomDynamicSampling: false,
      })
    ).toBe(
      'attachments, cron monitors, errors, performance units, profile hours, replays, and uptime monitors'
    );
  });

  it('should oxfordize categories alphabetically for am3', function () {
    expect(
      getReservedBudgetDisplayName({
        plan: am3Plan,
        categories: am3Plan?.categories ?? [],
        hadCustomDynamicSampling: false,
      })
    ).toBe(
      'attachments, cron monitors, errors, profile hours, replays, spans, and uptime monitors'
    );
  });

  it('should use accepted spans for DS', function () {
    expect(
      getReservedBudgetDisplayName({
        plan: am3DsPlan,
        categories: ['spans', 'spansIndexed'],
        hadCustomDynamicSampling: true,
      })
    ).toBe('accepted spans and stored spans');

    expect(
      getReservedBudgetDisplayName({
        plan: am3DsPlan,
        categories: ['spans', 'spansIndexed'],
        hadCustomDynamicSampling: false,
      })
    ).toBe('spans and stored spans');
  });

  it('should title case categories only', function () {
    expect(
      getReservedBudgetDisplayName({
        plan: am3Plan,
        categories: am3Plan?.categories ?? [],
        shouldTitleCase: true,
      })
    ).toBe(
      'Attachments, Cron Monitors, Errors, Profile Hours, Replays, Spans, and Uptime Monitors'
    );
  });
});

describe('listDisplayNames', function () {
  const plan = PlanDetailsLookupFixture('am3_business_ent_ds_auf');

  it('should list categories in order given', function () {
    expect(
      listDisplayNames({
        plan: plan!,
        categories: [
          'spans',
          'transactions',
          'errors',
          'replays',
          'monitorSeats',
          'attachments',
        ],
      })
    ).toBe('spans, transactions, errors, replays, cron monitors, and attachments');
  });

  it('should hide stored spans for no DS', function () {
    expect(
      listDisplayNames({
        plan: plan!,
        categories: plan!.checkoutCategories,
        hadCustomDynamicSampling: false,
      })
    ).toBe(
      'errors, replays, attachments, cron monitors, spans, profile hours, and uptime monitors'
    );
  });

  it('should include stored spans and use accepted spans for DS', function () {
    expect(
      listDisplayNames({
        plan: plan!,
        categories: plan!.checkoutCategories,
        hadCustomDynamicSampling: true,
      })
    ).toBe(
      'errors, replays, attachments, cron monitors, accepted spans, profile hours, uptime monitors, and stored spans'
    );
  });
});
