import {
  Injectable,
  NotFoundException,
  ForbiddenException,
  BadRequestException,
} from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { TranslationsService } from '../translations/translations.service';
import { CharactersGateway } from './characters.gateway';
import { TranslationType, ResearchField } from '../../generated/prisma/client.js';
import {
  AddFormulaDto,
  DailyPreparationDto,
  QuickAlchemyDto,
  InitializeAlchemyDto,
} from './dto';

@Injectable()
export class AlchemyService {
  constructor(
    private prisma: PrismaService,
    private translationsService: TranslationsService,
    private charactersGateway: CharactersGateway,
  ) {}

  /**
   * Enrich equipment with German translations
   */
  private async enrichEquipmentWithTranslations(
    equipment: { name: string; summary?: string | null; effect?: string | null } | null | undefined,
  ): Promise<{ nameGerman?: string; summaryGerman?: string; effectGerman?: string }> {
    if (!equipment) {
      return {};
    }
    try {
      const translation = await this.translationsService.getTranslation(
        TranslationType.EQUIPMENT,
        equipment.name,
        equipment.summary || undefined,
        equipment.effect || undefined,
      );
      return {
        nameGerman: translation.germanName,
        summaryGerman: translation.germanDescription,
        effectGerman: translation.germanEffect,
      };
    } catch {
      return {};
    }
  }

  // Check if user has access to character
  private async checkCharacterAccess(characterId: string, userId: string, requireOwnership = false) {
    const character = await this.prisma.character.findUnique({
      where: { id: characterId },
      include: { campaign: { include: { members: true } } },
    });

    if (!character) {
      throw new NotFoundException('Character not found');
    }

    const isGM = character.campaign.gmId === userId;
    const isOwner = character.ownerId === userId;

    if (requireOwnership && !isOwner && !isGM) {
      throw new ForbiddenException('Only the owner or GM can modify this character');
    }

    const isMember = character.campaign.members.some((m) => m.userId === userId);
    if (!isGM && !isMember) {
      throw new ForbiddenException('No access to this character');
    }

    return character;
  }

  /**
   * Get full alchemy data for a character
   */
  async getAlchemy(characterId: string, userId: string) {
    await this.checkCharacterAccess(characterId, userId);

    const [alchemyState, formulas, preparedItems] = await Promise.all([
      this.prisma.characterAlchemyState.findUnique({
        where: { characterId },
      }),
      this.prisma.characterFormula.findMany({
        where: { characterId },
        include: { equipment: true },
        orderBy: [{ learnedAt: 'asc' }, { name: 'asc' }],
      }),
      this.prisma.characterPreparedItem.findMany({
        where: { characterId },
        include: { equipment: true },
        orderBy: { createdAt: 'desc' },
      }),
    ]);

    // Enrich formulas with translations
    const enrichedFormulas = await Promise.all(
      formulas.map(async (formula) => {
        const translations = await this.enrichEquipmentWithTranslations(formula.equipment);
        return {
          ...formula,
          equipment: formula.equipment
            ? { ...formula.equipment, ...translations }
            : null,
        };
      }),
    );

    // Enrich prepared items with translations
    const enrichedPreparedItems = await Promise.all(
      preparedItems.map(async (item) => {
        const translations = await this.enrichEquipmentWithTranslations(item.equipment);
        return {
          ...item,
          equipment: item.equipment
            ? { ...item.equipment, ...translations }
            : null,
        };
      }),
    );

    return {
      state: alchemyState,
      formulas: enrichedFormulas,
      preparedItems: enrichedPreparedItems,
    };
  }

  /**
   * Initialize alchemy state for a character (usually during import or first setup)
   */
  async initializeAlchemy(characterId: string, dto: InitializeAlchemyDto, userId: string) {
    await this.checkCharacterAccess(characterId, userId, true);

    // Check if alchemy state already exists
    const existing = await this.prisma.characterAlchemyState.findUnique({
      where: { characterId },
    });

    if (existing) {
      // Update existing
      const result = await this.prisma.characterAlchemyState.update({
        where: { characterId },
        data: {
          researchField: dto.researchField as ResearchField | undefined,
          versatileVialsMax: dto.versatileVialsMax,
          versatileVialsCurrent: dto.versatileVialsMax,
          advancedAlchemyMax: dto.advancedAlchemyMax,
        },
      });

      this.charactersGateway.broadcastCharacterUpdate(characterId, {
        characterId,
        type: 'alchemy_state',
        data: result,
      });

      return result;
    }

    // Create new
    const result = await this.prisma.characterAlchemyState.create({
      data: {
        characterId,
        researchField: dto.researchField as ResearchField | undefined,
        versatileVialsMax: dto.versatileVialsMax,
        versatileVialsCurrent: dto.versatileVialsMax,
        advancedAlchemyMax: dto.advancedAlchemyMax,
      },
    });

    this.charactersGateway.broadcastCharacterUpdate(characterId, {
      characterId,
      type: 'alchemy_state',
      data: result,
    });

    return result;
  }

