import AsyncStorage from '@react-native-async-storage/async-storage';

export interface ChatMessage {
  id: string;
  role: 'user' | 'assistant' | 'system';
  content: string;
  timestamp: number;
}

export interface MovieContext {
  id: string;
  title: string;
  overview: string;
  releaseDate: string;
  released?: boolean;
  genres: string[];
  cast: Array<{
    name: string;
    character: string;
  }>;
  crew: Array<{
    name: string;
    job: string;
  }>;
  runtime?: number;
  tagline?: string;
  keywords?: string[];
}

export interface EpisodeContext {
  id: string;
  showId: string;
  showTitle: string;
  episodeTitle: string;
  seasonNumber: number;
  episodeNumber: number;
  overview: string;
  airDate: string;
  released: boolean;
  runtime?: number;
  cast: Array<{
    name: string;
    character: string;
  }>;
  crew: Array<{
    name: string;
    job: string;
  }>;
  guestStars?: Array<{
    name: string;
    character: string;
  }>;
}

export interface SeriesContext {
  id: string;
  title: string;
  overview: string;
  firstAirDate: string;
  lastAirDate?: string;
  totalSeasons: number;
  totalEpisodes: number;
  genres: string[];
  cast: Array<{
    name: string;
    character: string;
  }>;
  crew: Array<{
    name: string;
    job: string;
  }>;
  episodesBySeason: Record<number, Array<{
    seasonNumber: number;
    episodeNumber: number;
    title: string;
    airDate: string;
    released: boolean;
    overview?: string;
  }>>;
}

export type ContentContext = MovieContext | EpisodeContext | SeriesContext;

interface OpenRouterResponse {
  choices: Array<{
    message: {
      content: string;
      role: string;
    };
    finish_reason: string;
  }>;
  usage?: {
    prompt_tokens: number;
    completion_tokens: number;
    total_tokens: number;
  };
}

class AIService {
  private static instance: AIService;
  private apiKey: string | null = null;
  private baseUrl = 'https://openrouter.ai/api/v1';

  private constructor() {}

  static getInstance(): AIService {
    if (!AIService.instance) {
      AIService.instance = new AIService();
    }
    return AIService.instance;
  }

  async initialize(): Promise<boolean> {
    try {
      this.apiKey = await AsyncStorage.getItem('openrouter_api_key');
      return !!this.apiKey;
    } catch (error) {
      if (__DEV__) console.error('Failed to initialize AI service:', error);
      return false;
    }
  }

  async isConfigured(): Promise<boolean> {
    if (!this.apiKey) {
      await this.initialize();
    }
    return !!this.apiKey;
  }

