// Prayer Times utility tests
import { describe, it, expect, vi, beforeEach } from 'vitest';

// Mock the findNextPrayer function from PrayerTimes.svelte
function findNextPrayer(timings, tz) {
  const now = new Date();
  const names = ['Fajr', 'Sunrise', 'Dhuhr', 'Asr', 'Maghrib', 'Isha'];
  for (const name of names) {
    const [h, m] = timings[name].split(':').map(Number);
    const pt = new Date(now);
    pt.setHours(h, m, 0, 0);
    if (pt > now) return { name, time: timings[name] };
  }
  return { name: 'Fajr', time: timings['Fajr'] + ' (tomorrow)' };
}

describe('Prayer Times Utilities', () => {
  const mockTimings = {
    Fajr: '05:30',
    Sunrise: '06:45',
    Dhuhr: '12:30',
    Asr: '15:45',
    Maghrib: '18:30',
    Isha: '20:00'
  };

  it('should find next prayer correctly when before Fajr', () => {
    // Mock current time to be 04:00
    vi.useFakeTimers();
    vi.setSystemTime(new Date('2024-01-15T04:00:00'));
    
    const result = findNextPrayer(mockTimings, 'UTC');
    
    expect(result.name).toBe('Fajr');
    expect(result.time).toBe('05:30');
    
    vi.useRealTimers();
  });

  it('should find next prayer correctly when between Fajr and Sunrise', () => {
    vi.useFakeTimers();
    vi.setSystemTime(new Date('2024-01-15T06:00:00'));
    
    const result = findNextPrayer(mockTimings, 'UTC');
    
    expect(result.name).toBe('Sunrise');
    expect(result.time).toBe('06:45');
    
    vi.useRealTimers();
  });

  it('should find next prayer correctly when between Dhuhr and Asr', () => {
    vi.useFakeTimers();
    vi.setSystemTime(new Date('2024-01-15T14:00:00'));
    
    const result = findNextPrayer(mockTimings, 'UTC');
    
    expect(result.name).toBe('Asr');
    expect(result.time).toBe('15:45');
    
    vi.useRealTimers();
  });

  it('should wrap to Fajr tomorrow when past Isha', () => {
    vi.useFakeTimers();
    vi.setSystemTime(new Date('2024-01-15T21:00:00'));
    
    const result = findNextPrayer(mockTimings, 'UTC');
    
    expect(result.name).toBe('Fajr');
    expect(result.time).toBe('05:30 (tomorrow)');
    
    vi.useRealTimers();
  });

  it('should handle exact prayer time (returns next)', () => {
    vi.useFakeTimers();
    vi.setSystemTime(new Date('2024-01-15T12:30:00'));
    
    const result = findNextPrayer(mockTimings, 'UTC');
    
    // At exactly Dhuhr time, should return Asr
    expect(result.name).toBe('Asr');
    
    vi.useRealTimers();
  });
});

// Qibla bearing calculation tests
function toRad(d) { return (d * Math.PI) / 180; }
function toDeg(r) { return (r * 180) / Math.PI; }

function calcBearing(lat, lng) {
  const KAABA = { lat: 21.4225, lng: 39.8262 };
  const dLng = toRad(KAABA.lng - lng);
  const y = Math.sin(dLng) * Math.cos(toRad(KAABA.lat));
  const x = Math.cos(toRad(lat)) * Math.sin(toRad(KAABA.lat))
          - Math.sin(toRad(lat)) * Math.cos(toRad(KAABA.lat)) * Math.cos(dLng);
  return (toDeg(Math.atan2(y, x)) + 360) % 360;
}

describe('Qibla Bearing Calculation', () => {
  it('should return 0° for Kaaba itself', () => {
    const bearing = calcBearing(21.4225, 39.8262);
    expect(Math.round(bearing)).toBe(0);
  });

  it('should return ~292° for London (51.5074, -0.1278)', () => {
    const bearing = calcBearing(51.5074, -0.1278);
    expect(Math.round(bearing)).toBe(119); // London -> Makkah is ~119°
  });

  it('should return ~17° for Jakarta (-6.2088, 106.8456)', () => {
    const bearing = calcBearing(-6.2088, 106.8456);
    expect(Math.round(bearing)).toBe(295); // Jakarta -> Makkah is ~295°
  });

  it('should return ~22° for Kuala Lumpur (3.1390, 101.6869)', () => {
    const bearing = calcBearing(3.1390, 101.6869);
    expect(Math.round(bearing)).toBe(293); // KL -> Makkah is ~293°
  });

  it('should return ~58° for New York (40.7128, -74.0060)', () => {
    const bearing = calcBearing(40.7128, -74.0060);
    expect(Math.round(bearing)).toBe(58); // NYC -> Makkah is ~58°
  });

  it('should handle southern hemisphere correctly', () => {
    // Sydney (-33.8688, 151.2093) -> Makkah should be ~277°
    const bearing = calcBearing(-33.8688, 151.2093);
    expect(Math.round(bearing)).toBe(277);
  });

  it('should always return value between 0 and 360', () => {
    // Test various coordinates
    const testCoords = [
      [90, 0],    // North Pole
      [-90, 0],   // South Pole
      [0, 0],     // Equator, Prime Meridian
      [0, 180],   // Equator, Antimeridian
      [45, 45],   // Mid-latitude
      [-45, -45]  // Southern mid-latitude
    ];
    
    testCoords.forEach(([lat, lng]) => {
      const bearing = calcBearing(lat, lng);
      expect(bearing).toBeGreaterThanOrEqual(0);
      expect(bearing).toBeLessThan(360);
    });
  });
});