  /**
   * Update versatile vials current count
   */
  async updateVials(characterId: string, current: number, userId: string) {
    await this.checkCharacterAccess(characterId, userId, true);

    const alchemyState = await this.prisma.characterAlchemyState.findUnique({
      where: { characterId },
    });

    if (!alchemyState) {
      throw new NotFoundException('Alchemy state not found for this character');
    }

    const newCurrent = Math.max(0, Math.min(current, alchemyState.versatileVialsMax));

    const result = await this.prisma.characterAlchemyState.update({
      where: { characterId },
      data: { versatileVialsCurrent: newCurrent },
    });

    this.charactersGateway.broadcastCharacterUpdate(characterId, {
      characterId,
      type: 'alchemy_vials',
      data: { versatileVialsCurrent: result.versatileVialsCurrent },
    });

    return result;
  }

  /**
   * Refill vials during exploration (10 minutes of activity)
   */
  async refillVials(characterId: string, userId: string) {
    await this.checkCharacterAccess(characterId, userId, true);

    const alchemyState = await this.prisma.characterAlchemyState.findUnique({
      where: { characterId },
    });

    if (!alchemyState) {
      throw new NotFoundException('Alchemy state not found for this character');
    }

    const result = await this.prisma.characterAlchemyState.update({
      where: { characterId },
      data: { versatileVialsCurrent: alchemyState.versatileVialsMax },
    });

    this.charactersGateway.broadcastCharacterUpdate(characterId, {
      characterId,
      type: 'alchemy_vials',
      data: { versatileVialsCurrent: result.versatileVialsCurrent },
    });

    return result;
  }

  /**
   * Get formulas for a character
   */
  async getFormulas(characterId: string, userId: string) {
    await this.checkCharacterAccess(characterId, userId);

    const formulas = await this.prisma.characterFormula.findMany({
      where: { characterId },
      include: { equipment: true },
      orderBy: [{ learnedAt: 'asc' }, { name: 'asc' }],
    });

    // Enrich formulas with translations
    return Promise.all(
      formulas.map(async (formula) => {
        const translations = await this.enrichEquipmentWithTranslations(formula.equipment);
        return {
          ...formula,
          equipment: formula.equipment
            ? { ...formula.equipment, ...translations }
            : null,
        };
      }),
    );
  }

  /**
   * Extract the base name from an alchemical item name
   * E.g., "Alchemist's Fire (Greater)" -> "Alchemist's Fire"
   *       "Lesser Elixir of Life" -> "Elixir of Life"
   */
  private extractBaseName(name: string): string {
    // Remove parenthetical suffix: "Item Name (Lesser)" -> "Item Name"
    let baseName = name.replace(/\s*\((Lesser|Minor|Moderate|Greater|Major|True)\)$/i, '').trim();

    // Also handle prefix style: "Lesser Item Name" -> "Item Name"
    baseName = baseName.replace(/^(Lesser|Minor|Moderate|Greater|Major|True)\s+/i, '').trim();

    return baseName;
  }

  /**
   * Check if an item name matches a base name (is a version of that item)
   * E.g., "Alchemist's Fire (Greater)" matches base name "Alchemist's Fire"
   */
  private isVersionOf(itemName: string, baseName: string): boolean {
    const itemBaseName = this.extractBaseName(itemName);
    return itemBaseName.toLowerCase() === baseName.toLowerCase();
  }

