import { HttpService } from "@nestjs/axios";
import { Injectable, Logger } from "@nestjs/common";
import { parseTextOnlyFromWebsite } from "../utils/webToTextParser";
import envConfig from "src/common/config/envConfig";
import { ChatGptService } from "src/shared/third-party/services/chat-gpt/chat-gpt.service";
import { ChatCompletionMessageParam } from "openai/resources";
import { IFullUser } from "src/modules/users/users.interface";

import { ClaudeService } from "src/shared/third-party/services/claude/claude.service";
import { LanguageService } from "src/shared/language/language.service";
import { GeminiService } from "src/shared/third-party/services/gemini/gemini.service";
import { AiModelsService } from "src/modules/app-config/ai-models/ai-models.service";

@Injectable()
export class GoogleService {

	private readonly logger = new Logger(GoogleService.name)


	constructor(
		private readonly http: HttpService,
		private readonly chatGptService: ChatGptService,
		private readonly claudeService: ClaudeService,
		private readonly languageService: LanguageService,
		private readonly geminiService: GeminiService,
		private readonly aiModelsService: AiModelsService
	) { }


	async askGoogle(prompt: string, userPrompt: string, user: IFullUser) {

		prompt = prompt.replace('google', '').replace('Google', '');

		let urlSnipets = await this.getReleventWebsites(prompt);
		// get 5000 caracters from each website
		for (let i = 0; i < urlSnipets.length; i++) {
			let fullWebsite = await this.getFullWebsite(urlSnipets[i].link);
			urlSnipets[i].longerSnipet = fullWebsite.substring(0, 5000)
		}

		// canvert full array of objects to string
		let searchString = ''
		for (let i = 0; i < urlSnipets.length; i++) {
			searchString += `/n result ${i + 1} /n  
			 Title: ${urlSnipets[i].title} /n
			 link: ${urlSnipets[i].link} /n
			 Short Snippet: ${urlSnipets[i].snippet} /n
			 Long Snippet: ${urlSnipets[i].longerSnipet} /n
			 /n
			 `
		}

		const isChatGPT = await this.aiModelsService.selectChatService(user?.subscription?.aiModel) === 'chatgpt';
		const isGemini = await this.aiModelsService.selectChatService(user?.subscription?.aiModel) === 'gemini';

		let answer: { success: boolean, answer: string, tokens: number, stream?: any };
		if (isChatGPT) {
			answer = await this.getAnswerFromWebsiteStream(searchString, prompt, userPrompt, user);
		} else if (isGemini) {
			answer = await this.getAnswerFromWebsiteStream_With_gemini(searchString, prompt, userPrompt, user);
		} else {
			answer = await this.getAnswerFromWebsiteStream_WithClaude(searchString, prompt, userPrompt, user);
		}

		return answer;
	}

	async getReleventWebsites(query: string): Promise<any[]> {
		let urlList = [];
		let url = `https://customsearch.googleapis.com/customsearch/v1?key=${envConfig().GOOGLE_API_KEY}&cx=747101d787d074a8b&q=${query}&num=4`;

		let response = await this.http.get(url).toPromise().then((res) => {
			try {
				for (let i = 0; i < res.data.items.length; i++) {
					urlList.push({
						title: res.data.items[i].title,
						link: res.data.items[i].link,
						snippet: res.data.items[i].snippet,
						longerSnipet: ''
					});
				}
			} catch (e) {
				this.logger.log('error while getting relevent websites');
				this.logger.log(e);
			}
		},
			(error) => {
				this.logger.log('error while getting relevent websites');
				this.logger.log(error)
			}
		);

		return urlList;
	}

	async getFullWebsite(url: string): Promise<string> {
		let headers = { 'Accept-Encoding': 'gzip,deflate,compress' }
		let response = await this.http.get(url, { headers: headers, timeout: 15000 }).toPromise().then((res) => {
			return res.data
		},
			(err) => {
				// this.logger.log('error while getting full website');
				// this.logger.log(err);
				return '';
			});
		return parseTextOnlyFromWebsite(response);
	}



