/**
 * Advanced LangChain features and integrations
 * Demonstrates cutting-edge capabilities for manuscript analysis
 */

import type { BaseLanguageModel } from '@langchain/core/language_models/base';
import { JsonOutputParser, StringOutputParser } from '@langchain/core/output_parsers';
import { ChatPromptTemplate, MessagesPlaceholder, PromptTemplate } from '@langchain/core/prompts';
import { RunnableMap, RunnableSequence } from '@langchain/core/runnables';
import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai';
import { Document as LangchainDocument } from '@langchain/core/documents';
import { BufferWindowMemory } from '@langchain/classic/memory';
import { StructuredOutputParser } from '@langchain/core/output_parsers';
import { RecursiveCharacterTextSplitter } from '@langchain/textsplitters';
import { LangChainHMSVectorStore } from './hms-vector-store.js';
import { z } from 'zod';
import { createError, ErrorCode } from '../../core/errors.js';
import { getLogger } from '../../core/logger.js';
import type { ScrivenerDocument } from '../../types/index.js';

// Interfaces for advanced features
interface Entity {
	name: string;
	type: 'character' | 'location' | 'organization' | 'event' | 'object';
	context: string;
	mentions: number;
}

interface Relationship {
	entity1: string;
	entity2: string;
	relationship: string;
	strength: number;
	type: 'character' | 'location' | 'object' | 'event';
}

interface WritingStyleAnalysis {
	voice: {
		tone: string;
		perspective: string;
		consistency: number;
	};
	structure: {
		sentenceVariety: number;
		averageLength: number;
		complexity: string;
	};
	vocabulary: {
		level: string;
		variety: number;
		distinctiveness: number;
	};
	pacing: {
		rhythm: string;
		flow: number;
		tension: number;
	};
	literaryDevices: string[];
	strengths: string[];
	weaknesses: string[];
	overallScore: number;
}

// Advanced schemas for structured output
const CharacterAnalysisSchema = z.object({
	name: z.string().describe('Character name'),
	role: z.enum(['protagonist', 'antagonist', 'supporting', 'minor']).describe('Character role'),
	arc: z.string().describe('Character arc description'),
	traits: z.array(z.string()).describe('Key personality traits'),
	relationships: z
		.array(
			z.object({
				character: z.string(),
				relationship: z.string(),
				dynamic: z.enum(['static', 'evolving', 'deteriorating', 'improving']),
			})
		)
		.describe('Relationships with other characters'),
	motivations: z.array(z.string()).describe('Core motivations'),
	conflicts: z.array(z.string()).describe('Internal and external conflicts'),
	symbolism: z.string().optional().describe('Symbolic significance'),
	development: z
		.object({
			beginning: z.string().describe('Character state at story beginning'),
			middle: z.string().describe('Character state at story middle'),
			end: z.string().describe('Character state at story end'),
		})
		.describe('Character development through story'),
});

const PlotStructureSchema = z.object({
	acts: z
		.array(
			z.object({
				number: z.number(),
				title: z.string(),
				summary: z.string(),
				keyEvents: z.array(z.string()),
				turningPoint: z.string().optional(),
				tension: z.number().min(1).max(10).describe('Tension level 1-10'),
			})
		)
		.describe('Story acts'),
	incitingIncident: z.string().describe('The event that starts the story'),
	climax: z.string().describe('The story climax'),
	resolution: z.string().describe('How the story resolves'),
	subplots: z
		.array(
			z.object({
				title: z.string(),
				summary: z.string(),
				resolution: z.string().optional(),
				connection: z.string().describe('How it connects to main plot'),
			})
		)
		.describe('Subplots'),
	themes: z.array(z.string()).describe('Major themes'),
	pacing: z
		.object({
			overall: z.enum(['too slow', 'slow', 'balanced', 'fast', 'too fast']),
			recommendations: z.array(z.string()),
		})
		.describe('Pacing analysis'),
});

