import { Injectable } from '@nestjs/common';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { Bid } from '../bids/entities/bid.entity';
import { BotTelegramApi } from '../bids/apis/bot-telegram.api';
import { InjectRepository } from '@nestjs/typeorm';
import { Notification } from './entities/notification.entity';
import { LEGAL_TCP_SOCKET_OPTIONS, Repository } from 'typeorm';
import { isTimeReached } from '@/ultils';
import {
  FilterOperator,
  FilterSuffix,
  paginate,
  PaginateQuery,
} from 'nestjs-paginate';
import { Column } from 'nestjs-paginate/lib/helper';
import AppResponse from '@/response/app-response';
import { SendMessageHistoriesService } from '../bids/services/send-message-histories.service';
import { SendMessageHistory } from '../bids/entities/send-message-histories.entity';
import { Event } from '../bids/utils/events';

@Injectable()
export class NotificationService {
  constructor(
    private eventEmitter: EventEmitter2,
    private readonly botTelegramApi: BotTelegramApi,
    @InjectRepository(Notification)
    readonly notificationRepo: Repository<Notification>,
    @InjectRepository(SendMessageHistory)
    readonly sendMessageRepo: Repository<SendMessageHistory>,
  ) {}

  async index(query: PaginateQuery) {
    const filterableColumns: {
      [key in Column<Bid> | (string & {})]?:
        | (FilterOperator | FilterSuffix)[]
        | true;
    } = {
      id: true,
      message: true,
    };

    query.filter = AppResponse.processFilters(query.filter, filterableColumns);

    const data = await paginate(query, this.notificationRepo, {
      sortableColumns: ['id'],
      searchableColumns: ['id'],
      defaultLimit: 15,
      filterableColumns,
      defaultSortBy: [['id', 'DESC']],
      maxLimit: 100,
    });

    return AppResponse.toPagination<Notification>(data, true, Notification);
  }

  getBidStatusMessage(bid: Bid): string | null {
    const itemName = `*${bid.name || 'the item'}*`;

    switch (bid.status) {
      case 'biding':
        return !bid.name ? null : `✅ The item has been activated. ${bid.name}`;

      case 'out-bid':
        if (isTimeReached(bid.close_time)) {
          return `⏳ The auction for *${bid.name || 'this item'}* has ended.`;
        }

        if (
          bid.max_price + bid.plus_price <= bid.current_price ||
          bid.reserve_price > bid.max_price + bid.plus_price
        ) {
          return `💰 The current bid for ${itemName} has exceeded your maximum bid.`;
        }

        return `🛑 The auction for ${itemName} has been canceled.`;

      case 'win-bid':
        return `🎉 Congratulations! You won the auction for ${itemName} at *${bid.current_price}*.`;

      default:
        return '❓ Unknown auction status.';
    }
  }

  async emitBidStatus(bid: Bid, sendTo: boolean = true) {
    const groupData = await this.botTelegramApi.getGroupInfo();
    const sendToData = groupData && sendTo ? [groupData?.title || 'None'] : [];

    const message = this.getBidStatusMessage(bid);
    if (!message) return;

    if (bid.status === 'win-bid') {
      const prevSendMessage = await this.sendMessageRepo.findOne({
        where: { bid: { id: bid.id }, type: 'win-bid' },
      });

      if (prevSendMessage) return;
    }

    const notification = await this.notificationRepo.save({
      message,
      raw_data: JSON.stringify({
        id: bid.id,
        status: bid.status,
        name: bid.name,
        close_time: bid.close_time,
        current_price: bid.current_price,
      }),
      send_to: JSON.stringify(sendToData),
    });

    try {
      const prevAnyMessage = await this.sendMessageRepo.findOne({
        where: {
          bid: { id: bid.id },
          message: notification.message,
          type: bid.status,
          max_price: bid.max_price,
          reserve_price: bid.reserve_price,
        },
      });

      if (prevAnyMessage) return;

      await this.sendMessageRepo.save({
        bid: { id: bid.id },
        message: notification.message,
        type: bid.status,
        max_price: bid.max_price,
        reserve_price: bid.reserve_price,
      });

      this.eventEmitter.emit(Event.BID_STATUS, {
        bid: {
          ...bid,
          // status: 'out-bid',
        },
        notification,
      });
    } catch (error) {
      console.log(
        '%csrc/modules/notification/notification.service.ts:131 Error',
        'color: #007acc;',
        Error,
      );
    }
  }
}
