import {
    HttpException,
    HttpStatus,
    Injectable,
} from '@nestjs/common';

import * as dto from './dto/index';
import { Types } from 'mongoose';
import { ModelService } from '../model/model.service';
import { CommonService } from '../common/common.service';
import { RagService } from '../rag/rag.service';
import { CallService } from '../call/call.service';
import { KnowledgeService } from '../knowledge_base/knowledge.service';

@Injectable()
export class ChatService {
    constructor(
        private readonly Model: ModelService,
        private readonly CommonService: CommonService,
        private readonly RagService: RagService,
        private readonly CallService: CallService,
        private readonly KnowledgeService: KnowledgeService,
    ) {
    }


    async chat_with_ai(body: dto.chat.chatPost) {
        try {
            let { chat_id, text, agent_id, secret_key } = body
            const find_workspace_key = await this.Model.workspaceKeysModel.findOne({ key: secret_key?.toLowerCase(), is_delete: false })
            if (!find_workspace_key) throw new HttpException('scret key not found', HttpStatus.BAD_REQUEST)

                console.log('find_workspace_key.workspace_id', find_workspace_key.workspace_id)
            const subscription = await this.Model.subscriptionModel.findOne({
                workspace_id: find_workspace_key.workspace_id,
                is_active: true
            });
            if (!subscription) throw new HttpException(`You don’t have an active subscription plan. Please purchase a subscription to continue.`, HttpStatus.BAD_REQUEST);

            console.log('subscription.chat_token_limit_left', subscription.chat_token_limit_left)

            if (subscription.chat_token_limit_left <= 0) {
                throw new HttpException(`You have reached your chat token limit. Please upgrade your plan to continue.`, HttpStatus.BAD_REQUEST);
            }

            const user_details: any = {};
            if (!chat_id) {
                let chat_create = await this.Model.CallModel.create({
                    type: "CHAT", last_message: text,
                    workspace_id: find_workspace_key?.workspace_id,
                    agent_id: new Types.ObjectId(agent_id),
                    created_at: +new Date()
                })
                chat_id = chat_create._id.toString()
            } else {
                const chat_detail = await this.Model.CallModel.findByIdAndUpdate(new Types.ObjectId(chat_id), { last_message: text }, { new: true });
                user_details.name = chat_detail.name,
                user_details.email = chat_detail.email
            }

            await this.save_chat({ role: "user", text: text, chat_id: chat_id })
            let chat_history = await this.chat_history_for_chat(chat_id)
            console.time("CHAT TIME")
            const rag_response = await this.KnowledgeService.getAnswerKnowledgeBaseChat(text, chat_history, agent_id, subscription._id, subscription.chat_token_limit_left, user_details)
            console.timeEnd("CHAT TIME")

            await this.save_chat({ role: "model", text: rag_response?.answer, chat_id: chat_id })
            return { chat_id: chat_id, ai_response: rag_response?.answer }
        } catch (error) {
            throw error
        }
    }

    async chat_with_ai_landing_page(body: dto.chat.chatPost) {
        try {
            let { chat_id, text, secret_key } = body;
            console.log('chat_id, text, secret_key', chat_id, text, secret_key)
            let find_workspace_key = await this.Model.workspaceKeysModel.findOne({ key: secret_key?.toLowerCase(), is_delete: false })
            console.log('find_workspace_key', find_workspace_key)
            if (!find_workspace_key) throw new HttpException('scret key not found', HttpStatus.BAD_REQUEST)
            const agent_id = await this.CallService.get_default_agent_id("WEB");
            console.log('agent_id', agent_id)

            if (!chat_id) {
                let chat_create = await this.Model.CallModel.create({
                    type: "CHAT", last_message: text,
                    workspace_id: find_workspace_key?.workspace_id,
                    agent_id: new Types.ObjectId(agent_id),
                    created_at: +new Date()
                })
                chat_id = chat_create._id.toString()
            } else {
                await this.Model.CallModel.findByIdAndUpdate(new Types.ObjectId(chat_id), { last_message: text })
            }

            console.log('chat_id ==========> ', chat_id)


            console.time("CHAT TIME")
            const chat_req = {
                query: text,
                chat_id: chat_id,
                secret_key: secret_key,
                voice: ""
            }
            const rag_response = await this.KnowledgeService.getAnswerForLandingPageV2(chat_req, "CHAT")
            console.timeEnd("CHAT TIME")

            console.log('rag_response', rag_response)
            return { chat_id: chat_id, ai_response: rag_response?.answer }
        } catch (error) {
            throw error
        }
    }

