/**
 * Social Engine — Phase 2: Persona Router
 * Assigns detected trends to the most appropriate persona based on content_types,
 * weighted rotation, and heat thresholds.
 */
import { getActivePersonas, getPersonaDailyPostCount, getUnprocessedTrends } from './data-queries';
import type { PersonaConfig, TrendSignal, PersonaTrendPair } from './types';

// Content type → preferred persona mapping (fallback order)
const CONTENT_AFFINITY: Record<string, string[]> = {
  forecast_pick: ['the_sharp', 'the_degen', 'the_educator'],
  piff_prop: ['the_sharp', 'the_educator', 'the_degen'],
  breaking_news: ['the_sharp', 'the_culture_host', 'the_degen'],
  curated_news: ['the_educator', 'the_culture_host', 'the_sharp'],
  recap: ['the_sharp', 'the_degen', 'the_educator'],
  celebrity: ['the_culture_host', 'the_degen'],
  debate: ['the_culture_host'],
  hot_take: ['the_culture_host', 'the_degen'],
  model_explainer: ['the_educator'],
  trend_breakdown: ['the_educator', 'the_sharp'],
  stat_deep_dive: ['the_educator', 'the_sharp'],
  line_move: ['the_sharp', 'the_educator'],
  model_signal: ['the_sharp'],
  hype: ['the_degen'],
  trend_reaction: ['the_culture_host', 'the_degen'],
};

// Max posts per persona per day to maintain weighted balance
const MAX_DAILY_PER_PERSONA = 8;
const MAX_CONSECUTIVE_PERSONA_ASSIGNMENTS = 2;

export async function routeTrendsToPersonas(): Promise<PersonaTrendPair[]> {
  console.log('[social-engine] Phase 2: Routing trends to personas...');

  const personas = await getActivePersonas();
  const trends = await getUnprocessedTrends(20);

  if (trends.length === 0) {
    console.log('[social-engine] Phase 2: No unprocessed trends');
    return [];
  }

  if (personas.length === 0) {
    console.log('[social-engine] Phase 2: No active personas');
    return [];
  }

  // Get daily counts for weighted rotation
  const dailyCounts: Record<number, number> = {};
  for (const p of personas) {
    dailyCounts[p.id] = await getPersonaDailyPostCount(p.id);
  }

  const pairs: PersonaTrendPair[] = [];
  const recentSelections: string[] = [];

  for (const trend of trends) {
    const persona = selectPersona(trend, personas, dailyCounts, recentSelections);
    if (!persona) continue;

    pairs.push({ trend, persona });
    dailyCounts[persona.id] = (dailyCounts[persona.id] || 0) + 1;
    recentSelections.push(persona.slug);
    if (recentSelections.length > MAX_CONSECUTIVE_PERSONA_ASSIGNMENTS) {
      recentSelections.shift();
    }
  }

  console.log(`[social-engine] Phase 2 complete: ${pairs.length} (trend, persona) pairs created`);
  return pairs;
}

function selectPersona(
  trend: TrendSignal,
  personas: PersonaConfig[],
  dailyCounts: Record<number, number>,
  recentSelections: string[]
): PersonaConfig | null {
  // Culture Host only activates on heat > 50
  const eligible = personas.filter(p => {
    if (p.slug === 'the_culture_host' && trend.heat_score < 50) return false;
    if (dailyCounts[p.id] >= MAX_DAILY_PER_PERSONA) return false;
    return true;
  });

  if (eligible.length === 0) return null;

  const affinityOrder = CONTENT_AFFINITY[trend.trend_type] || [];
  const repeatedPersona = recentSelections.length === MAX_CONSECUTIVE_PERSONA_ASSIGNMENTS
    && recentSelections.every(slug => slug === recentSelections[0])
    ? recentSelections[0]
    : null;

  const typeMatches = eligible.filter(p => p.content_types.includes(trend.trend_type));
  const candidatePool = typeMatches.length > 0 ? typeMatches : eligible;

  const ranked = candidatePool
    .map((persona) => {
      const affinityIndex = affinityOrder.indexOf(persona.slug);
      const weightedLoad = (dailyCounts[persona.id] || 0) / Math.max(persona.weight, 1);
      const affinityScore = affinityIndex === -1 ? 10 : affinityIndex;
      const repetitionPenalty = repeatedPersona && persona.slug === repeatedPersona ? 5 : 0;

      return {
        persona,
        score: weightedLoad + affinityScore + repetitionPenalty,
      };
    })
    .sort((a, b) => a.score - b.score);

  return ranked[0]?.persona || null;
}
