/**
 * Comprehensive Unit Tests for Moderation Lock Helpers
 *
 * These tests ensure proper lock management and concurrency control
 */

import { describe, it, expect, beforeEach, vi } from 'vitest';
import {
  canClaimSubmission,
  isActiveLock,
  getLockStatus,
  formatLockExpiry,
  getLockUrgency,
  type LockStatus,
  type LockUrgency,
} from '@/lib/moderation/lockHelpers';

describe('canClaimSubmission', () => {
  const currentUserId = 'user-123';
  const otherUserId = 'user-456';

  describe('Unclaimed Submissions', () => {
    it('should allow claiming unassigned submission', () => {
      const submission = {
        assigned_to: null,
        locked_until: null,
      };
      expect(canClaimSubmission(submission, currentUserId)).toBe(true);
    });

    it('should allow claiming submission with no lock time', () => {
      const submission = {
        assigned_to: otherUserId,
        locked_until: null,
      };
      expect(canClaimSubmission(submission, currentUserId)).toBe(true);
    });
  });

  describe('Expired Locks', () => {
    it('should allow claiming submission with expired lock', () => {
      const pastDate = new Date(Date.now() - 1000).toISOString();
      const submission = {
        assigned_to: otherUserId,
        locked_until: pastDate,
      };
      expect(canClaimSubmission(submission, currentUserId)).toBe(true);
    });

    it('should allow claiming submission with lock expired 1 minute ago', () => {
      const pastDate = new Date(Date.now() - 60000).toISOString();
      const submission = {
        assigned_to: otherUserId,
        locked_until: pastDate,
      };
      expect(canClaimSubmission(submission, currentUserId)).toBe(true);
    });

    it('should allow claiming submission with lock expired 1 hour ago', () => {
      const pastDate = new Date(Date.now() - 3600000).toISOString();
      const submission = {
        assigned_to: otherUserId,
        locked_until: pastDate,
      };
      expect(canClaimSubmission(submission, currentUserId)).toBe(true);
    });
  });

  describe('Active Locks by Others', () => {
    it('should not allow claiming submission locked by another user', () => {
      const futureDate = new Date(Date.now() + 60000).toISOString();
      const submission = {
        assigned_to: otherUserId,
        locked_until: futureDate,
      };
      expect(canClaimSubmission(submission, currentUserId)).toBe(false);
    });

    it('should not allow claiming submission locked by another user (15 min lock)', () => {
      const futureDate = new Date(Date.now() + 15 * 60000).toISOString();
      const submission = {
        assigned_to: otherUserId,
        locked_until: futureDate,
      };
      expect(canClaimSubmission(submission, currentUserId)).toBe(false);
    });
  });

  describe('Own Locks', () => {
    it('should not allow claiming own locked submission', () => {
      const futureDate = new Date(Date.now() + 60000).toISOString();
      const submission = {
        assigned_to: currentUserId,
        locked_until: futureDate,
      };
      expect(canClaimSubmission(submission, currentUserId)).toBe(false);
    });

    it('should allow claiming own submission if lock expired', () => {
      const pastDate = new Date(Date.now() - 1000).toISOString();
      const submission = {
        assigned_to: currentUserId,
        locked_until: pastDate,
      };
      expect(canClaimSubmission(submission, currentUserId)).toBe(true);
    });
  });

  describe('Edge Cases', () => {
    it('should handle submission assigned but no lock time', () => {
      const submission = {
        assigned_to: currentUserId,
        locked_until: null,
      };
      expect(canClaimSubmission(submission, currentUserId)).toBe(true);
    });

    it('should handle lock time just expired (1ms ago)', () => {
      const pastDate = new Date(Date.now() - 1).toISOString();
      const submission = {
        assigned_to: otherUserId,
        locked_until: pastDate,
      };
      expect(canClaimSubmission(submission, currentUserId)).toBe(true);
    });

    it('should handle lock time about to expire (1ms future)', () => {
      const futureDate = new Date(Date.now() + 1).toISOString();
      const submission = {
        assigned_to: otherUserId,
        locked_until: futureDate,
      };
      expect(canClaimSubmission(submission, currentUserId)).toBe(false);
    });
  });
});