	// CHATGPT non stream
	async getAnswerFromWebsite(webPages: string, query: string, userPrompt: string, user: IFullUser): Promise<{ success: boolean, answer: string, tokens: number }> {

		const isHebrewText = this.languageService.isHebrew(userPrompt);
		const isHebrewSettings = user.language === 'HB';
		const isHebrew = isHebrewText || isHebrewSettings;

		let substring = webPages.substring(0, 6000);
		let prompt: ChatCompletionMessageParam[] = isHebrew ? [{
			role: 'system',
			content: `${substring} /n
        הוראות: באמצעות תוצאות החיפוש באינטרנט שסופקו, כתוב תשובה מקיפה לשאלה .
        אם תוצאות החיפוש המסופקות מתייחסות למספר נושאים בעלי אותו שם, כתוב תשובות נפרדות לכל נושא. /n
		תענה בעברית אלא אם כן המשתמש ביקש אחרת.
		`
		},
		{
			role: 'user',
			content: `${query}`
		}]
			:
			[{
				role: 'system',
				content: `${substring} /n
        Instructions: Using the provided web search results, write a comprehensive reply to the givin quary.
        if the provided search resualts refer to multiple subjects with the same name, write seperate answers for each subject. /n`
			},
			{
				role: 'user',
				content: `${query}`
			}]

		const res = await this.chatGptService.generateChatbotResponse({
			model: await this.aiModelsService.getModelProviderKey(user?.subscription?.aiModel),
			messages: prompt,
			temperature: 0
		})

		// console.log(res.choices[0].message.content);
		this.logger.log('Web answer generated successfully via chatGptService');

		return { success: true, answer: res.choices[0].message.content, tokens: res.usage.total_tokens }
	}

	// CLAUDE non stream
	async getAnswerFromWebsiteWithClaude(webPages: string, query: string, userPrompt: string, user: IFullUser): Promise<{ success: boolean, answer: string, tokens: number }> {

		const isHebrewText = this.languageService.isHebrew(userPrompt);
		const isHebrewSettings = user.language === 'HB';
		const isHebrew = isHebrewText || isHebrewSettings;

		let substring = webPages.substring(0, 6000);

		const systemPrompt = isHebrew ? `${substring} /n
		הוראות: באמצעות תוצאות החיפוש באינטרנט שסופקו, כתוב תשובה מקיפה למחצבת givin.
        שמרו על התשובה קצרה ופשוטה.
        אם תוצאות החיפוש המסופקות מתייחסות למספר נושאים בעלי אותו שם, כתוב תשובות נפרדות לכל נושא.
		תענה בעברית אלא אם כן המשתמש ביקש אחרת.
		`
			:
			`${substring} /n
		Instructions: Using the provided web search results, write a comprehensive reply to the givin quary.
        keep the answer short and simple.
        if the provided search resualts refer to multiple subjects with the same name, write seperate answers for each subject.`

		const res = await this.claudeService.generateChatbotResponse({
			system: systemPrompt,
			model: await this.aiModelsService.getModelProviderKey(user?.subscription?.aiModel),
			messages: [{
				role: 'user',
				content: `${query}`
			}],
			temperature: 0
		})

		this.logger.log('Web answer generated successfully via CLAUDE Services');

		return { success: true, answer: res.content?.[0]?.text, tokens: res.usage.output_tokens }
	}

