import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ProjectEntity } from '../entities/project.entity';
import { decodeBigNumberKey } from '../utils/big-number-key';
import { ProjectStatsParameterDTO } from './dto/stats-dto';

@Injectable()
export class ProjectStatService {
  constructor(
    @InjectRepository(ProjectEntity)
    private readonly projectRepo: Repository<ProjectEntity>,
  ) {}

  async getMembersCount(
    project_id: string,
    from: Date | null = null,
    to: Date | null = null,
  ): Promise<number> {
    const members_stats_params: any[] = [decodeBigNumberKey(project_id)];
    const members_stats_where: string[] = [];

    if (from) {
      members_stats_where.push(
        `pu.joined_at >= $${members_stats_params.length + 1}`,
      );
      members_stats_params.push(from);
    }
    if (to) {
      members_stats_where.push(
        `pu.joined_at < $${members_stats_params.length + 1}`,
      );
      members_stats_where.push(
        `(pu.left_at IS NULL OR pu.left_at >= $${
          members_stats_params.length + 1
        })`,
      );
      members_stats_params.push(to);
    } else {
      members_stats_where.push(`pu.left_at IS NULL`);
    }

    const members = await this.projectRepo.manager.query(
      `SELECT COUNT(*) members
       FROM project_users pu
       WHERE pu.project_id = $1
         ${
           members_stats_where.length > 0
             ? 'AND ' + members_stats_where.join(' AND ')
             : ''
         }
      `,
      members_stats_params,
    );
    return parseInt(members[0].members);
  }

  async getViewsStats(
    projectId: string,
    from: Date,
    to: Date,
  ): Promise<ProjectStatsParameterDTO[]> {
    const views = await this.projectRepo.manager.query(
      `SELECT created_at::date date, COUNT(*) as value
        FROM project_views
        WHERE project_id = $1
          AND created_at >= $2::date
          AND created_at < $3::date + interval '1 day'
        GROUP BY created_at::date
        ORDER BY created_at::date
      `,
      [decodeBigNumberKey(projectId), from, to],
    );
    return views.map((v) => {
      return {
        date: v.date.toISOString().split('T')[0],
        value: parseInt(v.value),
      };
    });
  }

  async getVisitorsStats(
    projectId: string,
    from: Date,
    to: Date,
  ): Promise<ProjectStatsParameterDTO[]> {
    const visitors = await this.projectRepo.manager.query(
      ` SELECT date, COUNT(*) as value
        FROM (
                SELECT DISTINCT created_at::date as date, ip
                FROM project_views
                WHERE project_id = $1
                AND created_at >= $2::date
                AND created_at < $3::date + interval '1 day'
            ) x
        GROUP BY date
        ORDER BY date
      `,
      [decodeBigNumberKey(projectId), from, to],
    );
    return visitors.map((v) => {
      return {
        date: v.date.toISOString().split('T')[0],
        value: parseInt(v.value),
      };
    });
  }
}
