import { Inject, Injectable } from '@nestjs/common';
import { ModelService } from '../model/model.service';
import { Types } from 'mongoose'
import { RagService } from '../rag/rag.service';
import { GoogleGenerativeAI } from '@google/generative-ai';
// import { KnowledgeService } from '../knowledge_base/knowledge.service';
@Injectable()
export class CallService {
    public initialmessage
    private genAI: GoogleGenerativeAI;

    constructor(
        private model: ModelService,
        private RagService: RagService,
        // private KnowledgeService: KnowledgeService,
    ) {
        this.initialmessage = 'Hello! i am an ai assistance from henceforth solution. just want to let you know can delay for few seconds after your query but i will answer the best as per my knowledge'
        this.genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);
    }

    async save_initiated_call(data: any, agent_id: string, workspace_id: string) {
        try {
            const { sid, toFormatted } = data
            await this.model.CallModel.create({
                call_id: sid,
                phone_no: toFormatted,
                status: 'INITIATED',
                agent_id: new Types.ObjectId(agent_id),
                workspace_id: new Types.ObjectId(workspace_id)
            })
        } catch (error) {
            throw error
        }
    }

    async save_voice_chat(data: any, agent_id: string) {
        try {
            const { sid, toFormatted } = data
            await this.model.CallModel.create({
                call_id: sid,
                phone_no: toFormatted,
                status: 'INITIATED',
                type: "VOICE_CHAT",
                agent_id: new Types.ObjectId(agent_id)
            })
        } catch (error) {
            throw error
        }
    }

    async save_call(data: any) {
        try {
            const { call_id, stream_id } = data
            // await this.model.CallModel.create({
            //     call_id: call_id,
            //     stream_id: stream_id
            // })
            const call_detail = await this.model.CallModel.findOneAndUpdate(
                { call_id: call_id },
                { stream_id: stream_id, status: 'ACTIVE' },
                { new: true }
            ).populate({ path: "agent_id", select: "default_type" });
            return call_detail
        } catch (error) {
            throw error
        }
    }

    async update_call(data: any) {
        try {
            let { stream_id, status, call_duration, last_message } = data
            await this.model.CallModel.findOneAndUpdate({ stream_id: stream_id },
                {
                    ...(status && { status: status }),
                    ...(call_duration && { call_duration: call_duration }),
                    ...(last_message && { last_message: last_message })
                }
            )
        } catch (error) {
            throw error
        }
    }

    async save_call_transcript(data: any) {
        try {
            let { stream_id, text, role } = data
            let call = await this.model.CallModel.findOne({ stream_id: stream_id })

            await this.model.CallTranscriptModel.create({
                call_id: call._id,
                stream_id: stream_id,
                text: text,
                role: role,
            })
        } catch (error) {
            throw error
        }
    }

    async save_call_transcript_delete_last_message(data: any, last_message: string) {
        try {
            let { stream_id, text, role } = data
            let call = await this.model.CallModel.findOne({ stream_id: stream_id })
            if (last_message) await this.delete_last_message_of_call(stream_id)
            await this.model.CallTranscriptModel.create({
                call_id: call?._id,
                stream_id: stream_id,
                text: text,
                role: role,
            })
        } catch (error) {
            throw error
        }
    }

    async delete_last_message_of_call(stream_id: any) {
        try {
            let data = await this.model.CallTranscriptModel.findOne({ stream_id: stream_id, is_send: false, role: "user" }, {},
                { lean: true, sort: { _id: -1 }, limit: 1 })
            if (data?.role == "user") {
                return await this.model.CallTranscriptModel.findOneAndUpdate({ _id: data?._id }, { is_delete: true }, { lean: true })
            }
        } catch (error) {
            throw error
        }
    }

    async mark_send_call_transcript(stream_id: string) {
        try {
            let data = await this.model.CallTranscriptModel.findOne({ stream_id: stream_id, is_send: false, role: "user" }, {}, { lean: true, sort: { _id: 1 }, limit: 1 })

            await this.model.CallTranscriptModel.updateOne({ _id: data?._id }, { is_send: true })
        } catch (error) {
            throw error
        }
    }

    async get_in_progress_transcript(stream_id: string) {
        try {
            return await this.model.CallTranscriptModel.countDocuments({ stream_id: stream_id, is_send: false, role: "user" })
        } catch (error) {
            throw error
        }
    }

    async get_last_message_of_call(stream_id: any) {
        try {
            let data = await this.model.CallTranscriptModel.findOne({ stream_id: stream_id, is_send: false, role: "user" }, {}, { lean: true, sort: { _id: -1 }, limit: 1 })
            if (data) return data?.text
            return null
        } catch (error) {
            throw error
        }
    }

    async call_summerize(data: any) {
        try {
            let { stream_id } = data
            let call = await this.model.CallModel.findOne({ stream_id: stream_id })

            let chatData = await this.model.CallTranscriptModel.find({ call_id: call._id }, {}, { sort: { _id: 1 } })
            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)
            // const customer_name = await this.KnowledgeService.getCustomerName(chat)
            // console.log('customer_name ===>> ', customer_name)
            
            console.log("emotion", emotion);
            await this.model.CallModel.findOneAndUpdate({ stream_id: stream_id },
                {
                    summary: summry,
                    emotion: emotion?.answer,
                    // name: customer_name
                }
            )
        } 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 = await this.model.CallTranscriptModel.find({ call_id: call._id }, {}, { sort: { _id: 1 } })
            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)
            const json_data = await this.getExtractedData(chat)
            console.log('json_data', json_data)
            // console.log("summry", summry);
            await this.model.CallModel.findOneAndUpdate({ _id: new Types.ObjectId(chat_id) },
                {
                    summary: summry,
                    emotion: emotion?.answer,
                    extracted_data: json_data,
                }
            )
        } catch (error) {
            throw error
        }
    }

    async chat_history(stream_id: any) {
        try {
            let call = await this.model.CallModel.findOne({ stream_id: stream_id })
            let chatData = await this.model.CallTranscriptModel.find({ call_id: call._id }, { role: 1, text: 1 }, { sort: { _id: 1 } })
            let chat = chatData
                .map((message) => `${message.role.charAt(0).toUpperCase() + message.role.slice(1)}: ${message.text}`)
                .join('\n');

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

    async get_initial_message(call_agen_type = "CALL") {
        try {
            // let data = await this.model.MessageModel.findOne()
            let agent = await this.model.AgentModel.findOne({ is_default: true, default_type: call_agen_type }, {}, {})
            // console.log("agent",agent);
            
            if (agent) {
                return agent.call_first_message
            } else {
                let message = "Hello! i am an ai assistance from henceforth solution. just want to let you know can delay for few seconds after your query but i will answer the best as per my knowledge"
                // await this.model.MessageModel.create({ message: message })
                return message
            }
        } catch (error) {
            throw error
        }
    }


    async get_default_agent_id(default_type: string) {
        try {
            let agent = await this.model.AgentModel.findOne({ is_default: true, default_type: default_type }, {}, {lean:true})
            return agent?._id?.toString()
        } catch (error) {
            throw error
        }
    }

    async get_default_voice() {
        try {
            let agent = await this.model.AgentModel.findOne({ is_default: true }, {}, {lean:true})
            return agent?.voice?.toString()
        } catch (error) {
            throw error
        }
    }


    async update_initial_message(message: string) {
        try {
            let data = await this.model.MessageModel.findOne()
            let response
            if (data) {
                await this.model.MessageModel.findOneAndUpdate({ _id: data._id }, { message: message }, {})
            } else {
                await this.model.MessageModel.create({ message: message })
            }
            return message
        } catch (error) {
            throw error
        }
    }

    async getExtractedData(chat_history?: string) {
        try {
            const prompt = `
            You are an AI model analyzing customer interactions. Below is a chat history between a customer and a support agent.
            Your task is to extract key information from the conversation and format it as JSON. The required fields are:
          
            - full_name: Full name of the person (if mentioned).
            - email: Email address (if provided).
            - phone_number: Contact number (if provided).
            - address: Residential or business address (if available).
            - purpose_of_appointment: The reason for the appointment or meeting.
            - appointment_date_time: Date and time of the appointment or meeting.
            - meeting_with: Name of the person the customer has an appointment with.
            - meeting_details: Additional information related to the meeting, if any.
          
            If any information is not available in the chat, set its value to null.
          
            Chat History:
            ${chat_history}
          
            Provide the extracted information in the following JSON format:
          
            {
              "full_name": "John Doe",
              "email": "johndoe@example.com",
              "phone_number": "+123456789",
              "address": "123 Main St, City, Country",
              "purpose_of_appointment": "Consultation regarding project",
              "appointment_date_time": "2024-06-15T14:30:00",
              "meeting_with": "Jane Smith",
              "meeting_details": "Discussion about project requirements"
            }
          
            If data is missing, use null. Provide only the JSON output without additional explanations.
          `.trim();
          
          const model = this.genAI.getGenerativeModel({
            model: 'gemini-1.5-flash',
            generationConfig: {
              maxOutputTokens: 200,
              temperature: 0.7,
            },
          });
    
          console.time('time in gemini response');
          const result = await model.generateContent(prompt);
          console.timeEnd('time in gemini response');
    
          return {
            answer: result.response.text(),
          };
        } catch (error) {
          throw error;
        }
      }



}