  /**
   * Get all available formula versions for a character
   * This includes upgraded versions of known formulas up to the character's level
   * E.g., if character knows "Alchemist's Fire (Lesser)" and is level 5,
   * they can also create "Alchemist's Fire (Moderate)" (level 3)
   *
   * NOTE: This method only reads from the translation cache - it does NOT trigger
   * new translations. Translations are pre-loaded when formulas are learned.
   */
  async getAvailableFormulas(characterId: string, userId: string) {
    const character = await this.checkCharacterAccess(characterId, userId);

    // Get all learned formulas
    const formulas = await this.prisma.characterFormula.findMany({
      where: { characterId },
      include: { equipment: true },
    });

    if (formulas.length === 0) {
      return [];
    }

    // Extract unique base names from known formulas
    const baseNames = [...new Set(formulas.map(f => this.extractBaseName(f.name)))];

    // Get all alchemical items up to character level
    const allAlchemicalItems = await this.prisma.equipment.findMany({
      where: {
        itemCategory: 'Alchemical Items',
        OR: [
          { level: { lte: character.level } },
          { level: null },
        ],
      },
      orderBy: [
        { name: 'asc' },
        { level: 'asc' },
      ],
    });

    // Filter to only items that are versions of known formulas
    const matchingEquipment = allAlchemicalItems.filter(eq =>
      baseNames.some(baseName => this.isVersionOf(eq.name, baseName))
    );

    // Get cached translations for all matching equipment (single DB query, no API calls)
    const equipmentNames = matchingEquipment.map(eq => eq.name);
    const cachedTranslations = await this.prisma.translation.findMany({
      where: {
        type: TranslationType.EQUIPMENT,
        englishName: { in: equipmentNames },
      },
    });
    const translationMap = new Map(cachedTranslations.map(t => [t.englishName, t]));

    // Enrich equipment with cached translations only
    const enrichedEquipment = matchingEquipment.map((eq) => {
      const cached = translationMap.get(eq.name);
      return {
        ...eq,
        nameGerman: cached?.germanName,
        summaryGerman: cached?.germanDescription,
        effectGerman: cached?.germanEffect,
        // Mark if this is a "known" formula (exact match) or an "upgraded" version
        isLearned: formulas.some(f => f.equipmentId === eq.id),
      };
    });

    return enrichedEquipment;
  }

  /**
   * Add a formula to the character's formula book
   * Also pre-translates ALL versions of this formula (Lesser, Moderate, Greater, Major)
   */
  async addFormula(characterId: string, dto: AddFormulaDto, userId: string) {
    const character = await this.checkCharacterAccess(characterId, userId, true);

    // Verify equipment exists and is an alchemical item
    const equipment = await this.prisma.equipment.findUnique({
      where: { id: dto.equipmentId },
    });

    if (!equipment) {
      throw new NotFoundException('Equipment not found');
    }

    // Check level restriction - can only learn formulas up to character level
    const equipmentLevel = equipment.level ?? 0;
    if (equipmentLevel > character.level) {
      throw new BadRequestException(
        `Kann Formel nicht lernen: Gegenstand ist Stufe ${equipmentLevel}, Charakter ist Stufe ${character.level}`,
      );
    }

    // Check if formula already exists
    const existing = await this.prisma.characterFormula.findUnique({
      where: {
        characterId_equipmentId: {
          characterId,
          equipmentId: dto.equipmentId,
        },
      },
    });

    if (existing) {
      throw new BadRequestException('Formula already exists in formula book');
    }

    // Pre-translate ALL versions of this formula (Lesser, Moderate, Greater, Major)
    // This happens in the background so subsequent loads are fast
    const baseName = this.extractBaseName(equipment.name);
    this.preTranslateAllVersions(baseName).catch((err) => {
      // Log but don't fail the request
      console.error('Failed to pre-translate formula versions:', err);
    });

    // Get translation for this specific item
    let nameGerman: string | undefined;
    try {
      const translation = await this.translationsService.getTranslation(
        TranslationType.EQUIPMENT,
        equipment.name,
        equipment.summary || undefined,
        equipment.effect || undefined,
      );
      nameGerman = translation.germanName;
    } catch {
      // Translation not available, use original name
    }

    const result = await this.prisma.characterFormula.create({
      data: {
        characterId,
        equipmentId: dto.equipmentId,
        name: equipment.name,
        nameGerman,
        learnedAt: dto.learnedAt || 1,
        formulaSource: dto.formulaSource,
      },
      include: { equipment: true },
    });

    this.charactersGateway.broadcastCharacterUpdate(characterId, {
      characterId,
      type: 'alchemy_formulas',
      data: { action: 'add', formula: result },
    });

    return result;
  }

