/**
 * @ai-summary Unit tests for BackupClassificationService
 * @ai-context Tests pure timestamp-based classification functions
 */

import {
  classifyBackup,
  calculateExpiration,
  isFirstBackupOfDay,
  isSunday,
  isFirstDayOfMonth,
  classifyAndCalculateExpiration,
} from '../../domain/backup-classification.service';
import { TIERED_RETENTION } from '../../domain/backup.types';

describe('BackupClassificationService', () => {
  describe('classifyBackup', () => {
    it('should classify regular hourly backup (non-midnight)', () => {
      // Tuesday, January 7, 2026 at 14:30 UTC
      const timestamp = new Date('2026-01-07T14:30:00.000Z');
      const categories = classifyBackup(timestamp);

      expect(categories).toEqual(['hourly']);
    });

    it('should classify midnight backup as hourly + daily', () => {
      // Wednesday, January 8, 2026 at 00:00 UTC
      const timestamp = new Date('2026-01-08T00:00:00.000Z');
      const categories = classifyBackup(timestamp);

      expect(categories).toEqual(['hourly', 'daily']);
    });

    it('should classify Sunday midnight backup as hourly + daily + weekly', () => {
      // Sunday, January 4, 2026 at 00:00 UTC
      const timestamp = new Date('2026-01-04T00:00:00.000Z');
      const categories = classifyBackup(timestamp);

      expect(categories).toEqual(['hourly', 'daily', 'weekly']);
    });

    it('should classify 1st of month midnight backup as hourly + daily + monthly', () => {
      // Thursday, January 1, 2026 at 00:00 UTC (not Sunday)
      const timestamp = new Date('2026-01-01T00:00:00.000Z');
      const categories = classifyBackup(timestamp);

      expect(categories).toEqual(['hourly', 'daily', 'monthly']);
    });

    it('should classify Sunday 1st of month midnight as all categories', () => {
      // Sunday, February 1, 2026 at 00:00 UTC
      const timestamp = new Date('2026-02-01T00:00:00.000Z');
      const categories = classifyBackup(timestamp);

      expect(categories).toEqual(['hourly', 'daily', 'weekly', 'monthly']);
    });

    it('should not classify non-midnight on 1st as monthly', () => {
      // Thursday, January 1, 2026 at 10:00 UTC
      const timestamp = new Date('2026-01-01T10:00:00.000Z');
      const categories = classifyBackup(timestamp);

      expect(categories).toEqual(['hourly']);
    });

    it('should not classify non-midnight on Sunday as weekly', () => {
      // Sunday, January 4, 2026 at 15:00 UTC
      const timestamp = new Date('2026-01-04T15:00:00.000Z');
      const categories = classifyBackup(timestamp);

      expect(categories).toEqual(['hourly']);
    });
  });

  describe('calculateExpiration', () => {
    const baseTimestamp = new Date('2026-01-05T00:00:00.000Z');

    it('should calculate 8 hours for hourly-only backup', () => {
      const expiresAt = calculateExpiration(['hourly'], baseTimestamp);
      const expectedDate = new Date('2026-01-05T08:00:00.000Z');

      expect(expiresAt).toEqual(expectedDate);
    });

    it('should calculate 7 days for daily backup', () => {
      const expiresAt = calculateExpiration(['hourly', 'daily'], baseTimestamp);
      const expectedDate = new Date('2026-01-12T00:00:00.000Z');

      expect(expiresAt).toEqual(expectedDate);
    });

    it('should calculate 4 weeks for weekly backup', () => {
      const expiresAt = calculateExpiration(['hourly', 'daily', 'weekly'], baseTimestamp);
      const expectedDate = new Date('2026-02-02T00:00:00.000Z');

      expect(expiresAt).toEqual(expectedDate);
    });

    it('should calculate 12 months for monthly backup', () => {
      const expiresAt = calculateExpiration(
        ['hourly', 'daily', 'weekly', 'monthly'],
        baseTimestamp
      );
      const expectedDate = new Date('2027-01-05T00:00:00.000Z');

      expect(expiresAt).toEqual(expectedDate);
    });

    it('should use longest retention when monthly is present (even without weekly)', () => {
      const expiresAt = calculateExpiration(['hourly', 'daily', 'monthly'], baseTimestamp);
      const expectedDate = new Date('2027-01-05T00:00:00.000Z');

      expect(expiresAt).toEqual(expectedDate);
    });
  });

  describe('isFirstBackupOfDay', () => {
    it('should return true for midnight UTC', () => {
      const timestamp = new Date('2026-01-05T00:00:00.000Z');
      expect(isFirstBackupOfDay(timestamp)).toBe(true);
    });

    it('should return false for non-midnight', () => {
      const timestamp = new Date('2026-01-05T01:00:00.000Z');
      expect(isFirstBackupOfDay(timestamp)).toBe(false);
    });

    it('should return true for midnight with minutes/seconds', () => {
      // 00:30:45 is still hour 0
      const timestamp = new Date('2026-01-05T00:30:45.000Z');
      expect(isFirstBackupOfDay(timestamp)).toBe(true);
    });
  });

  describe('isSunday', () => {
    it('should return true for Sunday', () => {
      // January 4, 2026 is a Sunday
      const timestamp = new Date('2026-01-04T12:00:00.000Z');
      expect(isSunday(timestamp)).toBe(true);
    });

    it('should return false for non-Sunday', () => {
      // January 5, 2026 is a Monday
      const timestamp = new Date('2026-01-05T12:00:00.000Z');
      expect(isSunday(timestamp)).toBe(false);
    });
  });

  describe('isFirstDayOfMonth', () => {
    it('should return true for 1st of month', () => {
      const timestamp = new Date('2026-01-01T12:00:00.000Z');
      expect(isFirstDayOfMonth(timestamp)).toBe(true);
    });

    it('should return false for non-1st', () => {
      const timestamp = new Date('2026-01-15T12:00:00.000Z');
      expect(isFirstDayOfMonth(timestamp)).toBe(false);
    });
  });

  describe('classifyAndCalculateExpiration', () => {
    it('should return both categories and expiresAt', () => {
      // Sunday, February 1, 2026 at 00:00 UTC - all categories
      const timestamp = new Date('2026-02-01T00:00:00.000Z');
      const result = classifyAndCalculateExpiration(timestamp);

      expect(result.categories).toEqual(['hourly', 'daily', 'weekly', 'monthly']);
      expect(result.expiresAt).toEqual(new Date('2027-02-01T00:00:00.000Z'));
    });

    it('should work for hourly-only backup', () => {
      const timestamp = new Date('2026-01-07T14:30:00.000Z');
      const result = classifyAndCalculateExpiration(timestamp);

      expect(result.categories).toEqual(['hourly']);
      expect(result.expiresAt).toEqual(new Date('2026-01-07T22:30:00.000Z'));
    });
  });

  describe('TIERED_RETENTION constants', () => {
    it('should have correct retention values', () => {
      expect(TIERED_RETENTION.hourly).toBe(8);
      expect(TIERED_RETENTION.daily).toBe(7);
      expect(TIERED_RETENTION.weekly).toBe(4);
      expect(TIERED_RETENTION.monthly).toBe(12);
    });
  });
});