const WritingStyleSchema = z.object({
	voice: z.object({
		perspective: z.enum([
			'first-person',
			'second-person',
			'third-person-limited',
			'third-person-omniscient',
		]),
		tone: z.array(z.string()).describe('Dominant tones (e.g., humorous, serious, ironic)'),
		consistency: z.number().min(1).max(10).describe('Voice consistency score'),
	}),
	prose: z.object({
		sentenceVariety: z.enum(['poor', 'fair', 'good', 'excellent']),
		averageSentenceLength: z.number(),
		vocabularyLevel: z.enum(['simple', 'moderate', 'advanced', 'academic']),
		descriptiveness: z.enum(['sparse', 'balanced', 'rich', 'excessive']),
	}),
	dialogue: z.object({
		naturalness: z.number().min(1).max(10),
		characterDistinction: z.number().min(1).max(10),
		tagVariety: z.enum(['repetitive', 'limited', 'good', 'excellent']),
		balanceWithNarration: z.enum(['too little', 'balanced', 'too much']),
	}),
	techniques: z.array(z.string()).describe('Literary techniques used'),
	strengths: z.array(z.string()),
	weaknesses: z.array(z.string()),
	comparisons: z.array(z.string()).describe('Similar authors or works'),
});

export class AdvancedLangChainFeatures {
	private llm: ChatOpenAI;
	private embeddings: OpenAIEmbeddings;
	private vectorStore: LangChainHMSVectorStore | null = null;
	private logger: ReturnType<typeof getLogger>;
	private characterParser: StructuredOutputParser<typeof CharacterAnalysisSchema>;
	private plotParser: StructuredOutputParser<typeof PlotStructureSchema>;
	private styleParser: StructuredOutputParser<typeof WritingStyleSchema>;

	constructor(apiKey?: string) {
		this.logger = getLogger('advanced-langchain-features');

		if (!apiKey && !process.env.OPENAI_API_KEY) {
			throw createError(
				ErrorCode.CONFIGURATION_ERROR,
				null,
				'OpenAI API key required for advanced features'
			);
		}

		this.llm = new ChatOpenAI({
			openAIApiKey: apiKey || process.env.OPENAI_API_KEY,
			temperature: 0.3, // Lower temperature for structured output
			modelName: 'gpt-4-turbo-preview',
		});

		this.embeddings = new OpenAIEmbeddings({
			openAIApiKey: apiKey || process.env.OPENAI_API_KEY,
		});

		// Initialize structured output parsers
		this.characterParser = StructuredOutputParser.fromZodSchema(CharacterAnalysisSchema);
		this.plotParser = StructuredOutputParser.fromZodSchema(PlotStructureSchema);
		this.styleParser = StructuredOutputParser.fromZodSchema(WritingStyleSchema);
	}

	/**
	 * Advanced character analysis with structured output
	 */
	async analyzeCharacterStructured(
		characterName: string,
		documents: ScrivenerDocument[]
	): Promise<z.infer<typeof CharacterAnalysisSchema>> {
		try {
			// Build context from documents
			const context = documents
				.map((doc) => doc.content)
				.join('\n\n')
				.substring(0, 10000); // Limit context size

			const prompt = PromptTemplate.fromTemplate(`
				Analyze the character "{characterName}" from the following manuscript:

				{context}

				{format_instructions}

				Provide a comprehensive character analysis.
			`);

			const chain = RunnableSequence.from([prompt, this.llm, this.characterParser]);

			const result = await chain.invoke({
				characterName,
				context,
				format_instructions: this.characterParser.getFormatInstructions(),
			});

			return result;
		} catch (error) {
			throw createError(
				ErrorCode.AI_SERVICE_ERROR,
				error as Error,
				`Failed to analyze character: ${characterName}`
			);
		}
	}