  private createSystemPrompt(context: ContentContext): string {
    const isSeries = 'episodesBySeason' in (context as any);
    const isEpisode = !isSeries && 'showTitle' in (context as any);
    
    if (isSeries) {
      const series = context as SeriesContext;
      const currentDate = new Date().toISOString().split('T')[0];
      const seasonsSummary = Object.keys(series.episodesBySeason)
        .sort((a, b) => Number(a) - Number(b))
        .map(sn => {
          const episodes = series.episodesBySeason[Number(sn)] || [];
          const releasedCount = episodes.filter(e => e.released).length;
          return `- Season ${sn}: ${episodes.length} episodes (${releasedCount} released)`;
        })
        .join('\n');
      return `You are an AI assistant with access to current, up-to-date information about the TV series "${series.title}" across ALL seasons and episodes.

CRITICAL: Today's date is ${currentDate}. Use ONLY the verified information provided below from our database. IGNORE any conflicting information from your training data which may be outdated.

VERIFIED CURRENT SERIES INFORMATION FROM DATABASE:
- Title: ${series.title}
- First Air Date: ${series.firstAirDate || 'Unknown'}
- Last Air Date: ${series.lastAirDate || 'Unknown'}
- Seasons: ${series.totalSeasons}
- Episodes: ${series.totalEpisodes}
- Genres: ${series.genres.join(', ') || 'Unknown'}
- Synopsis: ${series.overview || 'No synopsis available'}

Cast:
${series.cast.map(c => `- ${c.name} as ${c.character}`).join('\n')}

Crew:
${series.crew.map(c => `- ${c.name} (${c.job})`).join('\n')}

Seasons & Episode Counts:
${seasonsSummary}

CRITICAL INSTRUCTIONS:
1. Never provide spoilers under any circumstances. Keep responses spoiler-safe.
2. The information above is from our verified database and is more current than your training data.
3. You can answer questions about ANY episode or season in the series. If dates indicate unreleased episodes, do not reveal plot details and clearly state they are unreleased.
4. Compare air dates to today's date (${currentDate}) to determine if an episode has already aired.
5. Base ALL responses on the verified information above, NOT on your training knowledge.
6. If asked about release dates or availability of episodes, refer ONLY to the database information provided.

FORMATTING RULES (use Markdown):
- Use short paragraphs separated by blank lines.
- Use clear headings (## or ###) when helpful.
- Use bullet lists for points and steps.
- Add a blank line before and after lists and headings.
- Keep lines concise; avoid giant unbroken blocks of text.
- Wrap inline code/terms with backticks only when appropriate.`;
    } else if (isEpisode) {
      const ep = context as EpisodeContext;
      const currentDate = new Date().toISOString().split('T')[0]; // YYYY-MM-DD format
      return `You are an AI assistant with access to current, up-to-date information about "${ep.showTitle}" Season ${ep.seasonNumber}, Episode ${ep.episodeNumber}: "${ep.episodeTitle}".

CRITICAL: Today's date is ${currentDate}. Use ONLY the verified information provided below from our database. IGNORE any conflicting information from your training data which is outdated.

VERIFIED CURRENT INFORMATION FROM DATABASE:
- Show: ${ep.showTitle}
- Episode: S${ep.seasonNumber}E${ep.episodeNumber} - "${ep.episodeTitle}"
- Air Date: ${ep.airDate || 'Unknown'}
- Release Status: ${ep.released ? 'RELEASED AND AVAILABLE FOR VIEWING' : 'Not Yet Released'}
- Runtime: ${ep.runtime ? `${ep.runtime} minutes` : 'Unknown'}
- Synopsis: ${ep.overview || 'No synopsis available'}

Cast:
${ep.cast.map(c => `- ${c.name} as ${c.character}`).join('\n')}

${ep.guestStars && ep.guestStars.length > 0 ? `Guest Stars:\n${ep.guestStars.map(g => `- ${g.name} as ${g.character}`).join('\n')}` : ''}

Crew:
${ep.crew.map(c => `- ${c.name} (${c.job})`).join('\n')}

CRITICAL INSTRUCTIONS:
1. Never provide spoilers under any circumstances. Always keep responses spoiler-safe.
2. The information above is from our verified database and is more current than your training data.
3. If Release Status shows "RELEASED AND AVAILABLE FOR VIEWING", the content IS AVAILABLE. Do not say it's "upcoming" or "unreleased".
4. Compare air dates to today's date (${currentDate}) to determine if something has already aired.
5. Base ALL responses on the verified information above, NOT on your training knowledge.
6. If asked about release dates or availability, refer ONLY to the database information provided.

FORMATTING RULES (use Markdown):
- Use short paragraphs separated by blank lines.
- Use clear headings (## or ###) when helpful.
- Use bullet lists for points, character lists, and steps.
- Add a blank line before and after lists and headings.
- Keep lines concise; avoid giant unbroken blocks of text.
- Wrap inline code/terms with backticks only when appropriate.
`;
    } else {
      const movie = context as MovieContext;
      const currentDate = new Date().toISOString().split('T')[0]; // YYYY-MM-DD format
      return `You are an AI assistant with access to current, verified information about the movie "${movie.title}".

CRITICAL: Today's date is ${currentDate}. Use ONLY the verified information provided below from our database. IGNORE any conflicting information from your training data which is outdated.

VERIFIED CURRENT MOVIE INFORMATION FROM DATABASE:
- Title: ${movie.title}
- Release Date: ${movie.releaseDate || 'Unknown'}
- Runtime: ${movie.runtime ? `${movie.runtime} minutes` : 'Unknown'}
- Genres: ${movie.genres.join(', ') || 'Unknown'}
- Tagline: ${movie.tagline || 'N/A'}
- Synopsis: ${movie.overview || 'No synopsis available'}

Cast:
${movie.cast.map(c => `- ${c.name} as ${c.character}`).join('\n')}

Crew:
${movie.crew.map(c => `- ${c.name} (${c.job})`).join('\n')}

${movie.keywords && movie.keywords.length > 0 ? `Keywords: ${movie.keywords.join(', ')}` : ''}

CRITICAL INSTRUCTIONS:
1. Never provide spoilers under any circumstances. Always keep responses spoiler-safe.
2. The information above is from our verified database and is more current than your training data.
3. Use the release date and today's date (${currentDate}) to determine availability - don't contradict database information.
4. Base ALL responses on the verified information above, NOT on your training knowledge.
5. If asked about release dates or availability, refer ONLY to the database information provided.
6. You can discuss themes, production, performances, and high-level plot setup without revealing twists, surprises, or outcomes.

FORMATTING RULES (use Markdown):
- Use short paragraphs separated by blank lines.
- Use clear headings (## or ###) when helpful.
- Use bullet lists for points and steps.
- Add a blank line before and after lists and headings.
- Keep lines concise; avoid giant unbroken blocks of text.

Answer questions about this movie using only the verified database information above, including plot analysis, character development, themes, cinematography, production notes, and trivia. Provide detailed, informative responses while remaining spoiler-safe.`;
    }
  }