  /**
   * Pre-translate all versions of a formula (Lesser, Moderate, Greater, Major)
   * This is called when a formula is learned to ensure all versions are cached
   */
  private async preTranslateAllVersions(baseName: string): Promise<void> {
    // Find all alchemical items that are versions of this base formula
    const allVersions = await this.prisma.equipment.findMany({
      where: {
        itemCategory: 'Alchemical Items',
      },
    });

    const matchingVersions = allVersions.filter((eq) =>
      this.isVersionOf(eq.name, baseName),
    );

    if (matchingVersions.length === 0) {
      return;
    }

    // Batch translate all versions
    const itemsToTranslate = matchingVersions.map((eq) => ({
      englishName: eq.name,
      englishDescription: eq.summary || undefined,
      englishEffect: eq.effect || undefined,
    }));

    await this.translationsService.getTranslationsBatch(
      TranslationType.EQUIPMENT,
      itemsToTranslate,
    );
  }

  /**
   * Refresh translations for all formulas of a character
   * This pre-translates all versions of all known formulas
   * Use this to populate translations for existing characters
   */
  async refreshFormulaTranslations(characterId: string, userId: string) {
    await this.checkCharacterAccess(characterId, userId);

    // Get all learned formulas
    const formulas = await this.prisma.characterFormula.findMany({
      where: { characterId },
      include: { equipment: true },
    });

    if (formulas.length === 0) {
      return { message: 'No formulas to translate', translated: 0 };
    }

    // Extract unique base names
    const baseNames = [...new Set(formulas.map((f) => this.extractBaseName(f.name)))];

    // Find all alchemical items that are versions of these base formulas
    const allAlchemicalItems = await this.prisma.equipment.findMany({
      where: { itemCategory: 'Alchemical Items' },
    });

    const matchingVersions = allAlchemicalItems.filter((eq) =>
      baseNames.some((baseName) => this.isVersionOf(eq.name, baseName)),
    );

    if (matchingVersions.length === 0) {
      return { message: 'No formula versions found', translated: 0 };
    }

    // Batch translate all versions (including summary AND effect)
    const itemsToTranslate = matchingVersions.map((eq) => ({
      englishName: eq.name,
      englishDescription: eq.summary || undefined,
      englishEffect: eq.effect || undefined,
    }));

    await this.translationsService.getTranslationsBatch(
      TranslationType.EQUIPMENT,
      itemsToTranslate,
    );

    return {
      message: 'Translations refreshed',
      baseFormulas: baseNames.length,
      versionsTranslated: matchingVersions.length,
    };
  }

  /**
   * Remove a formula from the character's formula book
   */
  async removeFormula(characterId: string, formulaId: string, userId: string) {
    await this.checkCharacterAccess(characterId, userId, true);

    const formula = await this.prisma.characterFormula.findUnique({
      where: { id: formulaId },
    });

    if (!formula || formula.characterId !== characterId) {
      throw new NotFoundException('Formula not found');
    }

    await this.prisma.characterFormula.delete({ where: { id: formulaId } });

    this.charactersGateway.broadcastCharacterUpdate(characterId, {
      characterId,
      type: 'alchemy_formulas',
      data: { action: 'remove', formulaId },
    });

    return { message: 'Formula removed' };
  }

  /**
   * Get prepared items for a character
   */
  async getPreparedItems(characterId: string, userId: string) {
    await this.checkCharacterAccess(characterId, userId);

    const items = await this.prisma.characterPreparedItem.findMany({
      where: { characterId },
      include: { equipment: true },
      orderBy: { createdAt: 'desc' },
    });

    // Enrich prepared items with translations
    return Promise.all(
      items.map(async (item) => {
        const translations = await this.enrichEquipmentWithTranslations(item.equipment);
        return {
          ...item,
          equipment: item.equipment
            ? { ...item.equipment, ...translations }
            : null,
        };
      }),
    );
  }

