import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { ErrorService } from '../../error/error.service';
import { Repository } from 'typeorm';
import { PollEntity } from './entities/poll.entity';
import { CreatePollItemDto } from './dto/create-poll-item.dto';
import { UpdatePollItemDto } from './dto/update-poll-item.dto';
import { PollItemEntity } from './entities/poll-item.entity';
import {
  applyFiltersToBuilder,
  applySortingToBuilder,
  paginationResult,
} from '../../utils';
import { json } from 'stream/consumers';

@Injectable()
export class PollService {
  constructor(
    @InjectRepository(PollEntity)
    private pollRepository: Repository<PollEntity>,
    @InjectRepository(PollItemEntity)
    private pollItemRepository: Repository<PollItemEntity>,
    private error: ErrorService,
  ) {}

  /**
   * -------------------------------------------------------
   */
  async getAll(page = 1, limit = 20, filters = null, sorts = null) {
    let builder = this.pollRepository
      .createQueryBuilder('poll')
      .leftJoin('poll.user', 'user')
      .select([
        'poll.id',
        'poll.orderId',
        'poll.isService',
        'poll.star',
        'poll.createdAt',
        'user.id',
        'user.name',
        'user.surName',
      ])
      .take(limit)
      .skip((page - 1) * limit);

    if (sorts) {
      builder = applySortingToBuilder(builder, sorts);
    } else {
      builder.orderBy('poll.id', 'DESC');
    }

    builder = applyFiltersToBuilder(builder, filters);

    const [items, totalItems] = await builder.getManyAndCount();

    return {
      items,
      pagination: paginationResult(page, limit, totalItems),
    };
  }

  /**
   * -------------------------------------------------------
   */
  async getById(id: number) {
    return await this.pollRepository.findOne(id);
  }

  /**
   * -------------------------------------------------------
   */
  async getAllItems(page = 1, limit = 20, filters = null, sorts = null) {
    let builder = this.pollItemRepository
      .createQueryBuilder('poll_items')
      .take(limit)
      .skip((page - 1) * limit);

    if (sorts) {
      builder = applySortingToBuilder(builder, sorts);
    } else {
      builder.orderBy('poll_items.id', 'ASC');
    }

    builder = applyFiltersToBuilder(builder, filters);

    const [items, totalItems] = await builder.getManyAndCount();

    return {
      items,
      pagination: paginationResult(page, limit, totalItems),
    };
  }

  /**
   * -------------------------------------------------------
   */
  async getItemById(id: number) {
    return await this.pollItemRepository.findOne(id);
  }

  /**
   * -------------------------------------------------------
   */
  async createItem(dto: CreatePollItemDto) {
    const { identifiers } = await this.pollItemRepository
      .createQueryBuilder()
      .insert()
      .values(dto)
      .execute();

    const newId = identifiers[0].id;
    return await this.pollItemRepository.findOne(newId);
  }

  /**
   * -------------------------------------------------------
   */
  async updateItem(id: number, dto: UpdatePollItemDto) {
    return await this.pollItemRepository
      .createQueryBuilder()
      .update()
      .set(dto)
      .where({ id })
      .execute();
  }

  /**
   * -------------------------------------------------------
   */
  async deleteItem(id: number) {
    return await this.pollItemRepository.delete(id);
  }

  /**
   * -------------------------------------------------------
   */
  async statistic(filters = null) {
    let builder = this.pollRepository.createQueryBuilder('poll');
    builder.select([
      'poll.id',
      'poll.star',
      'poll.positiveItems',
      'poll.negativeItems',
    ]);

    builder = applyFiltersToBuilder(builder, filters);
    const items = await builder.getMany();

    const result = { positiveItems: {}, negativeItems: {} };
    const stars = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 };

    items.forEach((item) => {
      stars[item.star] += 1;

      ['positiveItems', 'negativeItems'].forEach((field) => {
        const pnItems = JSON.parse(item[field] || '[]');

        pnItems.forEach((positiveItem) => {
          if (result[field][positiveItem]) {
            result[field][positiveItem] += 1;
          } else {
            result[field][positiveItem] = 1;
          }
        });
      });
    });

    const finalResult = { positiveItems: [], negativeItems: [] };
    ['positiveItems', 'negativeItems'].forEach((field) => {
      Object.entries(result[field]).forEach(([label, value]) => {
        finalResult[field].push({ label, value });
      });
      finalResult[field].sort((a, b) => b.value - a.value);
    });

    return { ...finalResult, stars };
  }
}
