import { Injectable } from '@nestjs/common';
import { BaseDataService } from 'src/core/modules/data/service/base-data.service';
import { InjectRepository } from '@nestjs/typeorm';
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
import { In, Repository } from 'typeorm';
import { QueueTicket } from '../../domain/entities/ticket.entity';
import {
  QueueItemModel,
  QueueOrderModel,
  QueueTicketModel,
} from '../models/queue.model';
import { QueueOrder } from '../../domain/entities/order.entity';

@Injectable()
export class TicketDataService extends BaseDataService<QueueTicket> {
  constructor(
    @InjectRepository(QueueTicketModel, CONNECTION_NAME.DEFAULT)
    private repo: Repository<QueueTicketModel>,

    @InjectRepository(QueueOrderModel, CONNECTION_NAME.DEFAULT)
    private order: Repository<QueueOrderModel>,

    @InjectRepository(QueueItemModel, CONNECTION_NAME.DEFAULT)
    private item: Repository<QueueItemModel>,
  ) {
    super(repo);
  }

  async createQueueOrder(order: QueueOrder): Promise<QueueOrderModel> {
    return await this.order.save(order);
  }

  async loginQueue(id: string): Promise<QueueOrder> {
    return this.order.findOneOrFail({
      relations: ['tickets'],
      where: {
        transaction_id: id,
      },
    });
  }

  async orders(order_id: string): Promise<QueueOrderModel[]> {
    const order = await this.order.findOneOrFail({
      where: {
        id: order_id,
      },
    });

    if (order.transaction_id != null) {
      return this.order.find({
        where: {
          code: order.code,
        },
      });
    }

    return [order];
  }

  async orderIds(order_id: string): Promise<string[]> {
    const orders = await this.orders(order_id);

    return orders.map((order) => order.id);
  }

  async orderItems(
    order_id: string,
    item_ids: string[],
  ): Promise<QueueOrderModel> {
    const order = await this.orderIds(order_id);
    return this.order.findOneOrFail({
      relations: ['tickets', 'tickets.items'],
      where: {
        tickets: {
          order_id: In(order),
          items: {
            id: In(item_ids),
          },
        },
      },
    });
  }

  async queueTickets(order_id: string): Promise<QueueTicketModel[]> {
    const order = await this.orderIds(order_id);
    return this.repo.find({
      relations: [
        'items',
        'items.queue',
        'items.item',
        'items.item.item_queue',
      ],
      where: {
        order_id: In(order),
      },
    });
  }

  async queueTicketItems(
    order_id: string,
    ticket_id: string,
  ): Promise<QueueTicketModel[]> {
    const order = await this.orderIds(order_id);
    return this.repo.find({
      relations: [
        'items',
        'items.queue',
        'items.item',
        'items.item.item_queue',
      ],
      where: {
        order_id: In(order),
        id: ticket_id,
      },
    });
  }

  async queueItemTickets(
    order_id: string,
    item_id: string,
  ): Promise<QueueTicketModel[]> {
    const order = await this.orderIds(order_id);
    return this.repo.find({
      relations: [
        'items',
        'items.queue',
        'items.item',
        'items.item.item_queue',
      ],
      where: {
        order_id: In(order),
        items: [{ item_id }, { item: { item_queue: { id: item_id } } }],
      },
    });
  }

  async queueItems(order_id: string): Promise<QueueItemModel[]> {
    const order = await this.orderIds(order_id);
    return this.item.find({
      relations: ['queue', 'ticket'],
      where: {
        ticket: {
          order_id: In(order),
        },
      },
    });
  }
}
