import {
    Injectable,
    NotFoundException,
    BadRequestException,
} from '@nestjs/common'
import { In, Repository, UpdateResult } from 'typeorm'
import { InjectRepository } from '@nestjs/typeorm'
import { ChatRole } from './entities/chat-role.entity'
import { ChatRoleDto } from './dto/chat-role.dto'
import { paginate, Pagination } from 'nestjs-typeorm-paginate'
import { PageRequest } from '../common/dto/page-request'
import { LabelService } from '../label/label.service'

@Injectable()
export class ChatRoleService {
    constructor(
        @InjectRepository(ChatRole)
        private readonly chatRoleRepository: Repository<ChatRole>,
        private readonly labelService: LabelService
    ) { }

    async findAll(req: PageRequest<ChatRole>): Promise<Pagination<ChatRole>> {
        return await paginate<ChatRole>(this.chatRoleRepository, req.page, req.search)
    }

    async findByPlayerName(playerName: string): Promise<ChatRole> {
        const chatRole = await this.chatRoleRepository.findOneBy({ playerName: playerName })
        if (!chatRole) {
            throw new NotFoundException(`Associated ChatRole ${playerName} not found`)
        }
        return chatRole
    }

    async findMapByIds(ids: number[]): Promise<Map<number, ChatRole>> {
        const chatRoleList = await this.chatRoleRepository.createQueryBuilder('chatRole')
            .where({
                id: In(ids),
            }).getMany();

        const chatRoleMap = new Map<number, ChatRole>();
        for (let i = 0; i < chatRoleList.length; i++) {
            const chatRole = chatRoleList[i];
            const roleLabelList = await this.labelService.getRoleLabeltList(chatRole.id);

            const labels: string[] = [];
            roleLabelList.forEach(c => {
                labels.push(c.describe);
            });
            chatRole.labels = labels;
            chatRoleMap.set(chatRole.id, chatRole);
        }

        return chatRoleMap
    }

    async randomQuery(num: number): Promise<ChatRole[]> {
        return await this.chatRoleRepository.createQueryBuilder().orderBy("RAND()").limit(num).getMany()
    }

    public async create(chatRoleDto: ChatRoleDto) {
        const result = await this.chatRoleRepository.save(chatRoleDto)
        if (Array.isArray(chatRoleDto.labelList) && chatRoleDto.labelList.length > 0) {
            this.labelService.addRoleLabel(result.id, chatRoleDto.labelList)
        }
        return result;
    }

    public async findById(id: number): Promise<ChatRole> {
        const chatRole = await this.chatRoleRepository.findOneBy({
            id: +id
        })

        if (!chatRole) {
            throw new NotFoundException(`ChatRole #${id} not found`)
        }

        const roleLabelList = await this.labelService.getRoleLabeltList(id)
        const labels: string[] = []
        roleLabelList.forEach((c) => {
            labels.push(c.describe)
        })
        chatRole.labels = labels
        return chatRole
    }

    public async update(id: number, dto: ChatRoleDto): Promise<UpdateResult> {

        try {
            const chatRole = await this.chatRoleRepository.update(
                {
                    id: +id
                },
                { ...dto }
            )

            const oleList = await this.labelService.getRoleLabeltList(id)
            await this.labelService.delRoleLabel(oleList)
            this.labelService.addRoleLabel(id, dto.labelList)

            return chatRole
        } catch (err) {
            throw new BadRequestException('ChatRole not updated')
        }
    }

    public async delete(id: number): Promise<void> {
        const chatRole = await this.findById(id)
        await this.chatRoleRepository.remove(chatRole)
    }

}