import {Injectable, Logger} from '@nestjs/common';
import {SocketEvents} from "../../shared/events.consts";
import {GuestsService} from "../../guests/guests.service";
import {SharedService} from "../../shared/shared.service";
import {InjectModel} from "@nestjs/mongoose";
import {Versus, VersusDocument} from "../../schemas/versus.schema";
import {Model} from "mongoose";
import {VersusDto} from "./versus.types";
import {CommandBus} from "@nestjs/cqrs";
import {IncreasePlayerScoreCommand} from "../../guests/command/increase-player-score.command";
import {IncreasePlayerWinningRateCommand} from "../commands/increase-player-winning-rate.command";

@Injectable()
export class VersusService {
  static configKeyCurrentAction = 'current_action';
  static configKeyActiveVersus = 'active_versus';
  private logger = new Logger(VersusService.name);
  constructor(
    private guestService: GuestsService,
    private sharedService: SharedService,
    @InjectModel(Versus.name) private versusModel: Model<VersusDocument>,
    private cmdBus: CommandBus,
  ) {
  }
  async simulateVersus() {
    const guests = (await this.guestService.findAll()).slice(0,2).map((guest) => {
      return {
        id: guest.telegramId,
        name: guest.name,
      }
    });
    if(guests.length < 2) {
      throw new Error("Can't simulate,  in db less than 2 players")
    }
    await this.beginVersus(guests[0].id, guests[1].id);
  }

  async beginVersus(player1: number, player2: number) {
    const [p1data,p2data] = await Promise.all([this.guestService.findById(player1), this.guestService.findById(player2)]);
    await this.sharedService.setConfig(VersusService.configKeyCurrentAction, JSON.stringify({
      action:'versus',
      data: {
        player1: player1,
        player2: player2,
        player1name: p1data.name,
        player2name: p2data.name,
      }
    }));
    this.sharedService.sendSocketNotificationToAllClients(
      SocketEvents.BEGIN_VERSUS,
      { player1, player2, player1name: p1data.name, player2name: p2data.name }
    )
  }

  async importVersus(data: VersusDto[]) {
    data.map(async (record) => {
      const item = new this.versusModel({
        ...record
      });
      await item.save();
    });
    return { result: true };
  }

  async getVersusTask() {
    const rand = await this.versusModel
      .aggregate([{ $match: { completed: false } }, { $sample: { size: 1 } }])
      .exec();
    // @TODO check who win with telegram

    const item = await this.versusModel.findOne({ _id: rand[0]._id }).exec();
    await this.sharedService.setConfig(VersusService.configKeyActiveVersus, item.id);
    return item;
  }
  async markAllAsUncompleted() {
    const versuses = await this.versusModel.find().exec();
    versuses.map(async (versus) => {
      versus.completed = false;
      await versus.save();
    });
    return { result: true };
  }

  async complete(winner: number) {
    const activeVersus = await this.sharedService.getConfig(VersusService.configKeyActiveVersus);
    const item = await this.versusModel.findOne({ _id: activeVersus.value }).exec();
    item.completed = true;
    await item.save();
    await this.cmdBus.execute(new IncreasePlayerScoreCommand(winner, 2));
    await this.cmdBus.execute(new IncreasePlayerWinningRateCommand(winner, 30));
    await this.sharedService.setConfig(VersusService.configKeyCurrentAction, '');
    this.sharedService.sendSocketNotificationToAllClients(
      SocketEvents.END_VERSUS,
      { winner: winner }
    )

    return item;
  }

  async checkIfAnotherVersusInProgress() {
    this.logger.debug(`checkIfAnotherVersusInProgress enter`)
    const currentAction = await this.sharedService.getConfig(VersusService.configKeyCurrentAction);
    return currentAction.value !== '';

  }
}
