import { Injectable, BadRequestException, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { Recipe } from './recipe.entity';
import { CraftJob } from './craft-job.entity';
import { Character } from '../character/entities/character.entity';
import { ItemService } from '../item/item.service';
import { MaterialService } from '../material/material.service';
import { User } from '../user/user.entity';

@Injectable()
export class CraftService {
  constructor(
    @InjectRepository(Recipe)
    private readonly recipeRepository: Repository<Recipe>,
    @InjectRepository(CraftJob)
    private readonly craftJobRepository: Repository<CraftJob>,
    @InjectRepository(Character)
    private readonly characterRepository: Repository<Character>,
    private readonly itemService: ItemService,
    private readonly materialService: MaterialService,
    private readonly eventEmitter: EventEmitter2,
  ) {}

  findAllRecipes() {
    return this.recipeRepository.find({ order: { name: 'ASC' } });
  }

  async startCraft(recipeId: string, user: User) {
    const char = await this.getCharacter(user);
    const recipe = await this.recipeRepository.findOne({ where: { id: recipeId } });
    if (!recipe) throw new NotFoundException('Recette introuvable');

    // Vérifier qu'aucun craft actif
    const activeCraft = await this.craftJobRepository.findOne({
      where: { characterId: char.id, collected: false },
    });
    if (activeCraft) throw new BadRequestException('Un craft est déjà en cours');

    // Calculer endurance actuelle (lazy pattern)
    const elapsedMinutes = (Date.now() - char.lastEnduranceTs.getTime()) / 60_000;
    const recharge = Math.floor(elapsedMinutes / 6);
    const enduranceCurrent = Math.min(char.enduranceSaved + recharge, char.enduranceMax);

    if (enduranceCurrent < recipe.enduranceCost) {
      throw new BadRequestException(
        `Endurance insuffisante (${enduranceCurrent}/${recipe.enduranceCost} requis)`,
      );
    }

    // Consommer les matériaux (vérifie la dispo et déduit)
    await this.materialService.consumeMaterials(char.id, recipe.ingredients);

    // Déduire l'endurance
    char.enduranceSaved = enduranceCurrent - recipe.enduranceCost;
    char.lastEnduranceTs = new Date();
    await this.characterRepository.save(char);

    // Créer le job (lazy timer)
    const startedAt = new Date();
    const completedAt = new Date(startedAt.getTime() + recipe.craftDurationSeconds * 1000);
    const job = this.craftJobRepository.create({
      characterId: char.id,
      recipeId: recipe.id,
      startedAt,
      completedAt,
      collected: false,
    });
    await this.craftJobRepository.save(job);

    return {
      jobId: job.id,
      recipe: recipe.name,
      startedAt,
      completedAt,
      remainingSeconds: recipe.craftDurationSeconds,
      status: 'pending',
    };
  }

  async getActiveJob(user: User) {
    const char = await this.getCharacter(user);
    const job = await this.craftJobRepository.findOne({
      where: { characterId: char.id, collected: false },
    });
    if (!job) return { status: 'none' };

    const now = new Date();
    const remaining = Math.max(0, Math.floor((job.completedAt.getTime() - now.getTime()) / 1000));
    return {
      status: now >= job.completedAt ? 'ready' : 'pending',
      jobId: job.id,
      recipe: job.recipe.name,
      completedAt: job.completedAt,
      remainingSeconds: remaining,
    };
  }

  async collectCraft(jobId: string, user: User) {
    const char = await this.getCharacter(user);
    const job = await this.craftJobRepository.findOne({
      where: { id: jobId, characterId: char.id, collected: false },
    });
    if (!job) throw new NotFoundException('Craft introuvable');

    const remaining = Math.ceil((job.completedAt.getTime() - Date.now()) / 1000);
    if (remaining > 0) {
      throw new BadRequestException(`Craft non terminé — encore ${remaining}s`);
    }

    // Ajouter l'item crafté à l'inventaire
    const charItem = await this.itemService.addItemToInventory(char.id, job.recipe.resultItemId);

    job.collected = true;
    await this.craftJobRepository.save(job);

    // Emit achievement event
    this.eventEmitter.emit('achievement.check', {
      characterId: char.id,
      type: 'craft_completed',
      increment: 1,
    });

    return {
      collected: true,
      item: charItem.item,
      message: `${job.recipe.resultItem.name} ajouté à l'inventaire !`,
    };
  }

  private async getCharacter(user: User): Promise<Character> {
    const char = await this.characterRepository.findOne({ where: { userId: user.id } });
    if (!char) throw new BadRequestException('Aucun personnage trouvé');
    return char;
  }
}
