import { Injectable, InternalServerErrorException, Logger, OnModuleInit } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { PaperOrder, PaperOrderStatus } from './entities/paper-order.entity'
import { Repository } from 'typeorm'
import { PaperGenResult } from './entities/paper-gen-result.entity'
import { Pagination, paginate } from 'nestjs-typeorm-paginate'
import { PageRequest } from 'src/common/dto/page-request'
import { CreatePaperOrderDto } from './dto/create-order.dto'
import { genPaper } from './paper-gen'
import { genGeneralPaper1 } from './paper-gen/general'
import { createLLM } from './paper-gen/llm'
import { genChapters } from './paper-gen/chapter'

@Injectable()
export class PaperService implements OnModuleInit {
    constructor(
        @InjectRepository(PaperOrder)
        private readonly paperOrderRepository: Repository<PaperOrder>,
        @InjectRepository(PaperGenResult)
        private readonly paperGenResultRepository: Repository<PaperGenResult>
    ) {}

    async onModuleInit() {
        for (const order of await this.paperOrderRepository.findBy({
            status: PaperOrderStatus.Generating
        })) {
            if (
                (await this.paperGenResultRepository.countBy({
                    orderId: order.id
                })) === 0
            ) {
                order.status = PaperOrderStatus.Pending
            } else {
                order.status = PaperOrderStatus.Complete
            }
            await this.paperOrderRepository.save(order)
        }
    }

    async findAllOrders(req: PageRequest<PaperOrder>) {
        return await paginate<PaperOrder>(this.paperOrderRepository, req.page, req.search)
    }

    async findOrderById(id: number): Promise<PaperOrder> {
        return await this.paperOrderRepository.findOneByOrFail({
            id
        })
    }

    async findAllResults(req: PageRequest<PaperGenResult>) {
        return await paginate<PaperGenResult>(this.paperGenResultRepository, req.page, req.search)
    }

    async createOrder(dto: CreatePaperOrderDto) {
        return await this.paperOrderRepository.save(dto)
    }

    async updateOrder(id: number, data) {
        return await this.paperOrderRepository.update(id, data)
    }

    async gen(orderId: number) {
        const order = await this.findOrderById(orderId)
        if (order.status === PaperOrderStatus.Generating) {
            throw new InternalServerErrorException('正在生成中，请稍后再试')
        }
        order.status = PaperOrderStatus.Generating
        await this.paperOrderRepository.save(order)
        this.genPaper(order)
    }

    async genChapters(major: string, title: string, description: string) {
        const tools = createLLM('gpt-3.5-turbo')
        const chapters = await genChapters(tools, major, title, description)
        return chapters
    }

    async genPaper(order: PaperOrder) {
        try {
            let content, duration, tokenUsage, fileUrl
            if (/计算机/.test(order.major)) {
                ;({ content, duration, tokenUsage, fileUrl } = await genPaper(order.title, order.description))
            } else {
                ;({ content, duration, tokenUsage, fileUrl } = await genGeneralPaper1(
                    order.major,
                    order.title,
                    order.description,
                    order.chapters
                ))
            }
            await this.paperGenResultRepository.save({
                orderId: order.id,
                content,
                duration,
                tokenUsage,
                fileUrl
            })
            order.status = PaperOrderStatus.Complete
            await this.paperOrderRepository.save(order)
        } catch (error) {
            Logger.error('生成论文失败', error.stack)
            order.status = PaperOrderStatus.Pending
            await this.paperOrderRepository.save(order)
        }
    }
}
