import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import {
  applyFiltersToBuilder,
  applySortingToBuilder,
  paginationResult,
} from 'src/utils';
import { User } from 'src/utils/decorators/user.decorator';
import { IsNull, Repository } from 'typeorm';
import { ErrorService } from '../../error/error.service';
import { CreateTicketDto } from './dto/create-ticket.dto';
import { UpdateTicketDto } from './dto/update-ticket.dto';
import {
  TicketCategory,
  TicketCategoryList,
  TicketEntity,
} from './entities/ticket.entity';

@Injectable()
export class TicketService {
  constructor(
    @InjectRepository(TicketEntity)
    private ticketRepository: Repository<TicketEntity>,
    private error: ErrorService,
  ) {}

  /**
   * -------------------------------------------------------
   * Admin
   * Get ticket list
   */
  async getAll(page = 1, limit = 20, sorts = null, filters = null) {
    let builder = this.ticketRepository.createQueryBuilder('ticket');

    builder.leftJoin('ticket.user', 'user');

    builder.select([
      'ticket.id',
      'ticket.parentId',
      'ticket.userId',
      'ticket.title',
      'ticket.category',
      'ticket.sendAdmin',
      'ticket.createdAt',

      'user.id',
      'user.name',
      'user.surName',
    ]);

    builder.addSelect('ticket.isReade', 'isReaded');
    builder.addSelect('ticket.isClose', 'isClosed');

    builder = applyFiltersToBuilder(builder, filters);

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

    builder.andWhere('ticket.parentId IS NULL');

    const [items, totalItems] = await builder
      .take(limit) // LIMIT
      .skip((page - 1) * limit) // OFFSET
      .getManyAndCount();

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

  /**
   * -------------------------------------------------------
   * Admin
   * Get ticket by id
   */
  async getAllByParentId(id: number) {
    const builder = this.ticketRepository.createQueryBuilder('ticket');

    builder.leftJoin('ticket.user', 'user');

    builder.select([
      'ticket.id',
      'ticket.parentId',
      'ticket.userId',
      'ticket.title',
      'ticket.category',
      'ticket.description',
      'ticket.image',
      'ticket.sendAdmin',
      'ticket.createdAt',

      'user.id',
      'user.name',
      'user.surName',
      'user.mobile',
      'user.email',
    ]);

    builder.addSelect('ticket.isReade', 'isReaded');
    builder.addSelect('ticket.isClose', 'isClosed');

    builder.andWhere('(ticket.id = :tId OR ticket.parentId = :tId)', {
      tId: id,
    });
    builder.orderBy('ticket.createdAt', 'ASC');

    const items = await builder.getMany();
    return items;
  }

  /**
   * -------------------------------------------------------
   * Admin
   * add ticket (reply)
   */
  async addTicket(userId: string, dto: CreateTicketDto) {
    const foundParent = await this.ticketRepository.findOne({
      id: dto.parentId,
      parentId: null,
    });

    if (!foundParent) {
      this.error.unprocessableEntity(['اطلاعات ورودی نامعتبر می‌باشند']);
    }

    // Inserting a new child record
    const newTicket = new TicketEntity();

    newTicket.parentId = dto.parentId;
    newTicket.userId = userId;
    newTicket.sendAdmin = true;
    newTicket.title = foundParent.title;
    newTicket.description = dto.description;
    newTicket.createdAt = new Date();
    newTicket.updatedAt = new Date();

    const { identifiers } = await this.ticketRepository
      .createQueryBuilder()
      .insert()
      .values(newTicket)
      .execute();

    // Updating the parent
    foundParent.isClose = dto.isClosed;
    await foundParent.save();

    // Finding the last child
    const ticketId = identifiers[0].id;
    return await this.getAllByParentId(ticketId);
  }

  /**
   * -------------------------------------------------------
   * Admin
   * update ticket
   */
  async updateById(id: number, dto: UpdateTicketDto) {
    const values: any = {};

    if (dto.isReaded !== undefined) {
      values.isReade = dto.isReaded;
    }
    if (dto.isClosed !== undefined) {
      values.isClose = dto.isClosed;
    }
    if (dto.category !== undefined) {
      values.category = dto.category;
    }
    console.log('values', values);

    return await this._update(id, values);
  }

  /**
   * -------------------------------------------------------
   * get category list
   */
  getCategoryList() {
    return TicketCategoryList;
  }

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

  /**
   * -------------------------------------------------------
   */
  async statistic() {
    const unReaded = await this.ticketRepository
      .createQueryBuilder()
      .where('(isReade = 0 OR isReade IS NULL)')
      .andWhere('parentId IS NULL')
      .getCount();

    return { unReaded };
  }

  //   ------------------------------------------------------

  // private _findAdminBuilder() {
  //   return this.userRepository
  //     .createQueryBuilder('user')
  //     .andWhere({ isActive: true })
  //     .andWhere({ roleId: RoleIds.Admin });
  // }

  //   ------------------------------------------------------

  //   async getAdminByEmailOrMobile(emailOrMobile: string) {
  //     return await this._findAdminBuilder()
  //       .andWhere('(user.email = :eom OR user.mobile = :eom)', {
  //         eom: emailOrMobile,
  //       })
  //       .getOne();
  //   }

  //   async findAdminById(userId: string) {
  //     return await this._findAdminBuilder().andWhere({ id: userId }).getOne();
  //   }
}