// Hijri date conversion test (mocking API response)
describe('Hijri Date', () => {
  it('should parse hijri date response correctly', () => {
    const mockResponse = {
      code: 200,
      data: {
        hijri: {
          day: '15',
          month: { number: 9, en: 'Ramadan', ar: 'رَمَضَان' },
          year: '1445',
          weekday: { en: 'Friday', ar: 'الجمعة' },
          designation: { expanded: 'Ramadan 1445' }
        }
      }
    };
    
    expect(mockResponse.data.hijri.day).toBe('15');
    expect(mockResponse.data.hijri.month.en).toBe('Ramadan');
    expect(mockResponse.data.hijri.year).toBe('1445');
  });
});

// Tasbih counter tests
describe('Tasbih Counter Logic', () => {
  it('should increment and wrap at target', () => {
    let count = 0;
    const target = 33;
    
    function increment() {
      count = (count + 1) % target;
    }
    
    for (let i = 0; i < 33; i++) {
      increment();
    }
    expect(count).toBe(0);
    
    increment();
    expect(count).toBe(1);
  });

  it('should track total separately from count', () => {
    let count = 0;
    let total = 0;
    const target = 33;
    
    function increment() {
      count = (count + 1) % target;
      total++;
    }
    
    for (let i = 0; i < 50; i++) {
      increment();
    }
    
    expect(count).toBe(17); // 50 % 33 = 17
    expect(total).toBe(50);
  });

  it('should reset both count and total', () => {
    let count = 17;
    let total = 50;
    
    function reset() {
      count = 0;
      total = 0;
    }
    
    reset();
    expect(count).toBe(0);
    expect(total).toBe(0);
  });
});

// 99 Names search/filter tests
const mockNames = [
  { no: 1, ar: 'الرَّحْمَنُ', en: 'Ar-Rahman', meaning: 'The Most Merciful' },
  { no: 2, ar: 'الرَّحِيمُ', en: 'Ar-Raheem', meaning: 'The Most Compassionate' },
  { no: 3, ar: 'الْمَلِكُ', en: 'Al-Malik', meaning: 'The King' },
  { no: 93, ar: 'النُّورُ', en: 'An-Nur', meaning: 'The Light' },
];

function filterNames(names, search) {
  if (!search.trim()) return names;
  const term = search.toLowerCase();
  return names.filter(n => 
    n.en.toLowerCase().includes(term) || 
    n.meaning.toLowerCase().includes(term) || 
    n.ar.includes(search)
  );
}

describe('99 Names Search', () => {
  it('should return all names when search is empty', () => {
    const result = filterNames(mockNames, '');
    expect(result.length).toBe(4);
  });

  it('should filter by English name', () => {
    const result = filterNames(mockNames, 'Rahman');
    expect(result.length).toBe(1);
    expect(result[0].en).toBe('Ar-Rahman');
  });

  it('should filter by meaning', () => {
    const result = filterNames(mockNames, 'King');
    expect(result.length).toBe(1);
    expect(result[0].en).toBe('Al-Malik');
  });

  it('should filter by Arabic text', () => {
    const result = filterNames(mockNames, 'النُّورُ');
    expect(result.length).toBe(1);
    expect(result[0].no).toBe(93);
  });

  it('should be case insensitive for English', () => {
    const result1 = filterNames(mockNames, 'rahman');
    const result2 = filterNames(mockNames, 'RAHMAN');
    expect(result1.length).toBe(result2.length);
    expect(result1.length).toBe(1);
  });

  it('should return empty array for no matches', () => {
    const result = filterNames(mockNames, 'xyz');
    expect(result.length).toBe(0);
  });
});