import { Injectable, Logger } from '@nestjs/common';
import { ConversationMessage, MessageRole } from '../../../database/entities';
import { Child } from '../../../database/entities/child.entity';
import { Activity } from '../../../database/entities/activity.entity';

interface ContextPriority {
  weight: number;
  data: any;
  tokenEstimate: number;
}

@Injectable()
export class ContextManager {
  private readonly logger = new Logger('ContextManager');
  private readonly MAX_TOKENS = 4000;
  private readonly TOKENS_PER_MESSAGE = 100; // Rough estimate
  private readonly SYSTEM_PROMPT_TOKENS = 300;

  /**
   * Build context for AI conversation with token management
   */
  async buildContext(
    conversationHistory: ConversationMessage[],
    childContext?: Child[],
    recentActivities?: Activity[],
    userPreferences?: Record<string, any>,
  ): Promise<ConversationMessage[]> {
    const contextItems: ContextPriority[] = [];

    // System prompt (highest priority)
    const systemPrompt = this.buildSystemPrompt(userPreferences);
    contextItems.push({
      weight: 100,
      data: { role: MessageRole.SYSTEM, content: systemPrompt },
      tokenEstimate: this.SYSTEM_PROMPT_TOKENS,
    });

    // Child context (high priority)
    if (childContext && childContext.length > 0) {
      const childSummary = this.summarizeChildContext(childContext);
      contextItems.push({
        weight: 90,
        data: {
          role: MessageRole.SYSTEM,
          content: `Child Information:\n${childSummary}`,
        },
        tokenEstimate: childSummary.length / 4,
      });
    }

    // Recent activities (medium priority)
    if (recentActivities && recentActivities.length > 0) {
      const activitySummary = this.summarizeRecentActivities(recentActivities);
      contextItems.push({
        weight: 70,
        data: {
          role: MessageRole.SYSTEM,
          content: `Recent Activities:\n${activitySummary}`,
        },
        tokenEstimate: activitySummary.length / 4,
      });
    }

    // Conversation history (prioritize recent messages)
    conversationHistory.forEach((msg, index) => {
      const recencyWeight = 50 + (index / conversationHistory.length) * 30; // 50-80
      contextItems.push({
        weight: recencyWeight,
        data: msg,
        tokenEstimate: this.TOKENS_PER_MESSAGE,
      });
    });

    // Sort by weight (descending)
    contextItems.sort((a, b) => b.weight - a.weight);

    // Build final context within token limit
    const finalContext: ConversationMessage[] = [];
    let currentTokenCount = 0;

    for (const item of contextItems) {
      if (currentTokenCount + item.tokenEstimate <= this.MAX_TOKENS) {
        finalContext.push(item.data);
        currentTokenCount += item.tokenEstimate;
      } else {
        this.logger.log(
          `Context limit reached at ${currentTokenCount} tokens. Truncating remaining items.`,
        );
        break;
      }
    }

    // Re-order messages chronologically (except system messages)
    const systemMessages = finalContext.filter(
      (msg) => msg.role === MessageRole.SYSTEM,
    );
    const otherMessages = finalContext
      .filter((msg) => msg.role !== MessageRole.SYSTEM)
      .sort(
        (a, b) =>
          new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(),
      );

    return [...systemMessages, ...otherMessages];
  }

  /**
   * Build system prompt with safety boundaries and multi-child awareness
   */
  private buildSystemPrompt(userPreferences?: Record<string, any>): string {
    const language = userPreferences?.language || 'en';
    const tone = userPreferences?.tone || 'friendly';

    return `You are a helpful AI assistant for parents tracking their children's activities and milestones.

IMPORTANT GUIDELINES:
- You are NOT a medical professional. Always recommend consulting healthcare providers for medical concerns.
- Be supportive, encouraging, and non-judgmental in your responses.
- Focus on practical advice based on general parenting knowledge.
- If asked about serious medical issues, urge users to contact their pediatrician immediately.
- Respect cultural differences in parenting practices.
- Keep responses concise and actionable.

MULTI-CHILD FAMILY SUPPORT:
- When multiple children are in the family, pay attention to which child the parent is asking about.
- If a specific child's name is mentioned, focus your response on that child's age, stage, and patterns.
- If the question is ambiguous about which child, politely ask for clarification.
- When comparing or discussing siblings, be sensitive and avoid making judgments.
- Recognize that each child develops at their own pace.

USER PREFERENCES:
- Language: ${language}
- Tone: ${tone}

Your role is to:
1. Help interpret and log child activities (feeding, sleep, diaper changes, etc.)
2. Provide general developmental milestone information appropriate to each child's age
3. Offer encouragement and support to parents managing single or multiple children
4. Suggest patterns in children's behavior based on logged data
5. Answer general parenting questions (non-medical)
6. Handle multi-child context intelligently by identifying which child is being discussed

Remember: When in doubt, recommend professional consultation.`;
  }

