import { getRetentionConfig, getArchiveCronExpression } from '../../src/libs/archive/config';

jest.mock('@blocklet/sdk/lib/config', () => ({
  __esModule: true,
  default: {
    env: {
      preferences: {},
    },
  },
}));

describe('archive/config', () => {
  describe('getArchiveCronExpression', () => {
    it('should generate weekly cron expression for hour 0', () => {
      expect(getArchiveCronExpression(0)).toBe('0 0 0 * * 3');
    });

    it('should generate weekly cron expression for hour 2', () => {
      expect(getArchiveCronExpression(2)).toBe('0 0 2 * * 3');
    });

    it('should generate weekly cron expression for hour 23', () => {
      expect(getArchiveCronExpression(23)).toBe('0 0 23 * * 3');
    });

    it('should generate weekly cron expression for hour 12', () => {
      expect(getArchiveCronExpression(12)).toBe('0 0 12 * * 3');
    });
  });

  describe('getRetentionConfig', () => {
    beforeEach(() => {
      jest.resetModules();
    });

    it('should return default config when no preferences set', () => {
      const config = getRetentionConfig();

      expect(config.enabled).toBe(false);
      expect(config.defaults.retentionDays).toBe(365);
      expect(config.defaults.batchSize).toBe(500);
      expect(config.schedule.enabled).toBe(true);
      expect(config.schedule.hour).toBe(2);
      expect(config.storage.minFreeDiskMB).toBe(1000);
      expect(config.storage.maxArchiveFiles).toBe(10);
    });

    it('should have tables configured', () => {
      const config = getRetentionConfig();

      expect(config.tables).toBeDefined();
      expect(Object.keys(config.tables).length).toBeGreaterThan(0);
    });

    it('should include expected table policies', () => {
      const config = getRetentionConfig();
      const expectedTables = [
        'meter_events',
        'credit_transactions',
        'events',
        'webhook_attempts',
        'jobs',
        'payment_intents',
        'invoices',
        'refunds',
        'payouts',
        'subscriptions',
        'credit_grants',
        'products',
        'prices',
        'coupons',
        'customers',
      ];

      for (const table of expectedTables) {
        expect(config.tables[table]).toBeDefined();
      }
    });

    it('should have retention days set for each enabled table', () => {
      const config = getRetentionConfig();

      for (const policy of Object.values(config.tables)) {
        if (policy.enabled) {
          expect(policy.retentionDays).toBeGreaterThan(0);
        }
      }
    });

    it('should have customers table disabled', () => {
      const config = getRetentionConfig();
      expect(config.tables.customers!.enabled).toBe(false);
    });

    it('should have different retention periods for different table types', () => {
      const config = getRetentionConfig();

      expect(config.tables.meter_events!.retentionDays).toBe(90);
      expect(config.tables.credit_transactions!.retentionDays).toBe(90);

      expect(config.tables.payment_intents!.retentionDays).toBe(730);
      expect(config.tables.invoices!.retentionDays).toBe(730);

      expect(config.tables.products!.enabled).toBe(false);
      expect(config.tables.prices!.enabled).toBe(false);
    });

    it('should have archivable statuses defined for transaction tables', () => {
      const config = getRetentionConfig();

      expect(config.tables.meter_events!.archivableStatuses).toContain('completed');
      expect(config.tables.payment_intents!.archivableStatuses).toContain('succeeded');
      expect(config.tables.invoices!.archivableStatuses).toContain('paid');
    });

    it('should have exclude conditions for financial tables', () => {
      const config = getRetentionConfig();

      expect(config.tables.payment_intents!.excludeConditions?.statuses).toContain('processing');
      expect(config.tables.invoices!.excludeConditions?.statuses).toContain('draft');
    });

    it('should have hasActiveSubscription exclusion for relevant tables', () => {
      const config = getRetentionConfig();

      expect(config.tables.meter_events!.excludeConditions?.hasActiveSubscription).toBe(true);
      expect(config.tables.credit_transactions!.excludeConditions?.hasActiveSubscription).toBe(true);
      expect(config.tables.payment_intents!.excludeConditions?.hasActiveSubscription).toBe(true);
    });

    it('should generate correct cron expression in schedule', () => {
      const config = getRetentionConfig();
      expect(config.schedule.cron).toBe('0 0 2 * * 3');
    });
  });

  describe('getRetentionConfig with custom preferences', () => {
    it('should apply custom preferences when set', async () => {
      jest.resetModules();
      jest.doMock('@blocklet/sdk/lib/config', () => ({
        __esModule: true,
        default: {
          env: {
            preferences: {
              retentionEnabled: true,
              scheduleEnabled: false,
              scheduleHour: 5,
              batchSize: 300,
              minFreeDiskMB: 1000,
            },
          },
        },
      }));

      const { getRetentionConfig: getConfigWithPrefs } = await import('../../src/libs/archive/config');
      const config = getConfigWithPrefs();

      expect(config.enabled).toBe(true);
      expect(config.schedule.enabled).toBe(false);
      expect(config.schedule.hour).toBe(5);
      expect(config.defaults.batchSize).toBe(300);
      expect(config.storage.minFreeDiskMB).toBe(1000);
    });

    it('should fall back to defaults when batchSize exceeds max', async () => {
      jest.resetModules();
      jest.doMock('@blocklet/sdk/lib/config', () => ({
        __esModule: true,
        default: {
          env: {
            preferences: {
              batchSize: 1000,
            },
          },
        },
      }));

      const { getRetentionConfig: getConfigWithPrefs } = await import('../../src/libs/archive/config');
      const config = getConfigWithPrefs();

      // batchSize: 1000 exceeds max(500) → validation fails → fall back to default 500
      expect(config.defaults.batchSize).toBe(500);
    });
  });
});
