/**
 * Health Service Tests
 * Tests the health business logic with mock implementations
 */
import { describe, it, expect, beforeEach } from 'vitest';

// Mock habit data
interface Habit {
  id: string;
  name: string;
  category: string;
  healthImpact: number;
  status?: 'active' | 'quitting' | 'quit';
  quittingProgress?: number;
}

const HABITS: Habit[] = [
  { id: 'habit-1', name: 'Smoking', category: 'substance', healthImpact: -5 },
  { id: 'habit-2', name: 'Drinking Alcohol', category: 'substance', healthImpact: -3 },
  { id: 'habit-3', name: 'Gambling', category: 'behavioral', healthImpact: -1 },
  { id: 'habit-4', name: 'Junk Food', category: 'diet', healthImpact: -2 },
  { id: 'habit-5', name: 'Excessive Gaming', category: 'behavioral', healthImpact: -1 },
  { id: 'habit-6', name: 'Social Media Addiction', category: 'behavioral', healthImpact: -1 },
];

// Mock person type
interface MockPerson {
  id: string;
  firstname?: string;
  health: number;
  ageYears: number;
  habits: Habit[];
}

// Mock health status type
interface HealthStatus {
  level: string;
  description: string;
  riskFactors: string[];
}

// Mock service functions
function getHealthStatus(person: MockPerson): HealthStatus {
  const health = person.health;

  if (health >= 90) {
    return { level: 'Excellent', description: 'Peak physical condition', riskFactors: [] };
  }
  if (health >= 70) {
    return { level: 'Good', description: 'Healthy condition', riskFactors: [] };
  }
  if (health >= 50) {
    return { level: 'Fair', description: 'Average health', riskFactors: ['Could improve with exercise'] };
  }
  if (health >= 25) {
    return { level: 'Poor', description: 'Health concerns present', riskFactors: ['Should see a doctor', 'At risk for illness'] };
  }
  return { level: 'Critical', description: 'Serious health issues', riskFactors: ['Immediate medical attention needed', 'High mortality risk'] };
}

function calculateHealthDecay(person: MockPerson, hours: number): number {
  // Base decay rate
  let decayRate = 0.1;

  // Age factor - older people decay faster
  if (person.ageYears >= 60) {
    decayRate *= 2;
  } else if (person.ageYears >= 40) {
    decayRate *= 1.5;
  }

  // Calculate total decay
  return Math.min(person.health, decayRate * (hours / 24));
}

function applyHealthBonus(person: MockPerson, amount: number): number {
  const newHealth = Math.max(0, Math.min(100, person.health + amount));
  person.health = newHealth;
  return newHealth;
}

function getHabits(): Habit[] {
  return HABITS.map(h => ({ ...h }));
}

function quitHabit(person: MockPerson, habitId: string): void {
  const habit = person.habits.find(h => h.id === habitId);
  if (habit) {
    habit.status = 'quitting';
    habit.quittingProgress = 0;
  }
}

function stopQuitHabit(person: MockPerson, habitId: string): void {
  const habit = person.habits.find(h => h.id === habitId);
  if (habit) {
    habit.status = 'active';
    habit.quittingProgress = 0;
  }
}

function updateHabitProgress(person: MockPerson, habitId: string, days: number): void {
  const habit = person.habits.find(h => h.id === habitId);
  if (habit && habit.status === 'quitting') {
    habit.quittingProgress = Math.max(0, (habit.quittingProgress ?? 0) + days);
    if (habit.quittingProgress >= 30) {
      habit.status = 'quit';
    }
  }
}