  /**
   * Summarize child context for the AI (multi-child aware)
   */
  private summarizeChildContext(children: Child[]): string {
    if (children.length === 0) {
      return 'No children in family context.';
    }

    const childSummaries = children
      .map((child) => {
        const ageInMonths = this.calculateAgeInMonths(child.birthDate);
        const gender = child.gender ? ` (${child.gender})` : '';
        return `- ${child.name}${gender}: ${ageInMonths} months old, born ${child.birthDate.toDateString()}`;
      })
      .join('\n');

    // Add context about multiple children
    if (children.length > 1) {
      const names = children.map(c => c.name).join(', ');
      return `Family has ${children.length} children: ${names}\n\n${childSummaries}\n\nIMPORTANT: When user mentions a specific child name, focus your response on that child. If unclear which child, ask for clarification.`;
    }

    return childSummaries;
  }

  /**
   * Summarize recent activities
   */
  private summarizeRecentActivities(activities: Activity[]): string {
    const summary = activities.slice(0, 10).map((activity) => {
      const duration = activity.endedAt
        ? ` (${this.formatDuration(activity.startedAt, activity.endedAt)})`
        : '';
      return `- ${activity.type} at ${activity.startedAt.toLocaleString()}${duration}`;
    });
    return summary.join('\n');
  }

  /**
   * Calculate age in months
   */
  private calculateAgeInMonths(dateOfBirth: Date): number {
    const now = new Date();
    const months =
      (now.getFullYear() - dateOfBirth.getFullYear()) * 12 +
      (now.getMonth() - dateOfBirth.getMonth());
    return months;
  }

  /**
   * Format duration between two dates
   */
  private formatDuration(start: Date, end: Date): string {
    const durationMs = end.getTime() - start.getTime();
    const hours = Math.floor(durationMs / (1000 * 60 * 60));
    const minutes = Math.floor((durationMs % (1000 * 60 * 60)) / (1000 * 60));

    if (hours > 0) {
      return `${hours}h ${minutes}m`;
    }
    return `${minutes}m`;
  }

  /**
   * Estimate token count for text (rough approximation)
   */
  estimateTokenCount(text: string): number {
    // Rough estimate: 1 token ≈ 4 characters
    return Math.ceil(text.length / 4);
  }

  /**
   * Detect which child is being referenced in a message (multi-child support)
   */
  detectChildInMessage(
    message: string,
    availableChildren: Child[],
  ): Child | null {
    if (!availableChildren || availableChildren.length === 0) {
      return null;
    }

    const lowerMessage = message.toLowerCase();

    // Try to find child by exact name match
    for (const child of availableChildren) {
      const childNameLower = child.name.toLowerCase();

      // Check for name mentions with common patterns
      const patterns = [
        new RegExp(`\\b${childNameLower}\\b`, 'i'),  // Exact word match
        new RegExp(`\\b${childNameLower}'s\\b`, 'i'), // Possessive
        new RegExp(`\\bfor ${childNameLower}\\b`, 'i'), // "for Emma"
        new RegExp(`\\babout ${childNameLower}\\b`, 'i'), // "about Emma"
        new RegExp(`\\b${childNameLower} is\\b`, 'i'), // "Emma is"
        new RegExp(`\\b${childNameLower} has\\b`, 'i'), // "Emma has"
      ];

      for (const pattern of patterns) {
        if (pattern.test(lowerMessage)) {
          this.logger.log(
            `Detected child "${child.name}" in message via pattern match`,
          );
          return child;
        }
      }
    }

    // If only one child exists, default to that child
    if (availableChildren.length === 1) {
      return availableChildren[0];
    }

    return null;
  }
}
