import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import {
  applyFiltersToBuilder,
  applySortingToBuilder,
  paginationResult,
} from 'src/utils';
import { getLastDisplayOrder } from 'src/utils/last-display-order';
import { Repository } from 'typeorm';
import { LogAction, LogType } from '../log/log.interface';
import { LogService } from '../log/log.service';
import { CreateCustomerrDto } from './dto/create-customer.dto';
import { UpdateCustomerDto } from './dto/update-customer.dto';
import { CustomerEntity } from './entities/customer.entity';

@Injectable()
export class CustomerService {
  constructor(
    @InjectRepository(CustomerEntity)
    private customerRepository: Repository<CustomerEntity>,

    private logService: LogService,
  ) {}

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

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

    builder = applyFiltersToBuilder(builder, filters);

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

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

  /**
   * -------------------------------------------------------
   */
  async getCustomerById(id: number) {
    return await this.customerRepository
      .createQueryBuilder('customer')
      .andWhere({ id })
      .getOne();
  }

  /**
   * -------------------------------------------------------
   * Admin
   * update Customer
   */
  async updateCustomer(
    id: number,
    dto: UpdateCustomerDto,
    image: Express.Multer.File,
    operatorUserId: string,
  ) {
    const customer = await this.getCustomerById(id);

    if (image) {
      dto.image = `/uploads/companies/${image.filename}`;
    }
    const data = await this.customerRepository
      .createQueryBuilder()
      .update()
      .set({ ...dto, updatedAt: new Date() })
      .where({ id })
      .execute();

    // Adding a log
    await this.logService.add({
      type: LogType.customer,
      action: LogAction.update,
      operatorUserId,
      message: `مشتری ${dto.name} آپدیت شد.`,
      affectedId: String(id),
      item: customer,
    });

    return data;
  }

  /**
   * -------------------------------------------------------
   */
  async addCustomer(
    dto: CreateCustomerrDto,
    image: Express.Multer.File,
    operatorUserId: string,
  ) {
    const newCustomer = new CustomerEntity();
    for (const key in dto) {
      newCustomer[key] = dto[key];
    }

    newCustomer.image = `/uploads/companies/${image.filename}`;
    newCustomer.displayOrder = await getLastDisplayOrder(CustomerEntity.name);

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

    const { identifiers } = await this.customerRepository
      .createQueryBuilder()
      .insert()
      .values(newCustomer)
      .execute();

    const newCustomerId = identifiers[0].id;
    const data = await this.customerRepository.findOne(newCustomerId);

    // Adding a log
    await this.logService.add({
      type: LogType.customer,
      action: LogAction.insert,
      operatorUserId,
      message: `مشتری ${newCustomer.name} اضافه شد.`,
      affectedId: newCustomerId,
      item: newCustomer,
    });

    return data;
  }

  /**
   * -------------------------------------------------------
   * DELETE /customers/1/admin
   */
  async deleteCustomer(id: number, operatorUserId: string) {
    const customer = await this.customerRepository.findOne(id);

    const data = await this.customerRepository
      .createQueryBuilder()
      .update()
      .set({ deleted: true, updatedAt: new Date() })
      .where({ id })
      .execute();

    // Adding a log
    await this.logService.add({
      type: LogType.customer,
      action: LogAction.delete,
      operatorUserId,
      message: `مشتری ${customer.name} حذف شد.`,
      affectedId: String(id),
      item: customer,
    });

    return data;
  }
}
