import { describe, expect, it } from 'vitest';

import {
  buildDashboardSignOfWeekPayload,
  buildSignLanguageCategories,
  buildSignLanguageLifeprintGifUrl,
  buildSignLanguageYoutubeSearchUrl,
  filterSignLanguageItems,
  getSignLanguageProgressPercent,
  getSignLanguageVideoDurationSeconds,
  normalizeSignLanguageGifUrl,
  normalizeSignLanguageItems,
  normalizeSignLanguageYoutubeVideoUrl,
  selectSignLanguageSignOfWeek,
  toSignLanguageCategoryFilter,
} from '@/business/sign-language/selectors';
import type { SignItem } from '@/shared/types/app';

const signs: readonly SignItem[] = [
  {
    id: 'help',
    word: 'Help',
    category: 'basic-needs',
    description: 'Help description',
    image: 'help.jpg',
    tip: 'Help tip',
    videoUrl: 'https://example.com/help-video',
    gifUrl: 'https://example.com/help.gif',
    videoSteps: [
      { step: 1, instruction: 'First', duration: 3 },
      { step: 2, instruction: 'Second', duration: 3 },
    ],
  },
  {
    id: 'calm',
    word: 'Calm',
    category: 'emotional',
    description: 'Calm description',
    image: 'calm.jpg',
    tip: 'Calm tip',
    videoUrl: 'https://example.com/calm-video',
    gifUrl: 'https://example.com/calm.gif',
    videoSteps: [
      { step: 1, instruction: 'First', duration: 4 },
    ],
  },
  {
    id: 'sit',
    word: 'Sit',
    category: 'classroom',
    description: 'Sit description',
    image: 'sit.jpg',
    tip: 'Sit tip',
    videoUrl: 'https://example.com/sit-video',
    gifUrl: 'https://example.com/sit.gif',
    videoSteps: [],
  },
];

describe('sign language selectors', () => {
  it('builds category counts from available signs', () => {
    expect(buildSignLanguageCategories(signs)).toEqual([
      { value: 'all', label: 'All Signs', count: 3 },
      { value: 'basic-needs', label: 'Basic Needs', count: 1 },
      { value: 'emotional', label: 'Emotional', count: 1 },
      { value: 'classroom', label: 'Classroom', count: 1 },
    ]);
  });

  it('filters signs by normalized search and category', () => {
    expect(filterSignLanguageItems(signs, {
      searchQuery: ' he ',
      categoryFilter: 'basic-needs',
    })).toEqual([signs[0]]);
  });

  it('returns zero progress when there are no signs', () => {
    expect(getSignLanguageProgressPercent([], new Set(['help']))).toBe(0);
  });

  it('calculates learned sign progress', () => {
    expect(getSignLanguageProgressPercent(signs, new Set(['help', 'calm']))).toBeCloseTo(66.67, 2);
  });

  it('calculates video duration from step count and first duration', () => {
    expect(getSignLanguageVideoDurationSeconds(signs[0])).toBe(6);
    expect(getSignLanguageVideoDurationSeconds(signs[2])).toBe(0);
  });

  it('normalizes unknown category filters to all', () => {
    expect(toSignLanguageCategoryFilter('emotional')).toBe('emotional');
    expect(toSignLanguageCategoryFilter('unknown')).toBe('all');
  });

  it('builds encoded YouTube search URLs', () => {
    expect(buildSignLanguageYoutubeSearchUrl(' All Done ')).toBe(
      'https://www.youtube.com/results?search_query=ASL%20sign%20language%20All%20Done%20tutorial',
    );
  });

  it('normalizes YouTube URLs to embeddable video URLs', () => {
    expect(normalizeSignLanguageYoutubeVideoUrl('https://www.youtube.com/watch?v=abc123_XYZ')).toBe(
      'https://www.youtube.com/embed/abc123_XYZ',
    );
    expect(normalizeSignLanguageYoutubeVideoUrl('https://youtu.be/abc123_XYZ')).toBe(
      'https://www.youtube.com/embed/abc123_XYZ',
    );
    expect(normalizeSignLanguageYoutubeVideoUrl('abc123_XYZ')).toBe(
      'https://www.youtube.com/embed/abc123_XYZ',
    );
  });

  it('normalizes Lifeprint GIF paths to the canonical GIF catalog', () => {
    expect(buildSignLanguageLifeprintGifUrl('/asl101/gifs/h/help.gif')).toBe(
      'https://www.lifeprint.com/asl101/gifs/h/help.gif',
    );
    expect(normalizeSignLanguageGifUrl('gifs/m/more')).toBe(
      'https://www.lifeprint.com/asl101/gifs/m/more.gif',
    );
  });

  it('suppresses legacy Lifeprint image-sign URLs as animated demos', () => {
    expect(normalizeSignLanguageGifUrl('https://www.lifeprint.com/asl101/images-signs/listen.gif')).toBe('');
    expect(normalizeSignLanguageGifUrl('images-signs/listen.gif')).toBe('');
  });

  it('normalizes sign media fields before rendering', () => {
    const normalizedSigns = normalizeSignLanguageItems([{
      ...signs[0],
      image: ' help.jpg ',
      videoUrl: 'https://www.youtube.com/watch?v=abc123_XYZ',
      gifUrl: 'gifs/h/help',
    }]);

    expect(normalizedSigns[0]).toMatchObject({
      image: 'help.jpg',
      videoUrl: 'https://www.youtube.com/embed/abc123_XYZ',
      gifUrl: 'https://www.lifeprint.com/asl101/gifs/h/help.gif',
    });
  });

  it('uses explicit YouTube search URLs when provided', () => {
    const normalizedSigns = normalizeSignLanguageItems([{
      ...signs[0],
      youtubeSearchUrl: ' https://www.youtube.com/results?search_query=help ',
    }]);

    expect(normalizedSigns[0].youtubeSearchUrl).toBe(
      'https://www.youtube.com/results?search_query=help',
    );
  });

  it('selects sign of the week by selector id with seeded word fallback', () => {
    expect(selectSignLanguageSignOfWeek(signs, {
      signId: 'calm',
      word: 'Help',
      description: 'Old payload',
      image: 'old.jpg',
      alt: 'Old',
    })).toEqual(signs[1]);

    expect(selectSignLanguageSignOfWeek(signs, {
      word: 'Help',
      description: 'Old payload',
      image: 'old.jpg',
      alt: 'Old',
    })).toEqual(signs[0]);
  });

  it('builds dashboard sign-of-week selector payloads from sign cards', () => {
    expect(buildDashboardSignOfWeekPayload(signs[0], new Date('2026-06-22T12:00:00Z'))).toEqual({
      signId: 'help',
      weekOf: '2026-06-21',
      word: 'Help',
      description: 'Help description',
      image: 'help.jpg',
      alt: 'Help sign',
    });
  });
});
