import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

import { Game_PersonEntity } from '../game/game.entity';
import { TrackingEntity } from './tracking.entity';
import { GeoDTO } from './geo.dto';
import { FactionEntity } from 'src/faction/faction.entity';

@Injectable()
export class TrackingService {
  constructor(
    @InjectRepository(TrackingEntity)
    private trackingrepository: Repository<TrackingEntity>,
    @InjectRepository(Game_PersonEntity)
    private gamepersonrepository: Repository<Game_PersonEntity>,
    @InjectRepository(FactionEntity)
    private factionRepository: Repository<FactionEntity>,
  ) {}

  private icons = {
    infantry: 'infantry.svg',
    recon: 'recon.svg',
    mechanized: 'mechanized.svg',
  };

  async trackLocation(
    gameperson: Game_PersonEntity,
    gameId,
    trackdata: GeoDTO,
  ) {
    // find ref to gameperson's tracking data
    let trackedperson = await this.trackingrepository.findOne({
      gamepersonId: gameperson,
    });

    if (trackedperson) {
      trackdata['time'] = Date.now();
      //add coordinates
      trackedperson.data.push(trackdata);
      //add timestamp
      await this.trackingrepository.save(trackedperson);
      return { message: 'Location updated!' };
    } else {
      trackdata['time'] = Date.now();
      // initialize data
      trackedperson = await this.trackingrepository.create(trackedperson);
      // if group exists, add icon based on that, else add default icon
      trackedperson.icon = gameperson.group
        ? this.icons[gameperson.group.class]
        : 'infantry.svg';
      trackedperson.data = [trackdata];
      trackedperson.faction = gameperson.faction;
      trackedperson.game = gameId;
      trackedperson.gamepersonId = gameperson;
      await this.trackingrepository.save(trackedperson);

      return { message: 'Entry Created!' };
    }
  }

  // get player data while game is running
  async getPlayers(gameperson, gameId) {
    let playerdata = [];
    // get playerdata
    if (gameperson.faction) {
      // create an array of the response as frontend maps the response
      // to create different clusters for factions
      playerdata.push(
        await this.trackingrepository.find({
          where: { faction: gameperson.faction },
          relations: ['faction', 'gamepersonId', 'gamepersonId.person'],
        }),
      );
    } else {
      let factions = await this.factionRepository.find({ game: gameId });
      playerdata = await Promise.all(
        factions.map(async faction => {
          let rawdata = await this.trackingrepository.find({
            where: { faction: faction.factionId },
            relations: ['faction', 'gamepersonId', 'gamepersonId.person'],
          });
          let groups = {
            'infantry.svg': [],
            'recon.svg': [],
            'mechanized.svg': [],
          };
          rawdata.forEach(async player => {
            groups[player.icon].push(player);
          });
          return groups;
        }),
      );
    }
    // parse data
    // create an array for each faction
    // inside faction create an array for each icon type
    // insisde icon arrays include all players with same icon
    const currentdata = await Promise.all(
      await playerdata.map(async faction => {
        let data = [];
        for (let group in faction) {
          data.push(
            await Promise.all(
              faction[group].map(async player => {
                return await {
                  username: player['gamepersonId']['person']['name'],
                  gamepersonId: player['gamepersonId']['gamepersonId'],
                  gamepersonRole: player['gamepersonId']['role'],
                  factionId: player['faction']['factionId'],
                  factionColour: player['faction']['colour'],
                  icon: player['icon'],
                  coordinates: player['data'].pop(),
                };
              }),
            ),
          );
        }
        return data;
      }),
    );
    return currentdata;
  }
}