    async chat_history_for_chat(chat_id: string) {
        try {
            // let call = await this.model.CallModel.findOne({ _id: chat_id })
            let chatData = await this.Model.CallTranscriptModel.find({ call_id: new Types.ObjectId(chat_id), }, { role: 1, text: 1, _id: 0 }, { sort: { _id: 1 } }).limit(10)
            console.log('chatData.length =>>>>>>>', chatData)
            let chat = chatData
                .map((message) => `${message.role.charAt(0).toUpperCase() + message.role.slice(1)}: ${message.text}`)
                .join('\n');

            // const chat = chatData

            return chat
        } catch (error) {
            throw error
        }
    }

    async save_chat(data: any) {
        try {
            let { role, text, chat_id } = data

            await this.Model.CallTranscriptModel.create({
                text: text,
                role: role,
                call_id: new Types.ObjectId(chat_id),
                created_at: + new Date()
            })

        } catch (error) {
            throw error
        }
    }


    async end_chat(chat_id: string) {
        try {
            let chat = await this.Model.CallModel.findByIdAndUpdate(new Types.ObjectId(chat_id), { status: "COMPLETE", updated_at: +new Date() }, { lean: true })
            await this.chat_summerize(chat_id)
            // await this.CallService.em(chat_id)

            return chat
        } catch (error) {
            throw error
        }
    }


    async chat_summerize(chat_id: any) {
        try {
            let call = await this.Model.CallModel.findOne({ _id: new Types.ObjectId(chat_id) });

            let chatData = call.type === "VOICE_CHAT" ? await this.Model.landingPageChatHistoryModel.find({ chat_id: call?._id }, {}, { sort: { _id: 1 } }) :
                await this.Model.CallTranscriptModel.find({ call_id: call?._id }, {}, { sort: { _id: 1 } });

                console.log('chat_summerize', call.type)
                
            let chat = chatData
                .map((message) => `${message.role.charAt(0).toUpperCase() + message.role.slice(1)}: ${message.text}`)
                .join('\n');

            let summry = await this.RagService.chatSummrize(chat)
            let emotion = await this.RagService.chatEmotion(chat)
            let chat_status = await this.KnowledgeService.getChatStatus(chat)
            const customer_name = await this.KnowledgeService.getCustomerName(chat)
            const json_data = await this.KnowledgeService.getExtractedData(chat)
            console.log('customer_name ===>> ', customer_name)
            console.log('json_data', json_data)


            // console.log("summry", summry);
            const chat_duration_in_sec = (call?.updated_at - call?.created_at) / 1000;

            const call_data = await this.Model.CallModel.findOneAndUpdate({ _id: new Types.ObjectId(chat_id) },
                {
                    summary: summry,
                    emotion: emotion?.answer,
                    chat_status: chat_status?.answer,
                    chat_duration: call?.updated_at - call?.created_at,
                    extracted_data: json_data,
                }
            )

            const subscription = await this.Model.subscriptionModel.findOneAndUpdate({ workspace_id: call_data.workspace_id });
            console.log("tele_duration_limit_left :",subscription.tele_duration_limit_left)
            await this.Model.subscriptionModel.findOneAndUpdate(
                { _id: subscription._id },
                { tele_duration_limit_left: chat_duration_in_sec },
                { new: true }
            );
        } catch (error) {
            throw error
        }
    }

    async update_chat_detail(chat_id: string, body: dto.chat.chatUpdateDetail) {
        try {
            const { country_code, phone_no, email, name, type } = body

            let chat = await this.Model.CallModel.findByIdAndUpdate(new Types.ObjectId(chat_id),
                {
                    ...(phone_no && { phone_no: phone_no }),
                    ...(email && { email: email }),
                    ...(name && { name: name }),
                    ...(country_code && { country_code: country_code }),
                    ...(type && { type: type }),
                },
                { lean: true })
            return chat
        } catch (error) {
            throw error
        }
    }

}
