import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { ErrorService } from '../../error/error.service';
import {
  applyFiltersToBuilder,
  applySortingToBuilder,
  paginationResult,
} from '../../utils';
import { Repository } from 'typeorm';
import { CategoryEntity } from './entities/category.entity';
import { UpdateCategoryDto } from './dto/update-category.dto';
import { CreateCategoryDto } from './dto/create-category.dto';
import { getLastDisplayOrder } from 'src/utils/last-display-order';

@Injectable()
export class CategoryService {
  constructor(
    @InjectRepository(CategoryEntity)
    private categoryRepository: Repository<CategoryEntity>,

    private error: ErrorService,
  ) {}

  /**
   * -------------------------------------------------------
   */
  async getAll(page = 1, limit = 20, filters = null, sorts = null) {
    let builder = this.categoryRepository
      .createQueryBuilder('category')
      .andWhere({ deleted: false })
      .take(limit)
      .skip((page - 1) * limit);

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

    builder = applyFiltersToBuilder(builder, filters);

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

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

  /**
   * -------------------------------------------------------
   */
  async getFull(filters = null) {
    let builder = this.categoryRepository
      .createQueryBuilder('category')
      .select(['category.id', 'category.name']);

    builder = applyFiltersToBuilder(builder, filters);

    return await builder.getMany();
  }

  /**
   * -------------------------------------------------------
   */
  async getById(id: number) {
    return await this.categoryRepository
      .createQueryBuilder('category')
      .andWhere({ id })
      .andWhere({ deleted: false })
      .getOne();
  }

  /**
   * -------------------------------------------------------
   */
  async updateById(id: number, values: any) {
    return await this.categoryRepository
      .createQueryBuilder()
      .update()
      .set({ ...values, updatedAt: new Date() })
      .where({ id })
      .execute();
  }

  /**
   * -------------------------------------------------------
   */
  async updateCategory(
    id: number,
    dto: UpdateCategoryDto,
    image: Express.Multer.File,
  ) {
    if (image) {
      dto.image = `/uploads/categories/${image.filename}`;
    }
    return await this.updateById(id, dto);
  }

  /**
   * -------------------------------------------------------
   */
  async addCategory(dto: CreateCategoryDto, image: Express.Multer.File) {
    const newCategory = new CategoryEntity();
    for (const key in dto) {
      newCategory[key] = dto[key];
    }

    newCategory.image = `/uploads/categories/${image.filename}`;
    newCategory.displayOrder = await getLastDisplayOrder(CategoryEntity.name);

    newCategory.createdAt = new Date();
    newCategory.updatedAt = new Date();

    const { identifiers } = await this.categoryRepository
      .createQueryBuilder()
      .insert()
      .values(newCategory)
      .execute();

    const newCategoryId = identifiers[0].id;
    return await this.getById(newCategoryId);
  }

  /**
   * -------------------------------------------------------
   */
  async deleteCategory(id: number) {
    return await this.updateById(id, { deleted: true });
  }
}
