import { Injectable } from '@nestjs/common';
import * as moment from 'jalali-moment';
import { InjectRepository } from '@nestjs/typeorm';
import {
  applyFiltersToBuilder,
  applySortingToBuilder,
  paginationResult,
} from '../../utils';
import { Repository } from 'typeorm';
import {
  AnnouncementEntity,
  AnnouncementSections,
} from './entities/announcement.entity';
import { CreateAnnouncementDto } from './dto/create-announcement.dto';
import { UpdateAnnouncementDto } from './dto/update-announcement.dto';
import { getLastDisplayOrder } from '../../utils/last-display-order';

@Injectable()
export class AnnouncementService {
  constructor(
    @InjectRepository(AnnouncementEntity)
    private announcementRepository: Repository<AnnouncementEntity>,
  ) {}

  /**
   * -------------------------------------------------------
   */
  async getByIdForAdmin(id: number) {
    return await this.announcementRepository
      .createQueryBuilder()
      .where({ id })
      .getOne();
  }

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

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

    builder = applyFiltersToBuilder(builder, filters);

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

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

  /**
   * -------------------------------------------------------
   */
  async getAll(section: AnnouncementSections = null) {
    const builder = this.announcementRepository
      .createQueryBuilder()
      .andWhere(
        '((startDate IS NULL AND endDate IS NULL) OR (startDate <= :currentDate AND endDate >= :currentDate))',
        { currentDate: moment().format('YYYY-MM-DD') },
      )
      .andWhere({ isPublished: true })
      .orderBy('displayOrder', 'ASC');

    if (section) {
      builder.andWhere('(section IS NULL OR section = :section)', { section });
    }

    return await builder.getMany();
  }

  /**
   * -------------------------------------------------------
   */
  async create(dto: CreateAnnouncementDto) {
    return await this.announcementRepository
      .createQueryBuilder()
      .insert()
      .values({
        ...dto,
        displayOrder: await getLastDisplayOrder(AnnouncementEntity.name),
        createdAt: new Date(),
        updatedAt: new Date(),
      })
      .execute();
  }

  /**
   * -------------------------------------------------------
   */
  async updateById(dto: UpdateAnnouncementDto) {
    this.announcementRepository
      .createQueryBuilder()
      .update()
      .set({ ...dto, updatedAt: new Date() })
      .where({ id: dto.id })
      .execute();
  }

  /**
   * -------------------------------------------------------
   */
  async delete(id: number) {
    return await this.announcementRepository
      .createQueryBuilder()
      .delete()
      .where({ id })
      .execute();
  }
}