describe('isActiveLock', () => {
  const assignedTo = 'user-123';

  describe('Active Locks', () => {
    it('should return true for active lock', () => {
      const futureDate = new Date(Date.now() + 60000).toISOString();
      expect(isActiveLock(assignedTo, futureDate)).toBe(true);
    });

    it('should return true for lock expiring in 1 second', () => {
      const futureDate = new Date(Date.now() + 1000).toISOString();
      expect(isActiveLock(assignedTo, futureDate)).toBe(true);
    });

    it('should return true for lock expiring in 15 minutes', () => {
      const futureDate = new Date(Date.now() + 15 * 60000).toISOString();
      expect(isActiveLock(assignedTo, futureDate)).toBe(true);
    });
  });

  describe('Inactive Locks', () => {
    it('should return false for expired lock', () => {
      const pastDate = new Date(Date.now() - 1000).toISOString();
      expect(isActiveLock(assignedTo, pastDate)).toBe(false);
    });

    it('should return false when no assignee', () => {
      const futureDate = new Date(Date.now() + 60000).toISOString();
      expect(isActiveLock(null, futureDate)).toBe(false);
    });

    it('should return false when no lock time', () => {
      expect(isActiveLock(assignedTo, null)).toBe(false);
    });

    it('should return false when both null', () => {
      expect(isActiveLock(null, null)).toBe(false);
    });
  });

  describe('Edge Cases', () => {
    it('should return false for lock expired 1ms ago', () => {
      const pastDate = new Date(Date.now() - 1).toISOString();
      expect(isActiveLock(assignedTo, pastDate)).toBe(false);
    });

    it('should return true for lock expiring in 1ms', () => {
      const futureDate = new Date(Date.now() + 1).toISOString();
      expect(isActiveLock(assignedTo, futureDate)).toBe(true);
    });
  });
});

describe('getLockStatus', () => {
  const currentUserId = 'user-123';
  const otherUserId = 'user-456';

  describe('Unlocked Status', () => {
    it('should return unlocked when no assignee', () => {
      const submission = {
        assigned_to: null,
        locked_until: null,
      };
      expect(getLockStatus(submission, currentUserId)).toBe('unlocked');
    });

    it('should return unlocked when no lock time', () => {
      const submission = {
        assigned_to: null,
        locked_until: new Date(Date.now() + 60000).toISOString(),
      };
      expect(getLockStatus(submission, currentUserId)).toBe('unlocked');
    });

    it('should return unlocked when assignee but no lock time', () => {
      const submission = {
        assigned_to: currentUserId,
        locked_until: null,
      };
      expect(getLockStatus(submission, currentUserId)).toBe('unlocked');
    });
  });

  describe('Expired Status', () => {
    it('should return expired for expired lock by current user', () => {
      const pastDate = new Date(Date.now() - 1000).toISOString();
      const submission = {
        assigned_to: currentUserId,
        locked_until: pastDate,
      };
      expect(getLockStatus(submission, currentUserId)).toBe('expired');
    });

    it('should return expired for expired lock by other user', () => {
      const pastDate = new Date(Date.now() - 1000).toISOString();
      const submission = {
        assigned_to: otherUserId,
        locked_until: pastDate,
      };
      expect(getLockStatus(submission, currentUserId)).toBe('expired');
    });
  });

  describe('Locked by Me Status', () => {
    it('should return locked_by_me for active lock by current user', () => {
      const futureDate = new Date(Date.now() + 60000).toISOString();
      const submission = {
        assigned_to: currentUserId,
        locked_until: futureDate,
      };
      expect(getLockStatus(submission, currentUserId)).toBe('locked_by_me');
    });

    it('should return locked_by_me for lock expiring soon', () => {
      const futureDate = new Date(Date.now() + 1000).toISOString();
      const submission = {
        assigned_to: currentUserId,
        locked_until: futureDate,
      };
      expect(getLockStatus(submission, currentUserId)).toBe('locked_by_me');
    });
  });

  describe('Locked by Other Status', () => {
    it('should return locked_by_other for active lock by other user', () => {
      const futureDate = new Date(Date.now() + 60000).toISOString();
      const submission = {
        assigned_to: otherUserId,
        locked_until: futureDate,
      };
      expect(getLockStatus(submission, currentUserId)).toBe('locked_by_other');
    });

    it('should return locked_by_other for lock expiring soon by other user', () => {
      const futureDate = new Date(Date.now() + 1000).toISOString();
      const submission = {
        assigned_to: otherUserId,
        locked_until: futureDate,
      };
      expect(getLockStatus(submission, currentUserId)).toBe('locked_by_other');
    });
  });

  describe('Edge Cases', () => {
    it('should handle lock expiring in 1ms by current user', () => {
      const futureDate = new Date(Date.now() + 1).toISOString();
      const submission = {
        assigned_to: currentUserId,
        locked_until: futureDate,
      };
      expect(getLockStatus(submission, currentUserId)).toBe('locked_by_me');
    });

    it('should handle lock expired 1ms ago', () => {
      const pastDate = new Date(Date.now() - 1).toISOString();
      const submission = {
        assigned_to: currentUserId,
        locked_until: pastDate,
      };
      expect(getLockStatus(submission, currentUserId)).toBe('expired');
    });
  });
});

