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
   */
  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 baby'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.

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

Your role is to:
1. Help interpret and log baby activities (feeding, sleep, diaper changes, etc.)
2. Provide general developmental milestone information
3. Offer encouragement and support to parents
4. Suggest patterns in baby's behavior based on logged data
5. Answer general parenting questions (non-medical)

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

  /**
   * Summarize child context for the AI
   */
  private summarizeChildContext(children: Child[]): string {
    return children
      .map((child) => {
        const ageInMonths = this.calculateAgeInMonths(child.birthDate);
        return `- ${child.name}: ${ageInMonths} months old, born ${child.birthDate.toDateString()}`;
      })
      .join('\n');
  }

  /**
   * 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);
  }
}