  /**
   * Perform daily preparation - create infused items
   * This uses advanced alchemy batch slots
   * Now supports auto-upgraded formulas (higher level versions of known formulas)
   */
  async dailyPreparation(characterId: string, dto: DailyPreparationDto, userId: string) {
    await this.checkCharacterAccess(characterId, userId, true);

    const alchemyState = await this.prisma.characterAlchemyState.findUnique({
      where: { characterId },
    });

    if (!alchemyState) {
      throw new NotFoundException('Alchemy state not found for this character');
    }

    // Calculate total items to prepare
    const totalItems = dto.items.reduce((sum, item) => sum + item.quantity, 0);

    // Check if we have enough batch slots
    const usedSlots = alchemyState.advancedAlchemyBatch;
    const availableSlots = alchemyState.advancedAlchemyMax - usedSlots;

    if (totalItems > availableSlots) {
      throw new BadRequestException(
        `Not enough batch slots. Available: ${availableSlots}, Requested: ${totalItems}`,
      );
    }

    // Get available formulas (includes auto-upgraded versions)
    const availableFormulas = await this.getAvailableFormulas(characterId, userId);
    const availableEquipmentIds = new Set(availableFormulas.map(f => f.id));

    // Verify all requested items are available
    for (const item of dto.items) {
      if (!availableEquipmentIds.has(item.equipmentId)) {
        throw new BadRequestException(`Formula not available for equipment: ${item.equipmentId}`);
      }
    }

    // Create a map of available formulas for quick lookup
    const availableFormulasMap = new Map(availableFormulas.map(f => [f.id, f]));

    // Create prepared items with equipment included
    const preparedItems: Array<
      Awaited<ReturnType<typeof this.prisma.characterPreparedItem.create>> & { equipment: any }
    > = [];
    for (const item of dto.items) {
      const formula = availableFormulasMap.get(item.equipmentId)!;

      const prepared = await this.prisma.characterPreparedItem.create({
        data: {
          characterId,
          equipmentId: item.equipmentId,
          name: formula.name,
          nameGerman: formula.nameGerman,
          quantity: item.quantity,
          isQuickAlchemy: false,
        },
        include: { equipment: true },
      });

      preparedItems.push(prepared as any);
    }

    // Update batch counter
    await this.prisma.characterAlchemyState.update({
      where: { characterId },
      data: { advancedAlchemyBatch: usedSlots + totalItems },
    });

    // Enrich prepared items with translations
    const enrichedPreparedItems = await Promise.all(
      preparedItems.map(async (item) => {
        const translations = await this.enrichEquipmentWithTranslations(item.equipment);
        return {
          ...item,
          equipment: item.equipment
            ? { ...item.equipment, ...translations }
            : null,
        };
      }),
    );

    this.charactersGateway.broadcastCharacterUpdate(characterId, {
      characterId,
      type: 'alchemy_prepared',
      data: { action: 'prepare', items: enrichedPreparedItems, batchUsed: totalItems },
    });

    return { preparedItems: enrichedPreparedItems, batchUsed: totalItems, batchRemaining: availableSlots - totalItems };
  }

  /**
   * Use Quick Alchemy to create an item on the fly
   * This costs 1 versatile vial
   * Now supports auto-upgraded formulas (higher level versions of known formulas)
   */
  async quickAlchemy(characterId: string, dto: QuickAlchemyDto, userId: string) {
    await this.checkCharacterAccess(characterId, userId, true);

    const alchemyState = await this.prisma.characterAlchemyState.findUnique({
      where: { characterId },
    });

    if (!alchemyState) {
      throw new NotFoundException('Alchemy state not found for this character');
    }

    if (alchemyState.versatileVialsCurrent < 1) {
      throw new BadRequestException('No versatile vials available');
    }

    // Get available formulas (includes auto-upgraded versions)
    const availableFormulas = await this.getAvailableFormulas(characterId, userId);
    const formula = availableFormulas.find(f => f.id === dto.equipmentId);

    if (!formula) {
      throw new BadRequestException('Formula not available');
    }

    // Create the quick alchemy item
    const prepared = await this.prisma.characterPreparedItem.create({
      data: {
        characterId,
        equipmentId: dto.equipmentId,
        name: formula.name,
        nameGerman: formula.nameGerman,
        quantity: 1,
        isQuickAlchemy: true,
      },
      include: { equipment: true },
    });

    // Enrich with translations
    const translations = await this.enrichEquipmentWithTranslations(prepared.equipment);
    const enrichedPrepared = {
      ...prepared,
      equipment: prepared.equipment
        ? { ...prepared.equipment, ...translations }
        : null,
    };

    // Consume a vial
    await this.prisma.characterAlchemyState.update({
      where: { characterId },
      data: { versatileVialsCurrent: alchemyState.versatileVialsCurrent - 1 },
    });

    this.charactersGateway.broadcastCharacterUpdate(characterId, {
      characterId,
      type: 'alchemy_prepared',
      data: { action: 'quick_alchemy', item: enrichedPrepared },
    });

    this.charactersGateway.broadcastCharacterUpdate(characterId, {
      characterId,
      type: 'alchemy_vials',
      data: { versatileVialsCurrent: alchemyState.versatileVialsCurrent - 1 },
    });

    return enrichedPrepared;
  }