describe('formatLockExpiry', () => {
  describe('Active Locks', () => {
    it('should format 1 minute remaining', () => {
      const futureDate = new Date(Date.now() + 60000).toISOString();
      const result = formatLockExpiry(futureDate);
      expect(result).toBe('1:00');
    });

    it('should format 5 minutes 30 seconds remaining', () => {
      const futureDate = new Date(Date.now() + 5.5 * 60000).toISOString();
      const result = formatLockExpiry(futureDate);
      expect(result).toBe('5:30');
    });

    it('should format 10 seconds remaining', () => {
      const futureDate = new Date(Date.now() + 10000).toISOString();
      const result = formatLockExpiry(futureDate);
      expect(result).toBe('0:10');
    });

    it('should format 59 seconds remaining', () => {
      const futureDate = new Date(Date.now() + 59000).toISOString();
      const result = formatLockExpiry(futureDate);
      expect(result).toBe('0:59');
    });

    it('should format 15 minutes remaining', () => {
      const futureDate = new Date(Date.now() + 15 * 60000).toISOString();
      const result = formatLockExpiry(futureDate);
      expect(result).toBe('15:00');
    });

    it('should pad single digit seconds with zero', () => {
      const futureDate = new Date(Date.now() + 65000).toISOString(); // 1:05
      const result = formatLockExpiry(futureDate);
      expect(result).toBe('1:05');
    });
  });

  describe('Expired Locks', () => {
    it('should return "Expired" for expired lock', () => {
      const pastDate = new Date(Date.now() - 1000).toISOString();
      const result = formatLockExpiry(pastDate);
      expect(result).toBe('Expired');
    });

    it('should return "Expired" for lock expired 1 minute ago', () => {
      const pastDate = new Date(Date.now() - 60000).toISOString();
      const result = formatLockExpiry(pastDate);
      expect(result).toBe('Expired');
    });

    it('should return "Expired" for lock expired 1 hour ago', () => {
      const pastDate = new Date(Date.now() - 3600000).toISOString();
      const result = formatLockExpiry(pastDate);
      expect(result).toBe('Expired');
    });
  });

  describe('Edge Cases', () => {
    it('should handle lock expiring in 1 second', () => {
      const futureDate = new Date(Date.now() + 1000).toISOString();
      const result = formatLockExpiry(futureDate);
      expect(result).toBe('0:01');
    });

    it('should handle lock expiring right now', () => {
      const futureDate = new Date(Date.now()).toISOString();
      const result = formatLockExpiry(futureDate);
      expect(result).toBe('Expired');
    });

    it('should handle lock expiring in less than 1 second', () => {
      const futureDate = new Date(Date.now() + 500).toISOString();
      const result = formatLockExpiry(futureDate);
      expect(result).toBe('0:00');
    });
  });
});