	/**
	 * Advanced plot structure analysis
	 */
	async analyzePlotStructure(
		documents: ScrivenerDocument[]
	): Promise<z.infer<typeof PlotStructureSchema>> {
		try {
			const context = documents
				.map(
					(doc, index) =>
						`Chapter ${index + 1}: ${doc.title}\n<document-content>\n${doc.content}\n</document-content>`
				)
				.join('\n\n---\n\n')
				.substring(0, 15000);

			const prompt = PromptTemplate.fromTemplate(`
				Analyze the plot structure of this manuscript:

				{context}

				{format_instructions}

				Provide a detailed plot structure analysis including acts, pacing, and themes.
			`);

			const chain = RunnableSequence.from([prompt, this.llm, this.plotParser]);

			const result = await chain.invoke({
				context,
				format_instructions: this.plotParser.getFormatInstructions(),
			});

			return result;
		} catch (error) {
			throw createError(
				ErrorCode.AI_SERVICE_ERROR,
				error as Error,
				'Failed to analyze plot structure'
			);
		}
	}

	/**
	 * Advanced writing style analysis
	 */
	async analyzeWritingStyleStructured(
		documents: ScrivenerDocument[]
	): Promise<z.infer<typeof WritingStyleSchema>> {
		try {
			// Sample from different parts of the manuscript
			const samples = documents
				.filter((_, index) => index % Math.ceil(documents.length / 5) === 0)
				.map((doc) => doc.content?.substring(0, 2000))
				.join('\n\n---\n\n');

			const prompt = PromptTemplate.fromTemplate(`
				Analyze the writing style of these manuscript samples:

				{samples}

				{format_instructions}

				Provide a comprehensive writing style analysis.
			`);

			const chain = RunnableSequence.from([prompt, this.llm, this.styleParser]);

			const result = await chain.invoke({
				samples,
				format_instructions: this.styleParser.getFormatInstructions(),
			});

			return result;
		} catch (error) {
			throw createError(
				ErrorCode.AI_SERVICE_ERROR,
				error as Error,
				'Failed to analyze writing style'
			);
		}
	}

	/**
	 * Create a custom writing coach chain
	 */
	async createWritingCoachChain(focusArea: 'dialogue' | 'description' | 'pacing' | 'character') {
		const coachPrompts = {
			dialogue: `You are an expert dialogue coach. Analyze the dialogue and provide specific improvements:
				- Make dialogue sound more natural
				- Ensure each character has a distinct voice
				- Add subtext and emotional layers
				- Improve dialogue tags and actions`,
			description: `You are a descriptive writing expert. Enhance descriptions by:
				- Using all five senses
				- Balancing detail with pacing
				- Creating atmosphere and mood
				- Showing rather than telling`,
			pacing: `You are a pacing specialist. Optimize the narrative flow by:
				- Varying sentence and paragraph length
				- Balancing action and reflection
				- Managing tension curves
				- Identifying slow spots`,
			character: `You are a character development coach. Strengthen characters by:
				- Deepening motivations
				- Adding complexity and contradictions
				- Showing growth and change
				- Enhancing relationships`,
		};

		const template = ChatPromptTemplate.fromMessages([
			['system', coachPrompts[focusArea]],
			['user', '{input}'],
			new MessagesPlaceholder('history'),
		]);

		const memory = new BufferWindowMemory({
			k: 5, // Remember last 5 exchanges
			returnMessages: true,
			memoryKey: 'history',
		});

		const chain = RunnableSequence.from([
			RunnableMap.from({
				input: (input: { text: string }) => input.text,
				history: async () => {
					const messages = await memory.chatHistory.getMessages();
					return messages;
				},
			}),
			template,
			this.llm,
			new StringOutputParser(),
		]);

		return {
			chain,
			memory,
			invoke: async (text: string) => {
				const response = await chain.invoke({ text });
				await memory.saveContext({ input: text }, { output: response });
				return response;
			},
		};
	}