  async sendMessage(
    message: string, 
    context: ContentContext, 
    conversationHistory: ChatMessage[] = []
  ): Promise<string> {
    if (!await this.isConfigured()) {
      throw new Error('AI service not configured. Please add your OpenRouter API key in settings.');
    }

    try {
      const systemPrompt = this.createSystemPrompt(context);
      
      // Prepare messages for API
      const messages = [
        { role: 'system', content: systemPrompt },
        ...conversationHistory
          .filter(msg => msg.role !== 'system')
          .slice(-10) // Keep last 10 messages for context
          .map(msg => ({
            role: msg.role,
            content: msg.content
          })),
        { role: 'user', content: message }
      ];

      if (__DEV__) {
        console.log('[AIService] Sending request to OpenRouter with context:', {
          contentType: 'showTitle' in context ? 'episode' : 'movie',
          title: 'showTitle' in context ? 
            `${(context as EpisodeContext).showTitle} S${(context as EpisodeContext).seasonNumber}E${(context as EpisodeContext).episodeNumber}` :
            (context as MovieContext).title,
          messageCount: messages.length
        });
      }

      const response = await fetch(`${this.baseUrl}/chat/completions`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.apiKey}`,
          'Content-Type': 'application/json',
          'HTTP-Referer': 'https://nuvio.app',
          'X-Title': 'Nuvio - AI Chat',
        },
        body: JSON.stringify({
          model: 'openrouter/sonoma-dusk-alpha',
          messages,
          max_tokens: 1000,
          temperature: 0.7,
          top_p: 0.9,
          frequency_penalty: 0.1,
          presence_penalty: 0.1,
        }),
      });

      if (!response.ok) {
        const errorText = await response.text();
        if (__DEV__) console.error('[AIService] API Error:', response.status, errorText);
        throw new Error(`API request failed: ${response.status} ${response.statusText}`);
      }

      const data: OpenRouterResponse = await response.json();
      
      if (!data.choices || data.choices.length === 0) {
        throw new Error('No response received from AI service');
      }

      const responseContent = data.choices[0].message.content;
      
      if (__DEV__ && data.usage) {
        console.log('[AIService] Token usage:', data.usage);
      }

      return responseContent;
    } catch (error) {
      if (__DEV__) console.error('[AIService] Error sending message:', error);
      throw error;
    }
  }

  // Helper method to create context from TMDB movie data
  static createMovieContext(movieData: any): MovieContext {
    if (__DEV__) {
      console.log('[AIService] Creating movie context from TMDB data:', {
        id: movieData.id,
        title: movieData.title || movieData.name,
        hasCredits: !!movieData.credits,
        castCount: movieData.credits?.cast?.length || 0,
        crewCount: movieData.credits?.crew?.length || 0,
        hasKeywords: !!(movieData.keywords?.keywords || movieData.keywords?.results),
        keywordCount: (movieData.keywords?.keywords || movieData.keywords?.results)?.length || 0,
        genreCount: movieData.genres?.length || 0,
        tmdbStatus: movieData.status,
        tmdbReleaseDate: movieData.release_date,
        tmdbReleaseDatesBlock: !!movieData.release_dates
      });
    }

    // Prefer US theatrical release date from release_dates if available
    let releaseDate: string = movieData.release_date || movieData.first_air_date || '';
    try {
      const groups = movieData.release_dates?.results as any[] | undefined;
      const us = groups?.find(g => g.iso_3166_1 === 'US');
      const theatric = us?.release_dates?.find((r: any) => r.type === 3 || r.type === 2 || r.type === 4);
      const anyDate = us?.release_dates?.[0]?.release_date || theatric?.release_date;
      if (anyDate) {
        // TMDB returns full ISO timestamps; keep only date part
        releaseDate = String(anyDate).split('T')[0];
      }
    } catch {}
    const statusText: string = (movieData.status || '').toString().toLowerCase();
    let released = statusText === 'released';
    if (!released && releaseDate) {
      const d = new Date(releaseDate);
      if (!isNaN(d.getTime())) released = d.getTime() <= Date.now();
    }
    if (!released) {
      const hasOverview = typeof movieData.overview === 'string' && movieData.overview.trim().length > 40;
      const hasRuntime = typeof movieData.runtime === 'number' && movieData.runtime > 0;
      const hasVotes = typeof movieData.vote_average === 'number' && movieData.vote_average > 0;
      if (hasOverview || hasRuntime || hasVotes) released = true;
    }

    if (__DEV__) {
      console.log('[AIService] Movie release resolution:', {
        resolvedReleaseDate: releaseDate,
        statusText: (movieData.status || '').toString(),
        computedReleased: released,
        today: new Date().toISOString().split('T')[0]
      });
    }

    return {
      id: movieData.id?.toString() || '',
      title: movieData.title || movieData.name || '',
      overview: movieData.overview || '',
      releaseDate,
      released,
      genres: movieData.genres?.map((g: any) => g.name) || [],
      cast: movieData.credits?.cast?.slice(0, 10).map((c: any) => ({
        name: c.name,
        character: c.character
      })) || [],
      crew: movieData.credits?.crew?.slice(0, 5).map((c: any) => ({
        name: c.name,
        job: c.job
      })) || [],
      runtime: movieData.runtime,
      tagline: movieData.tagline,
      keywords: movieData.keywords?.keywords?.map((k: any) => k.name) || 
               movieData.keywords?.results?.map((k: any) => k.name) || []
    };
  }

  // Helper method to create context from TMDB episode data
  static createEpisodeContext(
    episodeData: any, 
    showData: any, 
    seasonNumber: number, 
    episodeNumber: number
  ): EpisodeContext {
    // Compute release status from TMDB air date
    const airDate: string = episodeData.air_date || '';
    let released = false;
    try {
      if (airDate) {
        const parsed = new Date(airDate);
        if (!isNaN(parsed.getTime())) released = parsed.getTime() <= Date.now();
      }
    } catch {}
    // Heuristics: if TMDB provides meaningful content, treat as released
    if (!released) {
      const hasOverview = typeof episodeData.overview === 'string' && episodeData.overview.trim().length > 40;
      const hasRuntime = typeof episodeData.runtime === 'number' && episodeData.runtime > 0;
      const hasVotes = typeof episodeData.vote_average === 'number' && episodeData.vote_average > 0;
      if (hasOverview || hasRuntime || hasVotes) {
        released = true;
      }
    }
    if (__DEV__) {
      console.log('[AIService] Creating episode context from TMDB data:', {
        showId: showData.id,
        showTitle: showData.name || showData.title,
        episodeId: episodeData.id,
        episodeTitle: episodeData.name,
        season: seasonNumber,
        episode: episodeNumber,
        hasShowCredits: !!showData.credits,
        showCastCount: showData.credits?.cast?.length || 0,
        hasEpisodeCredits: !!episodeData.credits,
        episodeGuestStarsCount: episodeData.credits?.guest_stars?.length || 0,
        episodeCrewCount: episodeData.credits?.crew?.length || 0
      });
    }

    return {
      id: episodeData.id?.toString() || '',
      showId: showData.id?.toString() || '',
      showTitle: showData.name || showData.title || '',
      episodeTitle: episodeData.name || `Episode ${episodeNumber}`,
      seasonNumber,
      episodeNumber,
      overview: episodeData.overview || '',
      airDate,
      released,
      runtime: episodeData.runtime,
      cast: showData.credits?.cast?.slice(0, 8).map((c: any) => ({
        name: c.name,
        character: c.character
      })) || [],
      crew: episodeData.credits?.crew?.slice(0, 5).map((c: any) => ({
        name: c.name,
        job: c.job
      })) || showData.credits?.crew?.slice(0, 5).map((c: any) => ({
        name: c.name,
        job: c.job
      })) || [],
      guestStars: episodeData.credits?.guest_stars?.map((g: any) => ({
        name: g.name,
        character: g.character
      })) || []
    };
  }

  // Helper to create a series-wide context including all episodes
  static createSeriesContext(showData: any, episodesBySeason: Record<number, any[]>): SeriesContext {
    // Build flattened cast/crew from show credits
    const cast = showData.credits?.cast?.slice(0, 12).map((c: any) => ({
      name: c.name,
      character: c.character
    })) || [];
    const crew = showData.credits?.crew?.slice(0, 8).map((c: any) => ({
      name: c.name,
      job: c.job
    })) || [];

    // Normalize episodes map
    const normalized: SeriesContext['episodesBySeason'] = {};
    Object.keys(episodesBySeason || {}).forEach(k => {
      const seasonNum = Number(k);
      normalized[seasonNum] = (episodesBySeason[seasonNum] || []).map((ep: any) => {
        const airDate: string = ep.air_date || '';
        let released = false;
        try {
          if (airDate) {
            const parsed = new Date(airDate);
            if (!isNaN(parsed.getTime())) released = parsed.getTime() <= Date.now();
          }
        } catch {}
        if (!released) {
          const hasOverview = typeof ep.overview === 'string' && ep.overview.trim().length > 40;
          const hasRuntime = typeof ep.runtime === 'number' && ep.runtime > 0;
          const hasVotes = typeof ep.vote_average === 'number' && ep.vote_average > 0;
          if (hasOverview || hasRuntime || hasVotes) released = true;
        }
        return {
          seasonNumber: ep.season_number ?? seasonNum,
          episodeNumber: ep.episode_number,
          title: ep.name || `Episode ${ep.episode_number}`,
          airDate,
          released,
          overview: ep.overview || ''
        };
      });
    });

    const totalSeasons = Array.isArray(showData.seasons)
      ? showData.seasons.filter((s: any) => s.season_number > 0).length
      : Object.keys(normalized).length;
    const totalEpisodes = Object.values(normalized).reduce((sum, eps) => sum + (eps?.length || 0), 0);

    return {
      id: showData.id?.toString() || '',
      title: showData.name || showData.title || '',
      overview: showData.overview || '',
      firstAirDate: showData.first_air_date || '',
      lastAirDate: showData.last_air_date || '',
      totalSeasons,
      totalEpisodes,
      genres: showData.genres?.map((g: any) => g.name) || [],
      cast,
      crew,
      episodesBySeason: normalized,
    };
  }

  // Generate conversation starter suggestions
  static generateConversationStarters(context: ContentContext): string[] {
    const isSeries = 'episodesBySeason' in (context as any);
    const isEpisode = !isSeries && 'showTitle' in (context as any);

    if (isSeries) {
      const series = context as SeriesContext;
      return [
        `What is ${series.title} about overall?`,
        `Summarize key arcs across all seasons`,
        `Which episodes are the highest rated and why?`,
        `List pivotal episodes for character development`,
        `How did themes evolve from Season 1 onward?`
      ];
    } else if (isEpisode) {
      const ep = context as EpisodeContext;
      return [
        `What happened in this episode of ${ep.showTitle}?`,
        `Explain the main plot points of "${ep.episodeTitle}"`,
        `What character development occurred in this episode?`,
        `Are there any hidden details or easter eggs I might have missed?`,
        `How does this episode connect to the overall story arc?`
      ];
    } else {
      const movie = context as MovieContext;
      return [
        `What is ${movie.title} about?`,
        `Explain the themes in this movie`,
        `What's the significance of the ending?`,
        `Tell me about the main characters and their development`,
        `Are there any interesting production facts about this film?`
      ];
    }
  }
}

export const aiService = AIService.getInstance();

// Export static methods for easier access
export const createMovieContext = AIService.createMovieContext;
export const createEpisodeContext = AIService.createEpisodeContext;
export const generateConversationStarters = AIService.generateConversationStarters;
export const createSeriesContext = AIService.createSeriesContext;
