import { Controller } from '@nestjs/common';
import { EventPattern, Transport } from '@nestjs/microservices';
import { JSDOM } from 'jsdom';
import { StarsService } from '@gitroom/nestjs-libraries/database/prisma/stars/stars.service';
import { TrendingService } from '@gitroom/nestjs-libraries/services/trending.service';
import dayjs from 'dayjs';

@Controller()
export class StarsController {
  constructor(
    private _starsService: StarsService,
    private _trendingService: TrendingService
  ) {}
  @EventPattern('check_stars', Transport.REDIS)
  async checkStars(data: { login: string }) {
    // no to be effected by the limit, we scrape the HTML instead of using the API
    const loadedHtml = await (
      await fetch(`https://github.com/${data.login}`)
    ).text();
    const dom = new JSDOM(loadedHtml);

    const totalStars =
      +dom.window.document
        .querySelector('#repo-stars-counter-star')
        ?.getAttribute('title')
        ?.replace(/,/g, '') || 0;

    const totalForks = +dom.window.document
      .querySelector('#repo-network-counter')
      ?.getAttribute('title')
      ?.replace(/,/g, '');

    const lastValue = await this._starsService.getLastStarsByLogin(
      data.login
    );

    if (dayjs(lastValue.date).format('YYYY-MM-DD') === dayjs().format('YYYY-MM-DD')) {
      console.log('stars already synced for today');
      return ;
    }

    const totalNewsStars = totalStars - (lastValue?.totalStars || 0);
    const totalNewsForks = totalForks - (lastValue?.totalForks || 0);


    // if there is no stars in the database, we need to sync the stars
    if (!lastValue?.totalStars) {
      return;
    }

    // if there is stars in the database, sync the new stars
    return this._starsService.createStars(
      data.login,
      totalNewsStars,
      totalStars,
      totalNewsForks,
      totalForks,
      new Date()
    );
  }

  @EventPattern('sync_all_stars', Transport.REDIS, { concurrency: 1 })
  async syncAllStars(data: { login: string }) {
    // if there is a sync in progress, it's better not to touch it
    if (data?.login && (await this._starsService.getStarsByLogin(data?.login)).length) {
      return;
    }

    const findValidToken = await this._starsService.findValidToken(data?.login);
    await this._starsService.sync(data.login, findValidToken?.token);
  }

  @EventPattern('sync_trending', Transport.REDIS, { concurrency: 1 })
  async syncTrending() {
    return this._trendingService.syncTrending();
  }
}