	/**
	 * Generate alternative versions of a passage
	 */
	async generateAlternatives(
		passage: string,
		styles: Array<'literary' | 'commercial' | 'minimalist' | 'ornate' | 'noir' | 'comedic'>
	): Promise<Record<string, string>> {
		const stylePrompts = {
			literary:
				'Rewrite in a literary fiction style with rich metaphors and deep introspection',
			commercial:
				'Rewrite in a commercial fiction style with clear, engaging prose and strong hooks',
			minimalist: 'Rewrite in a minimalist style like Hemingway with short, direct sentences',
			ornate: 'Rewrite in an ornate Victorian style with elaborate descriptions',
			noir: 'Rewrite in a noir style with cynical tone and atmospheric descriptions',
			comedic: 'Rewrite with humor, wit, and comedic timing',
		};

		const alternatives: Record<string, string> = {};

		for (const style of styles) {
			const prompt = PromptTemplate.fromTemplate(`
				{stylePrompt}

				Original passage:
				{passage}

				Rewritten version:
			`);

			const chain = RunnableSequence.from([prompt, this.llm, new StringOutputParser()]);

			alternatives[style] = await chain.invoke({
				stylePrompt: stylePrompts[style],
				passage,
			});
		}

		return alternatives;
	}

	/**
	 * Advanced semantic similarity search with context
	 */
	async findSimilarScenes(
		sceneDescription: string,
		documents: ScrivenerDocument[],
		options: {
			minSimilarity?: number;
			maxResults?: number;
			includeContext?: boolean;
		} = {}
	): Promise<
		Array<{
			document: ScrivenerDocument;
			similarity: number;
			excerpt: string;
			analysis: string;
		}>
	> {
		if (!this.vectorStore) {
			// Build vector store from documents
			const splitter = new RecursiveCharacterTextSplitter({
				chunkSize: 1000,
				chunkOverlap: 100,
			});

			const chunks: LangchainDocument[] = [];
			for (const doc of documents) {
				const docChunks = await splitter.createDocuments(
					[doc.content || ''],
					[{ documentId: doc.id, title: doc.title }]
				);
				chunks.push(...docChunks);
			}

			this.vectorStore = await LangChainHMSVectorStore.fromDocuments(chunks, this.embeddings);
		}

		// Search for similar scenes
		const results = await this.vectorStore.similaritySearchWithScore(
			sceneDescription,
			options.maxResults || 5
		);

		// Filter by minimum similarity
		const minSim = options.minSimilarity || 0.7;
		const filtered = (results as [any, number][]).filter(([, score]) => score >= minSim);

		// Analyze each result
		const analyzed = await Promise.all(
			filtered.map(async ([doc, score]) => {
				const sourceDoc = documents.find((d) => d.id === doc.metadata.documentId);
				if (!sourceDoc) return null;

				let analysis = '';
				if (options.includeContext) {
					const prompt = PromptTemplate.fromTemplate(`
						Compare these two scenes and explain their similarities:

						Scene 1: {scene1}
						Scene 2: {scene2}

						Brief analysis:
					`);

					const chain = RunnableSequence.from([
						prompt,
						this.llm,
						new StringOutputParser(),
					]);

					analysis = await chain.invoke({
						scene1: sceneDescription.substring(0, 500),
						scene2: doc.pageContent.substring(0, 500),
					});
				}

				return {
					document: sourceDoc,
					similarity: score,
					excerpt: `${doc.pageContent.substring(0, 200)}...`,
					analysis,
				};
			})
		);

		return analyzed.filter(Boolean) as Array<{
			document: ScrivenerDocument;
			similarity: number;
			excerpt: string;
			analysis: string;
		}>;
	}