  /**
   * Consume/use a prepared item (reduce quantity or remove)
   */
  async consumePreparedItem(characterId: string, itemId: string, userId: string) {
    await this.checkCharacterAccess(characterId, userId, true);

    const item = await this.prisma.characterPreparedItem.findUnique({
      where: { id: itemId },
    });

    if (!item || item.characterId !== characterId) {
      throw new NotFoundException('Prepared item not found');
    }

    if (item.quantity > 1) {
      // Reduce quantity
      const result = await this.prisma.characterPreparedItem.update({
        where: { id: itemId },
        data: { quantity: item.quantity - 1 },
        include: { equipment: true },
      });

      // Enrich with translations
      const translations = await this.enrichEquipmentWithTranslations(result.equipment);
      const enrichedResult = {
        ...result,
        equipment: result.equipment
          ? { ...result.equipment, ...translations }
          : null,
      };

      this.charactersGateway.broadcastCharacterUpdate(characterId, {
        characterId,
        type: 'alchemy_prepared',
        data: { action: 'update', item: enrichedResult },
      });

      return enrichedResult;
    } else {
      // Remove entirely
      await this.prisma.characterPreparedItem.delete({ where: { id: itemId } });

      this.charactersGateway.broadcastCharacterUpdate(characterId, {
        characterId,
        type: 'alchemy_prepared',
        data: { action: 'remove', itemId },
      });

      return { message: 'Item consumed' };
    }
  }

  /**
   * Delete a prepared item completely
   */
  async deletePreparedItem(characterId: string, itemId: string, userId: string) {
    await this.checkCharacterAccess(characterId, userId, true);

    const item = await this.prisma.characterPreparedItem.findUnique({
      where: { id: itemId },
    });

    if (!item || item.characterId !== characterId) {
      throw new NotFoundException('Prepared item not found');
    }

    await this.prisma.characterPreparedItem.delete({ where: { id: itemId } });

    this.charactersGateway.broadcastCharacterUpdate(characterId, {
      characterId,
      type: 'alchemy_prepared',
      data: { action: 'remove', itemId },
    });

    return { message: 'Item removed' };
  }

  /**
   * Craft a permanent (non-infused) alchemical item
   * This represents normal alchemy crafting with resources/gold
   * Items created this way do NOT expire on rest
   */
  async craftAlchemy(
    characterId: string,
    equipmentId: string,
    quantity: number,
    userId: string,
  ) {
    await this.checkCharacterAccess(characterId, userId, true);

    // Verify equipment exists and is an alchemical item
    const equipment = await this.prisma.equipment.findUnique({
      where: { id: equipmentId },
    });

    if (!equipment) {
      throw new NotFoundException('Equipment not found');
    }

    // Translate the name if needed
    let nameGerman: string | undefined;
    try {
      const translation = await this.translationsService.getTranslation(
        TranslationType.EQUIPMENT,
        equipment.name,
        equipment.summary || undefined,
        equipment.effect || undefined,
      );
      nameGerman = translation.germanName;
    } catch {
      // Translation not available, use original name
    }

    // Create the permanent (non-infused) item
    const prepared = await this.prisma.characterPreparedItem.create({
      data: {
        characterId,
        equipmentId,
        name: equipment.name,
        nameGerman,
        quantity,
        isQuickAlchemy: false,
        isInfused: false, // This is the key difference - permanent items
      },
      include: { equipment: true },
    });

    // Enrich with translations
    const translations = await this.enrichEquipmentWithTranslations(prepared.equipment);
    const enrichedPrepared = {
      ...prepared,
      equipment: prepared.equipment
        ? { ...prepared.equipment, ...translations }
        : null,
    };

    this.charactersGateway.broadcastCharacterUpdate(characterId, {
      characterId,
      type: 'alchemy_prepared',
      data: { action: 'craft', item: enrichedPrepared },
    });

    return enrichedPrepared;
  }
}
