/**
 * Tests for Type Guards
 * FE-TYPE-004: Test type guard functions for runtime type checking
 */

import { describe, it, expect } from 'vitest';
import {
  isUser,
  isTrack,
  isPlaylist,
  isConversation,
  isMessage,
  isSession,
  isAuditLog,
  isNotification,
  isApiError,
  isApiResponse,
  isPaginationData,
  isUserArray,
  isTrackArray,
  isPlaylistArray,
  isConversationArray,
  isMessageArray,
  isNotificationArray,
  isUUID,
  isEmail,
  isISO8601Date,
  isNonEmptyString,
  isPositiveNumber,
  isNonNegativeNumber,
  isURL,
  isPlainObject,
  isArrayOf,
  isNotNull,
  isDefined,
  isNumber,
  isBoolean,
  isString,
} from './typeGuards';

describe('typeGuards', () => {
  describe('isUser', () => {
    it('should return true for valid user', () => {
      const user = {
        id: '123e4567-e89b-12d3-a456-426614174000',
        username: 'testuser',
        email: 'test@example.com',
        role: 'user',
        is_active: true,
        is_verified: true,
        is_admin: false,
        is_public: true,
        created_at: '2024-01-01T00:00:00Z',
        updated_at: '2024-01-01T00:00:00Z',
      };

      expect(isUser(user)).toBe(true);
    });

    it('should return false for invalid user', () => {
      expect(isUser(null)).toBe(false);
      expect(isUser(undefined)).toBe(false);
      expect(isUser({})).toBe(false);
      expect(isUser({ id: '123' })).toBe(false);
    });
  });

  describe('isTrack', () => {
    it('should return true for valid track', () => {
      const track = {
        id: '123e4567-e89b-12d3-a456-426614174000',
        creator_id: '123e4567-e89b-12d3-a456-426614174001',
        title: 'Test Track',
        artist: 'Test Artist',
        album: 'Test Album',
        duration: 180,
        genre: 'Rock',
        year: 2024,
        file_path: '/path/to/file.mp3',
        file_size: 5000000,
        format: 'mp3',
        bitrate: 320,
        sample_rate: 44100,
        is_public: true,
        status: 'completed',
        stream_status: 'ready',
        play_count: 0,
        like_count: 0,
        created_at: '2024-01-01T00:00:00Z',
        updated_at: '2024-01-01T00:00:00Z',
      };

      expect(isTrack(track)).toBe(true);
    });

    it('should return false for invalid track', () => {
      expect(isTrack(null)).toBe(false);
      expect(isTrack({})).toBe(false);
      expect(isTrack({ id: '123' })).toBe(false);
    });
  });

  describe('isPlaylist', () => {
    it('should return true for valid playlist', () => {
      const playlist = {
        id: '123e4567-e89b-12d3-a456-426614174000',
        user_id: '123e4567-e89b-12d3-a456-426614174001',
        title: 'Test Playlist',
        is_public: true,
        track_count: 10,
        follower_count: 5,
        created_at: '2024-01-01T00:00:00Z',
        updated_at: '2024-01-01T00:00:00Z',
      };

      expect(isPlaylist(playlist)).toBe(true);
    });
  });

  describe('isConversation', () => {
    it('should return true for valid conversation', () => {
      const conversation = {
        id: '123e4567-e89b-12d3-a456-426614174000',
        name: 'Test Conversation',
        type: 'group',
        creator_id: '123e4567-e89b-12d3-a456-426614174001',
        created_at: '2024-01-01T00:00:00Z',
        updated_at: '2024-01-01T00:00:00Z',
      };

      expect(isConversation(conversation)).toBe(true);
    });
  });

  describe('isMessage', () => {
    it('should return true for valid message', () => {
      const message = {
        id: '123e4567-e89b-12d3-a456-426614174000',
        conversation_id: '123e4567-e89b-12d3-a456-426614174001',
        sender_id: '123e4567-e89b-12d3-a456-426614174002',
        content: 'Hello, world!',
        message_type: 'text',
        created_at: '2024-01-01T00:00:00Z',
        updated_at: '2024-01-01T00:00:00Z',
      };

      expect(isMessage(message)).toBe(true);
    });
  });

  describe('isNotification', () => {
    it('should return true for valid notification', () => {
      const notification = {
        id: '123e4567-e89b-12d3-a456-426614174000',
        user_id: '123e4567-e89b-12d3-a456-426614174001',
        type: 'new_message',
        content: 'You have a new message',
        read: false,
        created_at: '2024-01-01T00:00:00Z',
      };

      expect(isNotification(notification)).toBe(true);
    });
  });

  describe('isApiError', () => {
    it('should return true for valid API error', () => {
      const error = {
        code: 400,
        message: 'Bad Request',
        timestamp: '2024-01-01T00:00:00Z',
      };

      expect(isApiError(error)).toBe(true);
    });
  });

  describe('isApiResponse', () => {
    it('should return true for valid API response', () => {
      const response = {
        success: true,
        data: { id: '123' },
      };

      expect(isApiResponse(response)).toBe(true);
    });

    it('should return true for failed API response', () => {
      const response = {
        success: false,
        error: { code: 400, message: 'Error' },
      };

      expect(isApiResponse(response)).toBe(true);
    });
  });

  describe('isPaginationData', () => {
    it('should return true for valid pagination data', () => {
      const pagination = {
        page: 1,
        limit: 20,
        total: 100,
        total_pages: 5,
        has_next: true,
        has_prev: false,
      };

      expect(isPaginationData(pagination)).toBe(true);
    });
  });

  describe('isUUID', () => {
    it('should return true for valid UUID', () => {
      expect(isUUID('123e4567-e89b-12d3-a456-426614174000')).toBe(false); // Invalid UUID v4
      expect(isUUID('550e8400-e29b-41d4-a716-446655440000')).toBe(true); // Valid UUID v4
    });

    it('should return false for invalid UUID', () => {
      expect(isUUID('not-a-uuid')).toBe(false);
      expect(isUUID('123')).toBe(false);
      expect(isUUID(null)).toBe(false);
    });
  });

  describe('isEmail', () => {
    it('should return true for valid email', () => {
      expect(isEmail('test@example.com')).toBe(true);
    });

    it('should return false for invalid email', () => {
      expect(isEmail('not-an-email')).toBe(false);
      expect(isEmail('@example.com')).toBe(false);
      expect(isEmail('test@')).toBe(false);
    });
  });

  describe('isISO8601Date', () => {
    it('should return true for valid ISO8601 date', () => {
      expect(isISO8601Date('2024-01-01T00:00:00Z')).toBe(true);
      expect(isISO8601Date('2024-01-01T00:00:00.000Z')).toBe(true);
    });

    it('should return false for invalid date', () => {
      expect(isISO8601Date('2024-01-01')).toBe(false);
      expect(isISO8601Date('not-a-date')).toBe(false);
    });
  });

  describe('isNonEmptyString', () => {
    it('should return true for non-empty string', () => {
      expect(isNonEmptyString('hello')).toBe(true);
    });

    it('should return false for empty string', () => {
      expect(isNonEmptyString('')).toBe(false);
    });

    it('should return false for non-string', () => {
      expect(isNonEmptyString(null)).toBe(false);
      expect(isNonEmptyString(123)).toBe(false);
    });
  });

  describe('isPositiveNumber', () => {
    it('should return true for positive number', () => {
      expect(isPositiveNumber(1)).toBe(true);
      expect(isPositiveNumber(100)).toBe(true);
    });

    it('should return false for zero or negative', () => {
      expect(isPositiveNumber(0)).toBe(false);
      expect(isPositiveNumber(-1)).toBe(false);
    });
  });

  describe('isNonNegativeNumber', () => {
    it('should return true for non-negative number', () => {
      expect(isNonNegativeNumber(0)).toBe(true);
      expect(isNonNegativeNumber(1)).toBe(true);
    });

    it('should return false for negative number', () => {
      expect(isNonNegativeNumber(-1)).toBe(false);
    });
  });

  describe('isURL', () => {
    it('should return true for valid URL', () => {
      expect(isURL('https://example.com')).toBe(true);
      expect(isURL('http://example.com/path')).toBe(true);
    });

    it('should return false for invalid URL', () => {
      expect(isURL('not-a-url')).toBe(false);
      expect(isURL('example.com')).toBe(false);
    });
  });

  describe('isPlainObject', () => {
    it('should return true for plain object', () => {
      expect(isPlainObject({})).toBe(true);
      expect(isPlainObject({ key: 'value' })).toBe(true);
    });

    it('should return false for array', () => {
      expect(isPlainObject([])).toBe(false);
    });

    it('should return false for null', () => {
      expect(isPlainObject(null)).toBe(false);
    });
  });

  describe('isArrayOf', () => {
    it('should return true for array of strings', () => {
      expect(isArrayOf(['a', 'b', 'c'], isString)).toBe(true);
    });

    it('should return false for mixed array', () => {
      expect(isArrayOf(['a', 1, 'c'], isString)).toBe(false);
    });
  });

  describe('isNotNull', () => {
    it('should return true for non-null value', () => {
      expect(isNotNull('value')).toBe(true);
      expect(isNotNull(0)).toBe(true);
    });

    it('should return false for null or undefined', () => {
      expect(isNotNull(null)).toBe(false);
      expect(isNotNull(undefined)).toBe(false);
    });
  });

  describe('isDefined', () => {
    it('should return true for defined value', () => {
      expect(isDefined('value')).toBe(true);
      expect(isDefined(null)).toBe(true);
    });

    it('should return false for undefined', () => {
      expect(isDefined(undefined)).toBe(false);
    });
  });

  describe('isNumber', () => {
    it('should return true for number', () => {
      expect(isNumber(0)).toBe(true);
      expect(isNumber(123)).toBe(true);
    });

    it('should return false for NaN', () => {
      expect(isNumber(NaN)).toBe(false);
    });
  });

  describe('isBoolean', () => {
    it('should return true for boolean', () => {
      expect(isBoolean(true)).toBe(true);
      expect(isBoolean(false)).toBe(true);
    });

    it('should return false for non-boolean', () => {
      expect(isBoolean(0)).toBe(false);
      expect(isBoolean('true')).toBe(false);
    });
  });

  describe('isString', () => {
    it('should return true for string', () => {
      expect(isString('hello')).toBe(true);
      expect(isString('')).toBe(true);
    });

    it('should return false for non-string', () => {
      expect(isString(123)).toBe(false);
      expect(isString(null)).toBe(false);
    });
  });

  describe('Array type guards', () => {
    it('should validate user array', () => {
      const users = [
        {
          id: '123e4567-e89b-12d3-a456-426614174000',
          username: 'user1',
          email: 'user1@example.com',
          role: 'user',
          is_active: true,
          is_verified: true,
          is_admin: false,
          is_public: true,
          created_at: '2024-01-01T00:00:00Z',
          updated_at: '2024-01-01T00:00:00Z',
        },
      ];

      expect(isUserArray(users)).toBe(true);
    });

    it('should reject invalid array', () => {
      expect(isUserArray([{ id: '123' }])).toBe(false);
      expect(isUserArray([])).toBe(true); // Empty array is valid
    });
  });
});