	/**
	 * Create a developmental editor AI
	 */
	async createDevelopmentalEditor() {
		// Pull a pre-made prompt from LangChain Hub (if available)
		// const basePrompt = await pull('manuscript-editor');

		const editorPrompt = ChatPromptTemplate.fromMessages([
			[
				'system',
				`You are an experienced developmental editor specializing in fiction manuscripts.
				Your role is to:
				1. Identify structural issues in the narrative
				2. Suggest improvements to character arcs
				3. Point out plot inconsistencies
				4. Recommend pacing adjustments
				5. Highlight themes that need strengthening

				Always provide actionable, specific feedback with examples.`,
			],
			['user', '{manuscript_section}'],
			['assistant', `I'll analyze this section as a developmental editor.`],
			['user', '{question}'],
		]);

		const chain = RunnableSequence.from([editorPrompt, this.llm, new StringOutputParser()]);

		return {
			analyze: async (section: string, question: string) => {
				return await chain.invoke({
					manuscript_section: section,
					question,
				});
			},
			compareVersions: async (original: string, revised: string) => {
				const comparePrompt = PromptTemplate.fromTemplate(`
					As a developmental editor, compare these two versions:

					ORIGINAL:
					{original}

					REVISED:
					{revised}

					Provide:
					1. What improved
					2. What still needs work
					3. Whether the changes align with story goals
					4. Specific next steps
				`);

				const compareChain = RunnableSequence.from([
					comparePrompt,
					this.llm,
					new StringOutputParser(),
				]);

				return await compareChain.invoke({ original, revised });
			},
		};
	}

	/**
	 * Generate a story bible from manuscript
	 */
	async generateStoryBible(documents: ScrivenerDocument[]): Promise<{
		characters: Record<string, unknown>;
		worldbuilding: Record<string, unknown>;
		timeline: Array<{ event: string; chapter: string; significance: string }>;
		themes: string[];
		symbols: Array<{ symbol: string; meaning: string; appearances: string[] }>;
		styleGuide: Record<string, string>;
	}> {
		const fullText = documents.map((d) => d.content).join('\n\n');

		// Generate each section of the story bible
		const [characters, worldbuilding, timeline, themes, symbols, styleGuide] =
			await Promise.all([
				this.extractCharacters(fullText),
				this.extractWorldbuilding(fullText),
				this.extractTimeline(documents),
				this.extractThemes(fullText),
				this.extractSymbols(fullText),
				this.extractStyleGuide(fullText),
			]);

		return {
			characters,
			worldbuilding,
			timeline,
			themes,
			symbols,
			styleGuide,
		};
	}

	private async extractCharacters(text: string): Promise<Record<string, unknown>> {
		const prompt = PromptTemplate.fromTemplate(`
			Extract all characters from this manuscript and create detailed profiles:
			{text}

			For each character include:
			- Full name and aliases
			- Physical description
			- Personality traits
			- Background
			- Relationships
			- Arc/journey

			Format as JSON.
		`);

		const chain = RunnableSequence.from([prompt, this.llm, new JsonOutputParser()]);

		return await chain.invoke({ text: text.substring(0, 10000) });
	}

	private async extractWorldbuilding(text: string): Promise<Record<string, unknown>> {
		const prompt = PromptTemplate.fromTemplate(`
			Extract worldbuilding details from this manuscript:
			{text}

			Include:
			- Settings and locations
			- Time period
			- Social structures
			- Rules and systems
			- Technology level
			- Cultural elements

			Format as JSON.
		`);

		const chain = RunnableSequence.from([prompt, this.llm, new JsonOutputParser()]);

		return await chain.invoke({ text: text.substring(0, 10000) });
	}

	private async extractTimeline(
		documents: ScrivenerDocument[]
	): Promise<Array<{ event: string; chapter: string; significance: string }>> {
		const timeline: Array<{ event: string; chapter: string; significance: string }> = [];

		for (const doc of documents.slice(0, 10)) {
			// Limit to first 10 chapters
			const prompt = PromptTemplate.fromTemplate(`
				Extract the key plot event from this chapter:
				{content}

				Provide:
				1. The main event (one sentence)
				2. Its significance to the overall story

				Format: EVENT|SIGNIFICANCE
			`);

			const chain = RunnableSequence.from([prompt, this.llm, new StringOutputParser()]);

			const result = await chain.invoke({
				content: doc.content?.substring(0, 2000),
			});

			const [event, significance] = result.split('|');
			if (event && significance) {
				timeline.push({
					event: event.trim(),
					chapter: doc.title || doc.id,
					significance: significance.trim(),
				});
			}
		}

		return timeline;
	}