describe('Health Service', () => {
  let person: MockPerson;

  beforeEach(() => {
    person = {
      id: 'player-1',
      firstname: 'Test',
      health: 80,
      ageYears: 25,
      habits: [],
    };
  });

  describe('getHealthStatus', () => {
    it('should return health status for a person', () => {
      const status = getHealthStatus(person);

      expect(status).toBeDefined();
      expect(typeof status).toBe('object');
    });

    it('should categorize health levels correctly', () => {
      const excellent = { ...person, health: 95 };
      const good = { ...person, health: 75 };
      const fair = { ...person, health: 50 };
      const poor = { ...person, health: 25 };
      const critical = { ...person, health: 10 };

      expect(getHealthStatus(excellent).level).toBe('Excellent');
      expect(getHealthStatus(good).level).toBe('Good');
      expect(getHealthStatus(fair).level).toBe('Fair');
      expect(getHealthStatus(poor).level).toBe('Poor');
      expect(getHealthStatus(critical).level).toBe('Critical');
    });

    it('should include risk factors for low health', () => {
      const poor = { ...person, health: 20 };
      const status = getHealthStatus(poor);

      expect(status.riskFactors.length).toBeGreaterThan(0);
    });
  });

  describe('calculateHealthDecay', () => {
    it('should calculate health decay based on time', () => {
      const decay = calculateHealthDecay(person, 24);

      expect(typeof decay).toBe('number');
      expect(decay).toBeGreaterThanOrEqual(0);
    });

    it('should decay faster for older characters', () => {
      const young = { ...person, ageYears: 20 };
      const old = { ...person, ageYears: 70 };

      const youngDecay = calculateHealthDecay(young, 24);
      const oldDecay = calculateHealthDecay(old, 24);

      expect(oldDecay).toBeGreaterThanOrEqual(youngDecay);
    });

    it('should not decay below 0', () => {
      const lowHealth = { ...person, health: 5, ageYears: 80 };
      const decay = calculateHealthDecay(lowHealth, 1000);
      const newHealth = Math.max(0, lowHealth.health - decay);

      expect(newHealth).toBeGreaterThanOrEqual(0);
    });
  });

  describe('applyHealthBonus', () => {
    it('should apply positive health bonus', () => {
      person.health = 50;
      const newHealth = applyHealthBonus(person, 20);

      expect(newHealth).toBe(70);
    });

    it('should not exceed max health (100)', () => {
      person.health = 90;
      const newHealth = applyHealthBonus(person, 50);

      expect(newHealth).toBeLessThanOrEqual(100);
    });

    it('should handle negative health changes', () => {
      person.health = 80;
      const newHealth = applyHealthBonus(person, -30);

      expect(newHealth).toBe(50);
    });

    it('should not go below 0', () => {
      person.health = 10;
      const newHealth = applyHealthBonus(person, -50);

      expect(newHealth).toBe(0);
    });
  });

  describe('getHabits', () => {
    it('should return list of possible habits', () => {
      const habits = getHabits();

      expect(Array.isArray(habits)).toBe(true);
      expect(habits.length).toBeGreaterThan(0);
    });

    it('should have habits with required properties', () => {
      const habits = getHabits();

      habits.forEach(habit => {
        expect(habit).toHaveProperty('id');
        expect(habit).toHaveProperty('name');
        expect(typeof habit.id).toBe('string');
        expect(typeof habit.name).toBe('string');
      });
    });

    it('should categorize habits', () => {
      const habits = getHabits();
      const categories = new Set(habits.map(h => h.category).filter(Boolean));

      expect(categories.size).toBeGreaterThan(0);
    });
  });

  describe('quitHabit', () => {
    it('should start quitting process for a habit', () => {
      person.habits = [{ id: 'habit-1', name: 'Test Habit', category: 'test', healthImpact: -1, status: 'active' }];

      quitHabit(person, 'habit-1');

      const habit = person.habits.find(h => h.id === 'habit-1');
      expect(habit?.status).toBe('quitting');
    });

    it('should set quitting progress to 0', () => {
      person.habits = [{ id: 'habit-1', name: 'Test Habit', category: 'test', healthImpact: -1, status: 'active' }];

      quitHabit(person, 'habit-1');

      const habit = person.habits.find(h => h.id === 'habit-1');
      expect(habit?.quittingProgress).toBe(0);
    });

    it('should handle non-existent habit', () => {
      person.habits = [];

      expect(() => quitHabit(person, 'non-existent')).not.toThrow();
    });
  });

  describe('stopQuitHabit', () => {
    it('should stop quitting and return to active', () => {
      person.habits = [{ id: 'habit-1', name: 'Test Habit', category: 'test', healthImpact: -1, status: 'quitting', quittingProgress: 10 }];

      stopQuitHabit(person, 'habit-1');

      const habit = person.habits.find(h => h.id === 'habit-1');
      expect(habit?.status).toBe('active');
    });

    it('should reset quitting progress', () => {
      person.habits = [{ id: 'habit-1', name: 'Test Habit', category: 'test', healthImpact: -1, status: 'quitting', quittingProgress: 15 }];

      stopQuitHabit(person, 'habit-1');

      const habit = person.habits.find(h => h.id === 'habit-1');
      expect(habit?.quittingProgress).toBe(0);
    });
  });

  describe('updateHabitProgress', () => {
    it('should increment quitting progress', () => {
      person.habits = [{ id: 'habit-1', name: 'Test Habit', category: 'test', healthImpact: -1, status: 'quitting', quittingProgress: 5 }];

      updateHabitProgress(person, 'habit-1', 1);

      const habit = person.habits.find(h => h.id === 'habit-1');
      expect(habit?.quittingProgress).toBe(6);
    });

    it('should complete quitting at 30 days', () => {
      person.habits = [{ id: 'habit-1', name: 'Test Habit', category: 'test', healthImpact: -1, status: 'quitting', quittingProgress: 29 }];

      updateHabitProgress(person, 'habit-1', 1);

      const habit = person.habits.find(h => h.id === 'habit-1');
      expect(habit?.quittingProgress).toBeGreaterThanOrEqual(30);
      expect(habit?.status).toBe('quit');
    });

    it('should handle relapse mechanics', () => {
      person.habits = [{ id: 'habit-1', name: 'Test Habit', category: 'test', healthImpact: -1, status: 'quitting', quittingProgress: 10 }];

      updateHabitProgress(person, 'habit-1', -5);

      const habit = person.habits.find(h => h.id === 'habit-1');
      expect(habit?.quittingProgress).toBe(5);
    });

    it('should not go below 0 progress', () => {
      person.habits = [{ id: 'habit-1', name: 'Test Habit', category: 'test', healthImpact: -1, status: 'quitting', quittingProgress: 3 }];

      updateHabitProgress(person, 'habit-1', -10);

      const habit = person.habits.find(h => h.id === 'habit-1');
      expect(habit?.quittingProgress).toBe(0);
    });
  });

  describe('Health stat ranges', () => {
    const healthLevels = [0, 10, 25, 50, 75, 90, 100];

    healthLevels.forEach(level => {
      it(`should handle health level ${level}`, () => {
        person.health = level;
        const status = getHealthStatus(person);
        expect(status).toBeDefined();
      });
    });
  });

  describe('Age-based health factors', () => {
    const ages = [5, 15, 25, 40, 60, 80, 100];

    ages.forEach(age => {
      it(`should calculate health for age ${age}`, () => {
        person.ageYears = age;
        const decay = calculateHealthDecay(person, 24);
        expect(typeof decay).toBe('number');
      });
    });
  });

  describe('Habit types', () => {
    it('should include negative habits', () => {
      const habits = getHabits();
      const negative = habits.filter(h => h.healthImpact < 0);

      expect(negative.length).toBeGreaterThan(0);
    });

    it('should have health impact values', () => {
      const habits = getHabits();

      habits.forEach(habit => {
        expect(typeof habit.healthImpact).toBe('number');
      });
    });
  });

  describe('Health recovery', () => {
    it('should support natural health recovery', () => {
      person.health = 50;
      const recovered = applyHealthBonus(person, 10);
      expect(recovered).toBe(60);
    });

    it('should recovery be same for any age', () => {
      const young = { ...person, health: 50, ageYears: 20 };
      const old = { ...person, health: 50, ageYears: 70 };

      expect(applyHealthBonus(young, 10)).toBe(60);
      expect(applyHealthBonus(old, 10)).toBe(60);
    });
  });
});