	// CHATGPT stream
	async getAnswerFromWebsiteStream(webPages: string, query: string, userPrompt: string, user: IFullUser): Promise<{ success: boolean, answer: string, tokens: number, stream: any }> {

		const isHebrewText = this.languageService.isHebrew(userPrompt);
		const isHebrewSettings = user.language === 'HB';
		const isHebrew = isHebrewText || isHebrewSettings;

		let substring = webPages.substring(0, 6000);
		let prompt: ChatCompletionMessageParam[] = isHebrew ? [{
			role: 'system',
			content: `${substring} /n
        הוראות: באמצעות תוצאות החיפוש באינטרנט שסופקו, כתוב תשובה מקיפה למחצבת givin.
        שמרו על התשובה קצרה ופשוטה.
        אם תוצאות החיפוש המסופקות מתייחסות למספר נושאים בעלי אותו שם, כתוב תשובות נפרדות לכל נושא. /n
		תענה בעברית אלא אם כן המשתמש ביקש אחרת.
		`
		},
		{
			role: 'user',
			content: `${query}`
		}]
			:
			[{
				role: 'system',
				content: `${substring} /n
        Instructions: Using the provided web search results, write a comprehensive reply to the givin quary.
        keep the answer short and simple.
        if the provided search resualts refer to multiple subjects with the same name, write seperate answers for each subject. /n`
			},
			{
				role: 'user',
				content: `${query}`
			}]

		const res = await this.chatGptService.generateChatbotResponseStream({
			model: await this.aiModelsService.getModelProviderKey(user?.subscription?.aiModel),
			messages: prompt,
			temperature: 0
		})

		// for stream response there is no answer and tokens
		return { success: true, answer: null, tokens: 0, stream: res }
	}

	// CLAUDE stream
	async getAnswerFromWebsiteStream_WithClaude(webPages: string, query: string, userPrompt: string, user: IFullUser): Promise<{ success: boolean, answer: string, tokens: number, stream: any }> {

		const isHebrewText = this.languageService.isHebrew(userPrompt);
		const isHebrewSettings = user.language === 'HB';
		const isHebrew = isHebrewText || isHebrewSettings;

		let substring = webPages.substring(0, 6000);

		const systemPrompt = isHebrew ? `${substring} /n
		הוראות: באמצעות תוצאות החיפוש באינטרנט שסופקו, כתוב תשובה מקיפה למחצבת givin.
        שמרו על התשובה קצרה ופשוטה.
        אם תוצאות החיפוש המסופקות מתייחסות למספר נושאים בעלי אותו שם, כתוב תשובות נפרדות לכל נושא.
		תענה בעברית אלא אם כן המשתמש ביקש אחרת.
		`
			:
			`${substring} /n
		Instructions: Using the provided web search results, write a comprehensive reply to the givin quary.
        keep the answer short and simple.
        if the provided search resualts refer to multiple subjects with the same name, write seperate answers for each subject.`

		const res = await this.claudeService.generateChatbotResponseStream({
			system: systemPrompt,
			model: await this.aiModelsService.getModelProviderKey(user?.subscription?.aiModel),
			messages: [{
				role: 'user',
				content: `${query}`
			}],
			temperature: 0
		});

		this.logger.log('Web answer generated successfully via CLAUDE Services');

		// for stream response there is no answer and tokens
		return { success: true, answer: null, tokens: 0, stream: res }
	}


	// Gemini stream
	async getAnswerFromWebsiteStream_With_gemini(webPages: string, query: string, userPrompt: string, user: IFullUser): Promise<{ success: boolean, answer: string, tokens: number, stream: any }> {

		const isHebrewText = this.languageService.isHebrew(userPrompt);
		const isHebrewSettings = user.language === 'HB';
		const isHebrew = isHebrewText || isHebrewSettings;

		let substring = webPages.substring(0, 6000);

		const systemPrompt = isHebrew ? `${substring} /n
		הוראות: באמצעות תוצאות החיפוש באינטרנט שסופקו, כתוב תשובה מקיפה למחצבת givin.
        שמרו על התשובה קצרה ופשוטה.
        אם תוצאות החיפוש המסופקות מתייחסות למספר נושאים בעלי אותו שם, כתוב תשובות נפרדות לכל נושא.
		תענה בעברית אלא אם כן המשתמש ביקש אחרת.
		`
			:
			`${substring} /n
		Instructions: Using the provided web search results, write a comprehensive reply to the givin quary.
        keep the answer short and simple.
        if the provided search resualts refer to multiple subjects with the same name, write seperate answers for each subject.`

		const res = await this.geminiService.generateChatbotResponseStream({
			systemInstruction: systemPrompt,
			contents: [{
				parts: [{
					text: `${query}`
				}],
				role: "user"
			}]
		});

		this.logger.log('Web answer generated successfully via Gemini Services');

		// for stream response there is no answer and tokens
		return { success: true, answer: null, tokens: 0, stream: res.stream }
	}
}