	private async extractThemes(text: string): Promise<string[]> {
		const prompt = PromptTemplate.fromTemplate(`
			Identify the major themes in this manuscript:
			{text}

			List 5-10 major themes, one per line.
		`);

		const chain = RunnableSequence.from([prompt, this.llm, new StringOutputParser()]);

		const result = await chain.invoke({ text: text.substring(0, 10000) });
		return result
			.split('\n')
			.filter((line) => line.trim())
			.map((line) => line.trim());
	}

	private async extractSymbols(
		text: string
	): Promise<Array<{ symbol: string; meaning: string; appearances: string[] }>> {
		const prompt = PromptTemplate.fromTemplate(`
			Identify recurring symbols and motifs in this manuscript:
			{text}

			For each symbol provide:
			SYMBOL: [name]
			MEANING: [what it represents]
			APPEARS: [where it appears]
			---
		`);

		const chain = RunnableSequence.from([prompt, this.llm, new StringOutputParser()]);

		const result = await chain.invoke({ text: text.substring(0, 10000) });

		const symbols: Array<{ symbol: string; meaning: string; appearances: string[] }> = [];
		const symbolBlocks = result.split('---');

		for (const block of symbolBlocks) {
			const lines = block.trim().split('\n');
			if (lines.length >= 3) {
				const symbol = lines[0].replace('SYMBOL:', '').trim();
				const meaning = lines[1].replace('MEANING:', '').trim();
				const appears = lines[2].replace('APPEARS:', '').trim();

				if (symbol && meaning) {
					symbols.push({
						symbol,
						meaning,
						appearances: [appears],
					});
				}
			}
		}

		return symbols;
	}

	private async extractStyleGuide(text: string): Promise<Record<string, string>> {
		const prompt = PromptTemplate.fromTemplate(`
			Create a style guide from this manuscript sample:
			{text}

			Include:
			- POV and tense
			- Dialogue style
			- Description approach
			- Tone guidelines
			- Vocabulary level
			- Sentence structure preferences

			Format as key: value pairs.
		`);

		const chain = RunnableSequence.from([prompt, this.llm, new StringOutputParser()]);

		const result = await chain.invoke({ text: text.substring(0, 5000) });

		const styleGuide: Record<string, string> = {};
		const lines = result.split('\n');

		for (const line of lines) {
			const [key, value] = line.split(':');
			if (key && value) {
				styleGuide[key.trim()] = value.trim();
			}
		}

		return styleGuide;
	}