describe('getLockUrgency', () => {
  describe('Critical Urgency', () => {
    it('should return critical for 1 minute remaining', () => {
      const timeLeftMs = 60000;
      expect(getLockUrgency(timeLeftMs)).toBe('critical');
    });

    it('should return critical for 30 seconds remaining', () => {
      const timeLeftMs = 30000;
      expect(getLockUrgency(timeLeftMs)).toBe('critical');
    });

    it('should return critical for 1 second remaining', () => {
      const timeLeftMs = 1000;
      expect(getLockUrgency(timeLeftMs)).toBe('critical');
    });

    it('should return critical for exactly 2 minutes - 1ms remaining', () => {
      const timeLeftMs = 2 * 60 * 1000 - 1;
      expect(getLockUrgency(timeLeftMs)).toBe('critical');
    });

    it('should return critical for 0 seconds remaining', () => {
      const timeLeftMs = 0;
      expect(getLockUrgency(timeLeftMs)).toBe('critical');
    });

    it('should return critical for negative time (expired)', () => {
      const timeLeftMs = -1000;
      expect(getLockUrgency(timeLeftMs)).toBe('critical');
    });
  });

  describe('Warning Urgency', () => {
    it('should return warning for 4 minutes remaining', () => {
      const timeLeftMs = 4 * 60000;
      expect(getLockUrgency(timeLeftMs)).toBe('warning');
    });

    it('should return warning for 3 minutes remaining', () => {
      const timeLeftMs = 3 * 60000;
      expect(getLockUrgency(timeLeftMs)).toBe('warning');
    });

    it('should return warning for exactly 2 minutes remaining', () => {
      const timeLeftMs = 2 * 60 * 1000;
      expect(getLockUrgency(timeLeftMs)).toBe('warning');
    });

    it('should return warning for exactly 5 minutes - 1ms remaining', () => {
      const timeLeftMs = 5 * 60 * 1000 - 1;
      expect(getLockUrgency(timeLeftMs)).toBe('warning');
    });
  });

  describe('Normal Urgency', () => {
    it('should return normal for 6 minutes remaining', () => {
      const timeLeftMs = 6 * 60000;
      expect(getLockUrgency(timeLeftMs)).toBe('normal');
    });

    it('should return normal for 10 minutes remaining', () => {
      const timeLeftMs = 10 * 60000;
      expect(getLockUrgency(timeLeftMs)).toBe('normal');
    });

    it('should return normal for 15 minutes remaining', () => {
      const timeLeftMs = 15 * 60000;
      expect(getLockUrgency(timeLeftMs)).toBe('normal');
    });

    it('should return normal for exactly 5 minutes remaining', () => {
      const timeLeftMs = 5 * 60 * 1000;
      expect(getLockUrgency(timeLeftMs)).toBe('normal');
    });

    it('should return normal for 1 hour remaining', () => {
      const timeLeftMs = 60 * 60000;
      expect(getLockUrgency(timeLeftMs)).toBe('normal');
    });
  });

  describe('Edge Cases', () => {
    it('should handle very large time values', () => {
      const timeLeftMs = 999999999;
      expect(getLockUrgency(timeLeftMs)).toBe('normal');
    });

    it('should handle very negative time values', () => {
      const timeLeftMs = -999999999;
      expect(getLockUrgency(timeLeftMs)).toBe('critical');
    });

    it('should handle exactly at 2 minute boundary', () => {
      const timeLeftMs = 2 * 60 * 1000;
      expect(getLockUrgency(timeLeftMs)).toBe('warning');
    });

    it('should handle exactly at 5 minute boundary', () => {
      const timeLeftMs = 5 * 60 * 1000;
      expect(getLockUrgency(timeLeftMs)).toBe('normal');
    });
  });
});

describe('Type Safety', () => {
  it('should enforce LockStatus type', () => {
    const validStatuses: LockStatus[] = [
      'locked_by_me',
      'locked_by_other',
      'unlocked',
      'expired',
    ];

    validStatuses.forEach(status => {
      expect(['locked_by_me', 'locked_by_other', 'unlocked', 'expired']).toContain(status);
    });
  });

  it('should enforce LockUrgency type', () => {
    const validUrgencies: LockUrgency[] = [
      'critical',
      'warning',
      'normal',
    ];

    validUrgencies.forEach(urgency => {
      expect(['critical', 'warning', 'normal']).toContain(urgency);
    });
  });
});
