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

// Mock store items data
interface StoreItem {
  id: string;
  name: string;
  description: string;
  category: string;
  price?: number;
  diamondPrice?: number;
  energyBonus?: number;
  healthBonus?: number;
  happinessBonus?: number;
  intelligenceBonus?: number;
}

const STORE_ITEMS: StoreItem[] = [
  { id: 'item-1', name: 'Energy Drink', description: 'Restores energy', category: 'food', price: 50, energyBonus: 20 },
  { id: 'item-2', name: 'Healthy Meal', description: 'Nutritious food', category: 'food', price: 100, healthBonus: 10, energyBonus: 5 },
  { id: 'item-3', name: 'Movie Ticket', description: 'Entertainment', category: 'entertainment', price: 25, happinessBonus: 15 },
  { id: 'item-4', name: 'Gym Pass', description: 'Monthly membership', category: 'health', price: 200, healthBonus: 20, energyBonus: 10 },
  { id: 'item-5', name: 'Book Collection', description: 'Learn new things', category: 'education', price: 75, intelligenceBonus: 5, happinessBonus: 5 },
  { id: 'item-6', name: 'Premium Coffee', description: 'Luxury drink', category: 'food', diamondPrice: 10, energyBonus: 30 },
  { id: 'item-7', name: 'Spa Day', description: 'Relaxation package', category: 'health', diamondPrice: 25, healthBonus: 25, happinessBonus: 25 },
  { id: 'item-8', name: 'Luxury Dinner', description: 'Fine dining', category: 'food', price: 500, happinessBonus: 30, healthBonus: 5 },
  { id: 'item-9', name: 'Video Game', description: 'New release', category: 'entertainment', price: 60, happinessBonus: 20 },
  { id: 'item-10', name: 'Super Bundle', description: 'All-in-one package', category: 'premium', price: 2000, energyBonus: 50, healthBonus: 50, happinessBonus: 50 },
];

// Mock player state
interface MockPlayer {
  id: string;
  money: number;
  diamonds: number;
  energy: number;
  health: number;
  happiness: number;
  intelligence: number;
  inventory: string[];
}

// Mock service functions
function getStoreItems(): StoreItem[] {
  return STORE_ITEMS;
}

function getItemById(itemId: string): StoreItem | undefined {
  return STORE_ITEMS.find(item => item.id === itemId);
}

function canAffordItem(player: MockPlayer, item: StoreItem): boolean {
  if (item.diamondPrice && item.diamondPrice > 0) {
    return player.diamonds >= item.diamondPrice;
  }
  if (item.price && item.price > 0) {
    return player.money >= item.price;
  }
  return false;
}

function purchaseItem(player: MockPlayer, itemId: string): { success: boolean; message?: string; item?: StoreItem } {
  const item = getItemById(itemId);

  if (!item) {
    return { success: false, message: 'Item not found' };
  }

  if (!canAffordItem(player, item)) {
    return { success: false, message: 'Cannot afford item' };
  }

  // Deduct cost
  if (item.diamondPrice && item.diamondPrice > 0) {
    player.diamonds -= item.diamondPrice;
  } else if (item.price && item.price > 0) {
    player.money -= item.price;
  }

  // Apply effects
  if (item.energyBonus) {
    player.energy = Math.min(100, player.energy + item.energyBonus);
  }
  if (item.healthBonus) {
    player.health = Math.min(100, player.health + item.healthBonus);
  }
  if (item.happinessBonus) {
    player.happiness = Math.min(100, player.happiness + item.happinessBonus);
  }
  if (item.intelligenceBonus) {
    player.intelligence = Math.min(100, player.intelligence + item.intelligenceBonus);
  }

  // Add to inventory
  player.inventory.push(itemId);

  return { success: true, item };
}