	/**
	 * Create a beta reader simulation
	 */
	async simulateBetaReader(
		document: ScrivenerDocument,
		readerProfile: {
			genre_preference: string;
			reading_level: 'casual' | 'avid' | 'professional';
			focus: 'plot' | 'character' | 'prose' | 'general';
		}
	): Promise<{
		overall_impression: string;
		strengths: string[];
		concerns: string[];
		questions: string[];
		emotional_response: string;
		would_continue_reading: boolean;
		rating: number;
		specific_feedback: Record<string, string>;
	}> {
		const readerPrompt = ChatPromptTemplate.fromMessages([
			[
				'system',
				`You are a beta reader with these characteristics:
				- Preferred genre: {genre_preference}
				- Reading level: {reading_level}
				- Focus area: {focus}

				Provide honest, constructive feedback as a real reader would.`,
			],
			['user', '{content}'],
		]);

		const chain = RunnableSequence.from([readerPrompt, this.llm, new StringOutputParser()]);

		const response = await chain.invoke({
			genre_preference: readerProfile.genre_preference,
			reading_level: readerProfile.reading_level,
			focus: readerProfile.focus,
			content: document.content?.substring(0, 5000),
		});

		// Parse the response into structured feedback
		const feedbackParser = StructuredOutputParser.fromZodSchema(
			z.object({
				overall_impression: z.string(),
				strengths: z.array(z.string()),
				concerns: z.array(z.string()),
				questions: z.array(z.string()),
				emotional_response: z.string(),
				would_continue_reading: z.boolean(),
				rating: z.number().min(1).max(10),
				specific_feedback: z.record(z.string(), z.string()),
			})
		);

		const structuredPrompt = PromptTemplate.fromTemplate(`
			Based on this beta reader feedback:
			{feedback}

			{format_instructions}

			Structure the feedback accordingly.
		`);

		const structuredChain = RunnableSequence.from([structuredPrompt, this.llm, feedbackParser]);

		return await structuredChain.invoke({
			feedback: response,
			format_instructions: feedbackParser.getFormatInstructions(),
		});
	}

	/**
	 * Extract entities from text
	 */
	async extractEntities(text: string): Promise<Entity[]> {
		const prompt = ChatPromptTemplate.fromTemplate(`
			Extract all named entities from the following text:
			{text}

			Return entities in categories: characters, locations, organizations, events, objects.
			Format as JSON array with fields: name, type, context, mentions
		`);

		const chain = prompt.pipe(this.llm).pipe(new JsonOutputParser());

		try {
			const result = await chain.invoke({ text });
			return Array.isArray(result) ? result : [];
		} catch (error) {
			this.logger.error('Failed to extract entities', { error });
			return [];
		}
	}

	/**
	 * Analyze relationships between entities
	 */
	async analyzeRelationships(entities: Entity[]): Promise<Relationship[]> {
		if (!entities || entities.length === 0) return [];

		const prompt = ChatPromptTemplate.fromTemplate(`
			Analyze relationships between these entities:
			{entities}

			Identify:
			1. Character relationships (family, romantic, adversarial, etc.)
			2. Location associations (who lives/works where)
			3. Object ownership or significance
			4. Event participation

			Return as JSON array with fields: entity1, entity2, relationship, strength, type
		`);

		const chain = prompt.pipe(this.llm).pipe(new JsonOutputParser());

		try {
			const result = await chain.invoke({
				entities: JSON.stringify(entities),
			});
			return Array.isArray(result) ? result : [];
		} catch (error) {
			this.logger.error('Failed to analyze relationships', { error });
			return [];
		}
	}

	/**
	 * Analyze writing style
	 */
	async analyzeWritingStyle(text: string): Promise<WritingStyleAnalysis> {
		const prompt = ChatPromptTemplate.fromTemplate(`
			Analyze the writing style of this text:
			{text}

			Evaluate:
			1. Voice and tone
			2. Sentence structure and variety
			3. Vocabulary and word choice
			4. Pacing and rhythm
			5. Literary devices used
			6. Strengths and weaknesses

			Return detailed analysis as JSON.
		`);

		const chain = prompt.pipe(this.llm).pipe(new JsonOutputParser());

		try {
			return await chain.invoke({ text });
		} catch (error) {
			this.logger.error('Failed to analyze writing style', { error });
			return {
				voice: { tone: 'unknown', perspective: 'unknown', consistency: 0 },
				structure: { sentenceVariety: 0, averageLength: 0, complexity: 'unknown' },
				vocabulary: { level: 'unknown', variety: 0, distinctiveness: 0 },
				pacing: { rhythm: 'unknown', flow: 0, tension: 0 },
				literaryDevices: [],
				strengths: [],
				weaknesses: ['Analysis failed'],
				overallScore: 0,
			};
		}
	}
}

export default AdvancedLangChainFeatures;