describe('Shop Service', () => {
  let player: MockPlayer;

  beforeEach(() => {
    player = {
      id: 'test-player',
      money: 1000,
      diamonds: 50,
      energy: 50,
      health: 50,
      happiness: 50,
      intelligence: 50,
      inventory: [],
    };
  });

  describe('getStoreItems', () => {
    it('should return list of store items', () => {
      const items = getStoreItems();

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

    it('should have items with required properties', () => {
      const items = getStoreItems();

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

    it('should have items with prices', () => {
      const items = getStoreItems();

      items.forEach(item => {
        const hasPrice =
          (item.price ?? 0) > 0 ||
          (item.diamondPrice ?? 0) > 0;

        expect(hasPrice).toBe(true);
      });
    });

    it('should have items with effects', () => {
      const items = getStoreItems();

      const itemsWithEffects = items.filter(item =>
        (item.energyBonus ?? 0) !== 0 ||
        (item.healthBonus ?? 0) !== 0 ||
        (item.happinessBonus ?? 0) !== 0 ||
        (item.intelligenceBonus ?? 0) !== 0
      );

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

  describe('getItemById', () => {
    it('should find item by ID', () => {
      const items = getStoreItems();
      const found = getItemById(items[0].id);

      expect(found).toBeDefined();
      expect(found?.id).toBe(items[0].id);
    });

    it('should return undefined for non-existent item', () => {
      const found = getItemById('non-existent-item-12345');

      expect(found).toBeUndefined();
    });
  });

  describe('canAffordItem', () => {
    it('should return true if can afford with money', () => {
      player.money = 1000;
      const items = getStoreItems();
      const moneyItem = items.find(i => (i.price ?? 0) > 0 && (i.price ?? 0) <= 1000);

      if (moneyItem) {
        const result = canAffordItem(player, moneyItem);
        expect(result).toBe(true);
      }
    });

    it('should return false if cannot afford', () => {
      player.money = 10;
      const items = getStoreItems();
      const expensiveItem = items.find(i => (i.price ?? 0) > 10);

      if (expensiveItem) {
        const result = canAffordItem(player, expensiveItem);
        expect(result).toBe(false);
      }
    });

    it('should check diamond cost', () => {
      player.diamonds = 100;
      const items = getStoreItems();
      const diamondItem = items.find(i => (i.diamondPrice ?? 0) > 0 && (i.diamondPrice ?? 0) <= 100);

      if (diamondItem) {
        const result = canAffordItem(player, diamondItem);
        expect(result).toBe(true);
      }
    });

    it('should return false if cannot afford diamonds', () => {
      player.diamonds = 5;
      const items = getStoreItems();
      const diamondItem = items.find(i => (i.diamondPrice ?? 0) > 5);

      if (diamondItem) {
        const result = canAffordItem(player, diamondItem);
        expect(result).toBe(false);
      }
    });
  });

  describe('purchaseItem', () => {
    it('should purchase item successfully', () => {
      player.money = 10000;
      const items = getStoreItems();
      const result = purchaseItem(player, items[0].id);

      expect(result).toBeDefined();
      expect(result.success).toBe(true);
    });

    it('should deduct money on purchase', () => {
      player.money = 1000;
      const items = getStoreItems();
      const moneyItem = items.find(i => (i.price ?? 0) > 0 && (i.price ?? 0) <= 1000);

      if (moneyItem) {
        const initialMoney = player.money;
        purchaseItem(player, moneyItem.id);

        expect(player.money).toBeLessThan(initialMoney);
      }
    });

    it('should deduct diamonds on purchase', () => {
      player.diamonds = 100;
      const items = getStoreItems();
      const diamondItem = items.find(i => (i.diamondPrice ?? 0) > 0 && (i.diamondPrice ?? 0) <= 100);

      if (diamondItem) {
        const initialDiamonds = player.diamonds;
        purchaseItem(player, diamondItem.id);

        expect(player.diamonds).toBeLessThan(initialDiamonds);
      }
    });

    it('should apply item effects', () => {
      player.money = 10000;
      player.energy = 50;
      player.health = 50;
      player.happiness = 50;

      const items = getStoreItems();
      const effectItem = items.find(i =>
        (i.energyBonus ?? 0) > 0 ||
        (i.healthBonus ?? 0) > 0 ||
        (i.happinessBonus ?? 0) > 0
      );

      if (effectItem) {
        const initialEnergy = player.energy;
        const initialHealth = player.health;
        const initialHappiness = player.happiness;

        purchaseItem(player, effectItem.id);

        const changed =
          player.energy !== initialEnergy ||
          player.health !== initialHealth ||
          player.happiness !== initialHappiness;

        expect(changed).toBe(true);
      }
    });

    it('should fail if cannot afford', () => {
      player.money = 0;
      player.diamonds = 0;

      const items = getStoreItems();
      const result = purchaseItem(player, items[0].id);

      expect(result.success).toBe(false);
    });

    it('should fail for invalid item', () => {
      player.money = 10000;
      const result = purchaseItem(player, 'non-existent-item');

      expect(result.success).toBe(false);
    });

    it('should add item to inventory', () => {
      player.money = 10000;
      const items = getStoreItems();

      expect(player.inventory).toHaveLength(0);

      purchaseItem(player, items[0].id);

      expect(player.inventory).toContain(items[0].id);
    });
  });

  describe('Item categories', () => {
    it('should have food items', () => {
      const items = getStoreItems();
      const food = items.filter(i => i.category === 'food');

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

    it('should have entertainment items', () => {
      const items = getStoreItems();
      const entertainment = items.filter(i => i.category === 'entertainment');

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

    it('should have health items', () => {
      const items = getStoreItems();
      const health = items.filter(i => i.category === 'health');

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

    it('should have education items', () => {
      const items = getStoreItems();
      const education = items.filter(i => i.category === 'education');

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

  describe('Item effects ranges', () => {
    it('should have reasonable energy bonuses', () => {
      const items = getStoreItems();

      items.forEach(item => {
        if (item.energyBonus !== undefined) {
          expect(item.energyBonus).toBeGreaterThanOrEqual(-100);
          expect(item.energyBonus).toBeLessThanOrEqual(100);
        }
      });
    });

    it('should have reasonable health bonuses', () => {
      const items = getStoreItems();

      items.forEach(item => {
        if (item.healthBonus !== undefined) {
          expect(item.healthBonus).toBeGreaterThanOrEqual(-100);
          expect(item.healthBonus).toBeLessThanOrEqual(100);
        }
      });
    });

    it('should have reasonable happiness bonuses', () => {
      const items = getStoreItems();

      items.forEach(item => {
        if (item.happinessBonus !== undefined) {
          expect(item.happinessBonus).toBeGreaterThanOrEqual(-100);
          expect(item.happinessBonus).toBeLessThanOrEqual(100);
        }
      });
    });

    it('should cap stats at 100', () => {
      player.energy = 90;
      player.money = 10000;

      const energyItem = getStoreItems().find(i => (i.energyBonus ?? 0) > 10);
      if (energyItem) {
        purchaseItem(player, energyItem.id);
        expect(player.energy).toBeLessThanOrEqual(100);
      }
    });
  });

  describe('Price ranges', () => {
    it('should have varied prices', () => {
      const items = getStoreItems();
      const prices = items.map(i => i.price ?? 0).filter(p => p > 0);

      const min = Math.min(...prices);
      const max = Math.max(...prices);

      expect(max).toBeGreaterThan(min);
    });

    it('should have affordable starter items', () => {
      const items = getStoreItems();
      const affordable = items.filter(i => (i.price ?? 0) <= 100 && (i.price ?? 0) > 0);

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

    it('should have premium items', () => {
      const items = getStoreItems();
      const premium = items.filter(i =>
        (i.diamondPrice ?? 0) > 0 ||
        (i.price ?? 0) > 1000
      );

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

  describe('Multiple purchases', () => {
    it('should handle sequential purchases', () => {
      player.money = 10000;

      const items = getStoreItems();
      const result1 = purchaseItem(player, items[0].id);
      const result2 = purchaseItem(player, items[1].id);

      expect(result1.success).toBe(true);
      expect(result2.success).toBe(true);
      expect(player.inventory).toHaveLength(2);
    });

    it('should track spending correctly', () => {
      player.money = 1000;

      const item = getStoreItems().find(i => i.price === 50);
      if (item) {
        purchaseItem(player, item.id);
        expect(player.money).toBe(950);

        purchaseItem(player, item.id);
        expect(player.money).toBe(900);
      }
    });
  });
});
