"""Research agent using Perplexity."""
import json
import random
import re
from datetime import datetime, timedelta, timezone
from typing import Dict, Any, List
from urllib.parse import urlparse
from loguru import logger

from src.agents.base import BaseAgent


class ResearchAgent(BaseAgent):
    """Agent for researching new content topics using Perplexity."""

    SOURCE_TIERS = {
        "tier_1_primary": {
            "domains": {
                "destatis.de", "bundesbank.de", "bmwk.de", "bmas.de", "bmbf.de",
                "europa.eu", "ec.europa.eu", "oecd.org", "weforum.org", "ilo.org",
                "who.int", "worldbank.org", "imf.org", "stanford.edu", "mit.edu",
                "harvard.edu", "ox.ac.uk", "cam.ac.uk", "nature.com", "science.org",
                "arxiv.org", "ssrn.com", "bitkom.org", "ifo.de", "iwkoeln.de",
                "iab.de", "fraunhofer.de", "acatech.de", "bertelsmann-stiftung.de"
            },
            "names": {
                "destatis", "bundesbank", "eu-kommission", "european commission",
                "oecd", "world economic forum", "stanford", "mit", "harvard",
                "nature", "science", "bitkom", "ifo institut", "fraunhofer",
                "institut der deutschen wirtschaft", "iab"
            },
            "label": "Primärquelle"
        },
        "tier_2_editorial": {
            "domains": {
                "handelsblatt.com", "faz.net", "manager-magazin.de", "wiwo.de",
                "sueddeutsche.de", "zeit.de", "spiegel.de", "tagesschau.de",
                "reuters.com", "bloomberg.com", "ft.com", "economist.com",
                "hbr.org", "mitsloan.mit.edu", "mckinsey.com", "bcg.com",
                "bain.com", "gartner.com", "forrester.com", "pwc.com",
                "deloitte.com", "kpmg.com", "ey.com", "accenture.com",
                "stackoverflow.blog", "stackoverflow.co", "github.blog"
            },
            "names": {
                "handelsblatt", "frankfurter allgemeine", "faz", "manager magazin",
                "wirtschaftswoche", "reuters", "bloomberg", "financial times",
                "harvard business review", "mit sloan", "mckinsey", "bcg",
                "bain", "gartner", "forrester", "pwc", "deloitte", "kpmg",
                "accenture", "stack overflow", "github"
            },
            "label": "Renommierte Sekundärquelle"
        },
        "tier_3_vendor": {
            "domains": {
                "microsoft.com", "google.com", "openai.com", "anthropic.com",
                "salesforce.com", "sap.com", "hubspot.com", "linkedin.com",
                "workday.com", "servicenow.com", "aws.amazon.com", "cloud.google.com"
            },
            "names": {
                "microsoft", "google", "openai", "anthropic", "salesforce",
                "sap", "hubspot", "linkedin", "workday", "servicenow", "aws"
            },
            "label": "Unternehmens-/Vendor-Quelle"
        }
    }

    def __init__(self):
        """Initialize research agent."""
        super().__init__("Researcher")

    async def process(
        self,
        profile_analysis: Dict[str, Any],
        existing_topics: List[str],
        customer_data: Dict[str, Any],
        example_posts: List[str] = None,
        post_type: Any = None,
        post_type_analysis: Dict[str, Any] = None,
        company_strategy: Dict[str, Any] = None,
        strategy_weight: float = 0.5
    ) -> Dict[str, Any]:
        """
        Research new content topics.

        Args:
            profile_analysis: Profile analysis results
            existing_topics: List of already covered topics
            customer_data: Customer data (contains persona, style_guide, etc.)
            example_posts: List of the person's actual posts for style reference
            post_type: Optional PostType object for targeted research
            post_type_analysis: Optional post type analysis for context
            company_strategy: Optional company strategy to align topics with
            strategy_weight: Strategy weight (0.0-1.0) controlling strategy influence

        Returns:
            Research results with suggested topics
        """
        logger.info("Starting research for new content topics")
        if post_type:
            logger.info(f"Targeting research for post type: {post_type.name}")

        # Extract key information from profile analysis
        audience_insights = profile_analysis.get("audience_insights", {})
        topic_patterns = profile_analysis.get("topic_patterns", {})

        industry = audience_insights.get("industry_context", "Business")
        target_audience = audience_insights.get("target_audience", "Professionals")
        content_pillars = topic_patterns.get("content_pillars", [])
        pain_points = audience_insights.get("pain_points_addressed", [])
        value_proposition = audience_insights.get("value_proposition", "")

        # Extract customer-specific data
        persona = customer_data.get("persona", "") if customer_data else ""

        # STEP 1: Use Perplexity for REAL internet research (has live data!)
        logger.info("Step 1: Researching with Perplexity (live internet data)")
        perplexity_prompt = self._get_perplexity_prompt(
            industry=industry,
            target_audience=target_audience,
            content_pillars=content_pillars,
            existing_topics=existing_topics,
            pain_points=pain_points,
            persona=persona
        )

        # Dynamic system prompt for variety
        system_prompts = [
            "Du bist ein investigativer Journalist. Finde die neuesten, spannendsten Entwicklungen mit harten Fakten.",
            "Du bist ein Branchen-Analyst. Identifiziere aktuelle Trends und Marktbewegungen mit konkreten Daten.",
            "Du bist ein Trend-Scout. Spüre auf, was diese Woche wirklich neu und relevant ist.",
            "Du bist ein Research-Spezialist. Finde aktuelle Studien, Statistiken und News mit Quellenangaben."
        ]

        raw_research = await self._research_with_provider(
            system_prompt=random.choice(system_prompts),
            user_prompt=perplexity_prompt
        )

        logger.info("Step 2: Transforming research into personalized topic ideas")
        # STEP 2: Transform raw research into PERSONALIZED topic suggestions
        transform_prompt = self._get_transform_prompt(
            raw_research=raw_research,
            target_audience=target_audience,
            persona=persona,
            content_pillars=content_pillars,
            example_posts=example_posts or [],
            existing_topics=existing_topics,
            post_type=post_type,
            post_type_analysis=post_type_analysis,
            company_strategy=company_strategy,
            strategy_weight=strategy_weight
        )

        response = await self.call_openai(
            system_prompt=self._get_topic_creator_system_prompt(),
            user_prompt=transform_prompt,
            model="gpt-4o",
            temperature=0.35,
            response_format={"type": "json_object"}
        )

        # Parse JSON response
        result = json.loads(response)
        suggested_topics = result.get("topics", [])

        # STEP 3: Quality gate + diversity
        suggested_topics = self._quality_gate_topics(
            suggested_topics,
            persona=persona,
            content_pillars=content_pillars,
            target_audience=target_audience,
            existing_topics=existing_topics,
            example_posts=example_posts or []
        )
        suggested_topics = self._ensure_diversity(suggested_topics)

        # Parse research results
        research_results = {
            "raw_response": response,
            "suggested_topics": suggested_topics,
            "industry": industry,
            "target_audience": target_audience
        }

        logger.info(f"Research completed with {len(research_results['suggested_topics'])} topic suggestions")
        return research_results

    async def _research_with_provider(self, system_prompt: str, user_prompt: str) -> str:
        """Run live web research through the current provider.

        This method intentionally keeps Perplexity isolated so the provider can be
        swapped for Azure/Exa/Tavily/Brave without rewriting topic transformation.
        """
        return await self.call_perplexity(
            system_prompt=system_prompt,
            user_prompt=user_prompt,
            model="sonar-pro"
        )

    def _get_topic_creator_system_prompt(self) -> str:
        """Get system prompt for transforming research into personalized topics."""
        return """Du bist ein LinkedIn Content-Stratege, der aus Recherche-Ergebnissen KONKRETE, PERSONALISIERTE Themenvorschläge erstellt.

WICHTIG: Du erstellst KEINE Schlagzeilen oder News-Titel!
Du erstellst KONKRETE CONTENT-IDEEN mit:
- Einem klaren ANGLE (Perspektive/Blickwinkel)
- Einer konkreten HOOK-IDEE
- Einem NARRATIV das die Person erzählen könnte

Der Unterschied:
❌ SCHLECHT (Schlagzeile): "KI verändert den Arbeitsmarkt"
✅ GUT (Themenvorschlag): "Warum ich als [Rolle] plötzlich 50% meiner Zeit mit KI-Prompts verbringe - und was das für mein Team bedeutet"

❌ SCHLECHT: "Neue Studie zu Remote Work"
✅ GUT: "3 Erkenntnisse aus der Stanford Remote-Studie, die mich als Führungskraft überrascht haben"

❌ SCHLECHT: "Fachkräftemangel in der IT"
✅ GUT: "Unpopuläre Meinung: Wir haben keinen Fachkräftemangel - wir haben ein Ausbildungsproblem. Hier ist was ich damit meine..."

Deine Themenvorschläge müssen:
1. ZUR PERSON PASSEN - Klingt wie etwas das diese spezifische Person posten würde
2. EINEN KONKRETEN ANGLE HABEN - Nicht "über X schreiben" sondern "diesen spezifischen Aspekt von X aus dieser Perspektive beleuchten"
3. EINEN HOOK VORSCHLAGEN - Eine konkrete Idee wie der Post starten könnte
4. HINTERGRUND-INFOS LIEFERN - Fakten/Daten aus der Recherche die die Person nutzen kann
5. ABWECHSLUNGSREICH SEIN - Verschiedene Formate und Kategorien
6. QUELLENTREU BLEIBEN - Nur Fakten aus den Recherche-Ergebnissen verwenden, keine Zahlen erfinden
7. REDAKTIONELL FILTERN - Wenn Quelle, Datum oder Fakt schwach sind, keinen Themenvorschlag daraus machen

Antworte als JSON."""

    def _get_system_prompt(self) -> str:
        """Get system prompt for research (legacy, kept for compatibility)."""
        return """Du bist ein hochspezialisierter Trend-Analyst und Content-Researcher.

Deine Mission ist es, aktuelle, hochrelevante Content-Themen für LinkedIn zu identifizieren.

Du sollst:
1. Aktuelle Trends, News und Diskussionen der letzten 7-14 Tage recherchieren
2. Themen finden, die für die spezifische Zielgruppe relevant sind
3. Verschiedene Kategorien abdecken:
   - Aktuelle News & Studien
   - Schmerzpunkt-Lösungen
   - Konträre Trends (gegen Mainstream-Meinung)
   - Emerging Topics

Für jedes Thema sollst du bereitstellen:
- Einen prägnanten Titel
- Den Kern-Fakt (mit Daten, Quellen, Beispielen)
- Warum es relevant ist für die Zielgruppe
- Die Kategorie

Fokussiere dich auf Themen, die:
- AKTUELL sind (letzte 1-2 Wochen)
- KONKRET sind (mit Daten/Fakten belegt)
- RELEVANT sind für die Zielgruppe
- UNIQUE sind (nicht bereits behandelt)

Gib deine Antwort als JSON zurück."""

    def _get_user_prompt(
        self,
        industry: str,
        target_audience: str,
        content_pillars: List[str],
        existing_topics: List[str],
        pain_points: List[str] = None,
        value_proposition: str = "",
        persona: str = ""
    ) -> str:
        """Get user prompt for research."""
        pillars_text = ", ".join(content_pillars) if content_pillars else "Verschiedene Business-Themen"
        existing_text = ", ".join(existing_topics[:20]) if existing_topics else "Keine"
        pain_points_text = ", ".join(pain_points) if pain_points else "Nicht spezifiziert"

        # Build persona section if available
        persona_section = ""
        if persona:
            persona_section = f"""
**PERSONA DER PERSON (WICHTIG - Themen müssen zu dieser Expertise passen!):**
{persona[:800]}
"""

        return f"""Recherchiere aktuelle LinkedIn-Content-Themen für folgendes Profil:

**KONTEXT:**
- Branche: {industry}
- Zielgruppe: {target_audience}
- Content-Säulen: {pillars_text}
- Pain Points der Zielgruppe: {pain_points_text}
- Value Proposition: {value_proposition or 'Mehrwert für die Zielgruppe bieten'}
{persona_section}
**BEREITS BEHANDELTE THEMEN (diese NICHT vorschlagen):**
{existing_text}

**AUFGABE:**
Finde 5-7 verschiedene aktuelle Themen, die:
1. ZUR EXPERTISE/PERSONA der Person passen
2. Die PAIN POINTS der Zielgruppe addressieren
3. AUTHENTISCH von dieser Person kommen könnten
4. NICHT generisch oder beliebig sind

Kategorien:
1. **News-Flash**: Aktuelle Nachrichten, Studien oder Entwicklungen
2. **Schmerzpunkt-Löser**: Probleme/Diskussionen, die die Zielgruppe aktuell beschäftigen
3. **Konträrer Trend**: Entwicklungen, die gegen die herkömmliche Meinung verstoßen
4. **Emerging Topic**: Neue Trends, die gerade an Fahrt gewinnen

WICHTIG: Themen müssen zur Person passen! Ein Experte für {industry} würde keine generischen "Productivity-Tips" posten, sondern spezifische Insights aus seinem Fachgebiet.

Fokus auf deutsche/DACH-Region relevante Themen.

Gib deine Antwort im folgenden JSON-Format zurück:

{{
  "topics": [
    {{
      "title": "Prägnanter Arbeitstitel (spezifisch, nicht generisch!)",
      "category": "News-Flash / Schmerzpunkt-Löser / Konträrer Trend / Emerging Topic",
      "fact": "Detaillierte Zusammenfassung mit Daten, Fakten, Beispielen - SPEZIFISCH für diese Branche",
      "relevance": "Warum ist das für {target_audience} wichtig und warum sollte DIESE Person darüber schreiben?",
      "source": "Quellenangaben (Studien, Artikel, Statistiken)"
    }}
  ]
}}"""

    def _get_perplexity_prompt(
        self,
        industry: str,
        target_audience: str,
        content_pillars: List[str],
        existing_topics: List[str],
        pain_points: List[str] = None,
        persona: str = ""
    ) -> str:
        """Get prompt for Perplexity research (optimized for live internet search)."""
        pillars_text = ", ".join(content_pillars) if content_pillars else "Business-Themen"
        existing_text = ", ".join(existing_topics[:20]) if existing_topics else "Keine bisherigen Themen"
        pain_points_text = ", ".join(pain_points) if pain_points else "Allgemeine Business-Probleme"

        # Current date for time-specific searches
        today = datetime.now(timezone.utc)
        date_str = today.strftime("%d. %B %Y")
        week_ago = (today - timedelta(days=7)).strftime("%d. %B %Y")

        persona_hint = ""
        if persona:
            persona_hint = f"\nEXPERTISE DER PERSON: {persona[:600]}\n"

        trusted_sources = self._trusted_sources_prompt()

        # Randomize the research focus for variety
        research_angles = [
            {
                "name": "Breaking News & Studien",
                "focus": "Suche nach brandneuen Studien, Reports, Umfragen oder Nachrichten",
                "examples": "Neue Statistiken, Forschungsergebnisse, Unternehmens-Announcements"
            },
            {
                "name": "Kontroverse & Debatten",
                "focus": "Suche nach aktuellen Kontroversen, Meinungsverschiedenheiten, heißen Diskussionen",
                "examples": "Polarisierende Meinungen, Kritik an Trends, unerwartete Entwicklungen"
            },
            {
                "name": "Technologie & Innovation",
                "focus": "Suche nach neuen Tools, Technologien, Methoden die gerade aufkommen",
                "examples": "Neue Software, AI-Entwicklungen, Prozess-Innovationen"
            },
            {
                "name": "Markt & Wirtschaft",
                "focus": "Suche nach wirtschaftlichen Entwicklungen, Marktveränderungen, Branchen-Shifts",
                "examples": "Fusionen, Insolvenzen, Markteintritt, Regulierungen"
            },
            {
                "name": "Menschen & Karriere",
                "focus": "Suche nach Personalien, Karriere-Trends, Arbeitsmarkt-Entwicklungen",
                "examples": "Führungswechsel, Hiring-Trends, Remote Work Updates, Skill-Demands"
            },
            {
                "name": "Fails & Learnings",
                "focus": "Suche nach öffentlichen Fehlern, Shitstorms, Lessons Learned",
                "examples": "PR-Desaster, gescheiterte Launches, öffentliche Kritik"
            }
        ]

        # Pick 3-4 random angles for this research session
        selected_angles = random.sample(research_angles, min(4, len(research_angles)))
        angles_text = "\n".join([
            f"- **{angle['name']}**: {angle['focus']} (z.B. {angle['examples']})"
            for angle in selected_angles
        ])

        # Random seed words for more variety
        seed_variations = [
            f"Was ist DIESE WOCHE ({week_ago} bis {date_str}) passiert in {industry}?",
            f"Welche BREAKING NEWS gibt es HEUTE ({date_str}) oder diese Woche in {industry}?",
            f"Was diskutiert die {industry}-Branche AKTUELL ({date_str})?",
            f"Welche NEUEN Entwicklungen gibt es seit {week_ago} in {industry}?"
        ]
        seed_question = random.choice(seed_variations)

        return f"""AKTUELLES DATUM: {date_str}

{seed_question}
{persona_hint}
KONTEXT:
- Branche: {industry}
- Zielgruppe: {target_audience}
- Themen-Fokus: {pillars_text}
- Pain Points: {pain_points_text}

RECHERCHE-SCHWERPUNKTE FÜR DIESE SESSION:
{angles_text}

BEVORZUGTE RENOMMIERTE QUELLEN:
{trusted_sources}

⛔ BEREITS BEHANDELTE THEMEN - NICHT NOCHMAL VORSCHLAGEN:
{existing_text}

=== DEINE AUFGABE ===

Recherchiere FAKTEN, DATEN und ENTWICKLUNGEN aus renommierten Quellen - keine fertigen Themenvorschläge!
Ich brauche ROHDATEN die ich dann in personalisierte Content-Ideen umwandeln kann.

Für jede Entwicklung/News sammle:
1. **Was genau ist passiert?** - Konkrete Fakten, nicht Interpretationen
2. **Zahlen & Daten** - Statistiken, Prozentsätze, Beträge, Veränderungen
3. **Wer ist beteiligt?** - Unternehmen, Personen, Organisationen
4. **Wann?** - Genaues Datum oder Zeitraum
5. **Quelle** - URL, Publikationsname und falls möglich Autor/Organisation
6. **Kontext** - Warum ist das relevant? Was bedeutet es?
7. **Quellenqualität** - Primärquelle, renommierte Sekundärquelle oder Vendor/Unternehmensquelle

SUCHE NACH:
✅ Neue Studien/Reports mit konkreten Zahlen
✅ Unternehmens-Entscheidungen oder -Ankündigungen
✅ Marktveränderungen mit Daten
✅ Gesetzliche/Regulatorische Änderungen
✅ Kontroverse Aussagen von Branchenführern
✅ Überraschende Statistiken oder Trends
✅ Gescheiterte Projekte oder unerwartete Erfolge

FORMAT DEINER ANTWORT:
Liefere 8-10 verschiedene Entwicklungen/News mit möglichst vielen Fakten und Zahlen.
Formatiere sie klar und strukturiert.

QUALITÄTSKRITERIEN (streng):
✅ QUELLE: Bevorzuge Primärquellen, offizielle Reports, renommierte Wirtschafts-/Fachmedien
✅ AKTUALITÄT: Möglichst letzte 30 Tage; bei Studien/Reports maximal 12 Monate, wenn sie substanziell sind
✅ KONKRETHEIT: Echte Zahlen, Namen, Daten (nicht "Experten sagen...")
✅ VERIFIZIERBARKEIT: Echte Quelle die man prüfen kann
✅ BRANCHENRELEVANZ: Spezifisch für {industry}

❌ VERMEIDE:
- Vage Aussagen ohne Daten ("KI wird wichtiger")
- Generische Trends ohne konkreten Aufhänger
- Alte News die jeder schon kennt
- Themen ohne verifizierbare Fakten
- SEO-Listen, Content-Farmen, reine Meinungsblogs ohne Primärdaten
- Quellen, die nur andere Quellen zusammenfassen und keinen eigenen Beleg liefern"""

    def _get_transform_prompt(
        self,
        raw_research: str,
        target_audience: str,
        persona: str,
        content_pillars: List[str],
        example_posts: List[str],
        existing_topics: List[str],
        post_type: Any = None,
        post_type_analysis: Dict[str, Any] = None,
        company_strategy: Dict[str, Any] = None,
        strategy_weight: float = 0.5
    ) -> str:
        """Transform raw research into personalized, concrete topic suggestions."""

        # Build example posts section
        examples_section = ""
        if example_posts:
            examples_section = "\n\n=== SO SCHREIBT DIESE PERSON (Beispiel-Posts) ===\n"
            for i, post in enumerate(example_posts[:5], 1):
                post_preview = post[:600] + "..." if len(post) > 600 else post
                examples_section += f"\n--- Beispiel {i} ---\n{post_preview}\n"
            examples_section += "--- Ende Beispiele ---\n"

        # Build pillars section
        pillars_text = ", ".join(content_pillars[:5]) if content_pillars else "Keine spezifischen Säulen"

        # Build existing topics section (to avoid)
        existing_text = ", ".join(existing_topics[:15]) if existing_topics else "Keine"

        # Build post type context section
        post_type_section = ""
        if post_type:
            post_type_section = f"""

=== ZIEL-POST-TYP: {post_type.name} ===
{f"Beschreibung: {post_type.description}" if post_type.description else ""}
{f"Typische Hashtags: {', '.join(post_type.identifying_hashtags[:5])}" if post_type.identifying_hashtags else ""}
{f"Keywords: {', '.join(post_type.identifying_keywords[:10])}" if post_type.identifying_keywords else ""}
"""
            if post_type.semantic_properties:
                props = post_type.semantic_properties
                if props.get("purpose"):
                    post_type_section += f"Zweck: {props['purpose']}\n"
                if props.get("typical_tone"):
                    post_type_section += f"Tonalität: {props['typical_tone']}\n"
                if props.get("target_audience"):
                    post_type_section += f"Zielgruppe: {props['target_audience']}\n"

            if post_type_analysis and post_type_analysis.get("sufficient_data"):
                post_type_section += "\n**Analyse-basierte Anforderungen:**\n"
                if hooks := post_type_analysis.get("hooks"):
                    post_type_section += f"- Hook-Typen: {', '.join(hooks.get('hook_types', [])[:3])}\n"
                if content := post_type_analysis.get("content_focus"):
                    post_type_section += f"- Hauptthemen: {', '.join(content.get('main_themes', [])[:3])}\n"
                    if content.get("target_emotion"):
                        post_type_section += f"- Ziel-Emotion: {content['target_emotion']}\n"

            post_type_section += "\n**WICHTIG:** Alle Themenvorschläge müssen zu diesem Post-Typ passen!\n"

        # Build company strategy section
        strategy_section = self._get_strategy_section(company_strategy, strategy_weight)

        return f"""AUFGABE: Transformiere die Recherche-Ergebnisse in KONKRETE, PERSONALISIERTE Themenvorschläge.
{post_type_section}{strategy_section}

=== RECHERCHE-ERGEBNISSE (Rohdaten) ===
{raw_research}

=== PERSON/EXPERTISE ===
{persona[:800] if persona else "Keine Persona definiert"}

=== CONTENT-SÄULEN DER PERSON ===
{pillars_text}
{examples_section}
=== BEREITS BEHANDELT (NICHT NOCHMAL!) ===
{existing_text}

=== DEINE AUFGABE ===

Erstelle 6-8 KONKRETE Themenvorschläge die:
1. ZU DIESER PERSON PASSEN - Basierend auf Expertise und Beispiel-Posts
2. EINEN KLAREN ANGLE HABEN - Nicht "über X schreiben" sondern eine spezifische Perspektive
3. FAKTEN AUS DER RECHERCHE NUTZEN - Konkrete Daten/Zahlen einbauen
4. ABWECHSLUNGSREICH SIND - Verschiedene Kategorien und Formate

KATEGORIEN (mindestens 3 verschiedene!):
- **Meinung/Take**: Deine Perspektive zu einem aktuellen Thema
- **Erfahrungsbericht**: "Was ich gelernt habe als..."
- **Konträr**: "Unpopuläre Meinung: ..."
- **How-To/Insight**: Konkrete Tipps basierend auf Daten
- **Story**: Persönliche Geschichte mit Business-Lesson
- **Analyse**: Daten/Trend analysiert durch deine Expertise-Brille

FORMAT DER THEMENVORSCHLÄGE:

{{
  "topics": [
    {{
      "title": "Konkreter Thementitel (kein Schlagzeilen-Stil!)",
      "category": "Meinung/Take | Erfahrungsbericht | Konträr | How-To/Insight | Story | Analyse",
      "angle": "Der spezifische Blickwinkel/die Perspektive für diesen Post",
      "hook_idea": "Konkrete Hook-Idee die zum Post passen würde (1-2 Sätze)",
      "fact": "Kurzer, konkreter Kernfakt für die bestehende Topic-Auswahl in der UI",
      "relevance": "Warum ist das für die Zielgruppe relevant?",
      "key_facts": ["Fakt 1 aus der Recherche", "Fakt 2 mit Zahlen", "Fakt 3"],
      "why_this_person": "Warum passt dieses Thema zu DIESER Person und ihrer Expertise?",
      "source": "Konkrete Quellenangabe mit URL oder Publikationsname",
      "source_title": "Titel der Quelle / Studie / Meldung",
      "source_domain": "Domain falls URL vorhanden",
      "published_at": "Publikationsdatum oder Zeitraum falls bekannt",
      "evidence": ["Beleg 1 aus Quelle", "Beleg 2 aus Quelle"],
      "source_quality": "Primärquelle | Renommierte Sekundärquelle | Vendor/Unternehmensquelle",
      "fit_reason": "Warum ist der Angle für diese Person glaubwürdig?"
    }}
  ]
}}

BEISPIEL EINES GUTEN THEMENVORSCHLAGS:
{{
  "title": "Warum ich als Tech-Lead jetzt 30% meiner Zeit mit Prompt Engineering verbringe",
  "category": "Erfahrungsbericht",
  "angle": "Persönliche Erfahrung eines Tech-Leads mit der Veränderung seiner Rolle durch KI",
  "hook_idea": "Vor einem Jahr habe ich Code geschrieben. Heute schreibe ich Prompts. Und ehrlich? Ich weiß noch nicht ob das gut oder schlecht ist.",
  "fact": "KI-Tools verändern Entwicklungsarbeit messbar: viele Teams sparen Zeit beim Coden, investieren aber mehr in Review und Qualitätssicherung.",
  "relevance": "Für technische Führungskräfte ist nicht nur Produktivität relevant, sondern wie sich Verantwortung, Review-Prozesse und Teamrollen verändern.",
  "key_facts": ["GitHub Copilot wird von 92% der Entwickler genutzt (Stack Overflow 2024)", "Durchschnittliche Zeitersparnis: 55%", "Aber: Code-Review-Zeit +40%"],
  "why_this_person": "Als Tech-Lead hat die Person direkten Einblick in diese Veränderung und kann authentisch darüber berichten",
  "source": "Stack Overflow Developer Survey 2024",
  "source_title": "Stack Overflow Developer Survey 2024",
  "source_domain": "stackoverflow.co",
  "published_at": "2024",
  "evidence": ["92% der Entwickler nutzen KI-Tools oder planen es", "Konkrete Aussagen zur Nutzung von KI im Entwicklungsworkflow"],
  "source_quality": "Primärquelle",
  "fit_reason": "Direkter Bezug zu Rolle, Teamalltag und technischen Entscheidungen"
}}

WICHTIG:
- Jeder Vorschlag muss sich UNTERSCHEIDEN (anderer Angle, andere Kategorie)
- Keine generischen "Die Zukunft von X" Themen
- Hook-Ideen müssen zum Stil der Beispiel-Posts passen!
- Key Facts müssen aus der Recherche stammen (keine erfundenen Zahlen)
- Verwirf Rohdaten mit schwacher Quelle statt sie kreativ umzudeuten
- Jeder Vorschlag braucht eine erkennbare, konkrete Quelle"""

    def _trusted_sources_prompt(self) -> str:
        """Return a compact source policy for the research provider prompt."""
        return """Tier 1 bevorzugen: offizielle Reports/Studien/Primärquellen (Destatis, Bundesbank, EU/OECD/WEF/ILO/World Bank/IMF, Universitäten, Fraunhofer, Ifo, Bitkom, Stack Overflow Survey, Unternehmensberichte).
Tier 2 zulässig: renommierte Wirtschafts- und Fachmedien oder Beratungs-/Researchhäuser (Handelsblatt, FAZ, Manager Magazin, WiWo, Reuters, Bloomberg, FT, HBR, MIT Sloan, McKinsey, BCG, Gartner, Forrester, Deloitte, PwC).
Tier 3 nur mit Vorsicht: Vendor-/Unternehmensblogs, wenn sie Primärdaten, Produktankündigungen oder konkrete Reports enthalten.
Nicht verwenden: SEO-Content, generische Trendlisten, Content-Farmen, reine Meinungsblogs ohne überprüfbare Daten."""

    def _extract_domain(self, source: str) -> str:
        """Extract a normalized domain from a source string or URL."""
        if not source:
            return ""
        urls = re.findall(r"https?://[^\s),\]]+", source)
        candidate = urls[0] if urls else source.strip().split()[0]
        parsed = urlparse(candidate if "://" in candidate else f"https://{candidate}")
        domain = (parsed.netloc or parsed.path).lower().strip("/")
        if domain.startswith("www."):
            domain = domain[4:]
        return domain

    def _domain_matches(self, domain: str, configured_domain: str) -> bool:
        configured_domain = configured_domain.lower()
        return domain == configured_domain or domain.endswith(f".{configured_domain}")

    def _classify_source(self, topic: Dict[str, Any]) -> Dict[str, str]:
        """Classify the source into a source tier using URL/domain and publication names."""
        source_text = " ".join([
            str(topic.get("source", "") or ""),
            str(topic.get("source_title", "") or ""),
            str(topic.get("source_domain", "") or ""),
        ]).lower()
        domain = self._extract_domain(source_text)

        for tier, config in self.SOURCE_TIERS.items():
            for configured_domain in config["domains"]:
                if domain and self._domain_matches(domain, configured_domain):
                    return {"source_tier": tier, "source_domain": domain, "source_quality": config["label"]}
            for name in config["names"]:
                if name in source_text:
                    return {"source_tier": tier, "source_domain": domain, "source_quality": config["label"]}

        return {
            "source_tier": "unverified",
            "source_domain": domain,
            "source_quality": "Nicht klassifizierte Quelle"
        }

    def _keyword_set(self, values: List[Any], limit: int = 80) -> set:
        """Extract a compact set of meaningful keywords for heuristics."""
        text_parts: List[str] = []
        for value in values:
            if isinstance(value, str):
                text_parts.append(value)
            elif isinstance(value, list):
                text_parts.extend([str(v) for v in value if v])
        text = " ".join(text_parts).lower()
        words = re.findall(r"\b[a-zA-ZäöüÄÖÜß][a-zA-ZäöüÄÖÜß\-]{3,}\b", text)
        stop_words = {
            "dass", "oder", "aber", "eine", "einer", "einem", "einen", "diese", "dieser",
            "dieses", "nicht", "auch", "mehr", "über", "unter", "durch", "thema", "werden",
            "wurde", "sind", "kann", "sich", "their", "about", "with", "from", "this",
            "that", "into", "professionals", "business"
        }
        result = []
        seen = set()
        for word in words:
            if word in stop_words or word in seen:
                continue
            seen.add(word)
            result.append(word)
            if len(result) >= limit:
                break
        return set(result)

    def _score_topic_quality(
        self,
        topic: Dict[str, Any],
        persona_keywords: set,
        existing_keywords: set
    ) -> float:
        """Score a topic for source quality, evidence, specificity and person fit."""
        score = 0.0
        tier = topic.get("source_tier", "unverified")
        if tier == "tier_1_primary":
            score += 5.0
        elif tier == "tier_2_editorial":
            score += 4.0
        elif tier == "tier_3_vendor":
            score += 2.0
        else:
            score -= 2.0

        text_values = [
            topic.get("title", ""),
            topic.get("angle", ""),
            topic.get("fact", ""),
            topic.get("why_this_person", ""),
            topic.get("fit_reason", ""),
            topic.get("relevance", ""),
            topic.get("key_facts", []),
            topic.get("evidence", []),
        ]
        topic_keywords = self._keyword_set(text_values, limit=80)
        overlap = topic_keywords.intersection(persona_keywords)
        score += min(len(overlap), 6) * 0.7

        if topic.get("why_this_person") or topic.get("fit_reason"):
            score += 1.5
        if topic.get("angle"):
            score += 1.0
        if topic.get("evidence") and isinstance(topic.get("evidence"), list):
            score += min(len(topic["evidence"]), 3) * 0.8
        if topic.get("key_facts") and isinstance(topic.get("key_facts"), list):
            score += min(len(topic["key_facts"]), 3) * 0.6
        if re.search(r"\d", " ".join([str(v) for v in text_values])):
            score += 1.0
        if not topic.get("source"):
            score -= 4.0
        if len(topic_keywords.intersection(existing_keywords)) >= 5:
            score -= 2.0

        return round(score, 2)

    def _quality_gate_topics(
        self,
        topics: List[Dict[str, Any]],
        persona: str,
        content_pillars: List[str],
        target_audience: str,
        existing_topics: List[str],
        example_posts: List[str]
    ) -> List[Dict[str, Any]]:
        """Normalize, score and filter researched topics before they reach the UI."""
        if not isinstance(topics, list):
            return []

        persona_keywords = self._keyword_set(
            [persona, content_pillars, target_audience, example_posts[:5]],
            limit=120
        )
        existing_keywords = self._keyword_set(existing_topics[:30], limit=160)

        processed: List[Dict[str, Any]] = []
        seen_titles = set()
        for topic in topics:
            if not isinstance(topic, dict):
                continue
            title = str(topic.get("title", "") or "").strip()
            if not title:
                continue
            title_key = re.sub(r"\s+", " ", title.lower())
            if title_key in seen_titles:
                continue
            seen_titles.add(title_key)

            source_info = self._classify_source(topic)
            normalized = dict(topic)
            normalized.update({k: v for k, v in source_info.items() if v})
            if not normalized.get("fact") and isinstance(normalized.get("key_facts"), list) and normalized["key_facts"]:
                normalized["fact"] = str(normalized["key_facts"][0])
            if not normalized.get("source_quality") or normalized.get("source_quality") == "Nicht klassifizierte Quelle":
                normalized["source_quality"] = source_info["source_quality"]
            if not normalized.get("source_domain") and source_info.get("source_domain"):
                normalized["source_domain"] = source_info["source_domain"]

            quality_score = self._score_topic_quality(normalized, persona_keywords, existing_keywords)
            normalized["research_quality_score"] = quality_score
            normalized["research_provider"] = "perplexity"

            # Keep strong unknown-source candidates only if they are highly specific and person-fit.
            if quality_score >= 3.0:
                processed.append(normalized)

        if len(processed) < 4:
            logger.warning("Research quality gate found fewer than 4 strong topics; relaxing threshold.")
            relaxed = []
            for topic in topics:
                if not isinstance(topic, dict) or not topic.get("title"):
                    continue
                source_info = self._classify_source(topic)
                normalized = dict(topic)
                normalized.update({k: v for k, v in source_info.items() if v})
                if not normalized.get("fact") and isinstance(normalized.get("key_facts"), list) and normalized["key_facts"]:
                    normalized["fact"] = str(normalized["key_facts"][0])
                normalized["research_quality_score"] = self._score_topic_quality(
                    normalized, persona_keywords, existing_keywords
                )
                normalized["research_provider"] = "perplexity"
                relaxed.append(normalized)
            processed = sorted(relaxed, key=lambda t: t.get("research_quality_score", 0), reverse=True)[:6]

        processed.sort(key=lambda t: t.get("research_quality_score", 0), reverse=True)
        logger.info(f"Research quality gate: {len(topics)} -> {len(processed)} topics")
        return processed[:8]

    def _get_strategy_section(self, company_strategy: Dict[str, Any] = None, strategy_weight: float = 0.5) -> str:
        """Build company strategy section for research prompt with weighted influence."""
        if not company_strategy:
            return ""

        # Extract strategy elements
        mission = company_strategy.get("mission", "")
        vision = company_strategy.get("vision", "")
        content_pillars = company_strategy.get("content_pillars", [])
        target_audience = company_strategy.get("target_audience", "")
        dos = company_strategy.get("dos", [])
        donts = company_strategy.get("donts", [])

        # Build section only if there's meaningful content
        if not any([mission, vision, content_pillars, dos, donts]):
            return ""

        # Determine importance level based on strategy_weight
        if strategy_weight >= 0.8:
            importance = "KRITISCH - STRIKT BEACHTEN"
            instruction = "Alle Themen MÜSSEN sich an der Unternehmensstrategie orientieren! Nur Topics vorschlagen, die perfekt zur Strategie passen."
        elif strategy_weight >= 0.6:
            importance = "WICHTIG - BERÜCKSICHTIGEN"
            instruction = "Priorisiere Topics die zur Unternehmensstrategie passen! Die Strategie soll klar erkennbar sein."
        elif strategy_weight >= 0.4:
            importance = "ORIENTIERUNG"
            instruction = "Berücksichtige die Unternehmensstrategie wo sinnvoll - persönliche Expertise hat Priorität."
        elif strategy_weight >= 0.2:
            importance = "OPTIONAL"
            instruction = "Die Strategie dient als Hintergrundinformation - freie Themenauswahl erlaubt."
        else:
            importance = "NUR REFERENZ"
            instruction = "Ignoriere die Strategie weitgehend - Fokus auf persönliche Themen und Expertise."

        section = f"""

=== UNTERNEHMENSSTRATEGIE ({importance}) ===
Strategy Weight: {strategy_weight:.1f} / 1.0
{instruction}
"""
        if mission:
            section += f"\nMISSION: {mission}"
        if vision:
            section += f"\nVISION: {vision}"
        if content_pillars:
            section += f"\nCONTENT PILLARS: {', '.join(content_pillars)}"
        if target_audience:
            section += f"\nZIELGRUPPE: {target_audience}"
        if dos:
            section += f"\n\nEMPFOHLENE THEMEN-RICHTUNGEN:\n" + "\n".join([f"  + {d}" for d in dos])
        if donts:
            section += f"\n\nZU VERMEIDENDE THEMEN:\n" + "\n".join([f"  - {d}" for d in donts])

        # Weight-specific closing instruction
        if strategy_weight >= 0.8:
            section += "\n\n**KRITISCH:** Alle Topics müssen zur Unternehmensstrategie passen - keine Ausnahmen!"
        elif strategy_weight >= 0.6:
            section += "\n\n**WICHTIG:** Stelle sicher, dass die Mehrheit der Topics die Unternehmenswerte widerspiegelt!"
        elif strategy_weight >= 0.4:
            section += "\n\n**BEACHTE:** Integriere die Strategie subtil - persönliche Expertise bleibt wichtig!"
        else:
            section += "\n\n**REFERENZ:** Die Strategie dient nur als Orientierung - persönliche Topics haben Vorrang!"

        return section + "\n"

    def _get_structure_prompt(
        self,
        raw_research: str,
        target_audience: str,
        persona: str = ""
    ) -> str:
        """Get prompt to structure Perplexity research into JSON (legacy)."""
        return f"""Strukturiere die folgenden Recherche-Ergebnisse in ein sauberes JSON-Format.

RECHERCHE-ERGEBNISSE:
{raw_research}

AUFGABE:
Extrahiere die Themen und formatiere sie als JSON. Behalte ALLE Fakten, Quellen und Details bei.

Gib das Ergebnis in diesem Format zurück:

{{
  "topics": [
    {{
      "title": "Prägnanter Titel des Themas",
      "category": "News-Flash / Schmerzpunkt-Löser / Konträrer Trend / Emerging Topic",
      "fact": "Die kompletten Fakten, Zahlen und Details aus der Recherche - NICHTS weglassen!",
      "relevance": "Warum ist das für {target_audience} wichtig?",
      "source": "Quellenangaben aus der Recherche"
    }}
  ]
}}

WICHTIG:
- Behalte ALLE Fakten und Quellen aus der Recherche
- Erfinde NICHTS dazu
- Wenn etwas unklar ist, lass es weg
- Mindestens 5 Themen wenn vorhanden"""

    def _ensure_diversity(self, topics: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        Ensure topic suggestions are diverse (different categories, angles).

        Args:
            topics: List of topic suggestions

        Returns:
            Filtered list with diverse topics
        """
        if len(topics) <= 3:
            return topics

        # Track categories used
        category_counts = {}
        diverse_topics = []

        for topic in topics:
            category = topic.get("category", "Unknown")

            # Allow max 2 topics per category
            if category_counts.get(category, 0) < 2:
                diverse_topics.append(topic)
                category_counts[category] = category_counts.get(category, 0) + 1

        # If we filtered too many, add back some
        if len(diverse_topics) < 5 and len(topics) >= 5:
            for topic in topics:
                if topic not in diverse_topics:
                    diverse_topics.append(topic)
                    if len(diverse_topics) >= 6:
                        break

        logger.info(f"Diversity check: {len(topics)} -> {len(diverse_topics)} topics, categories: {category_counts}")
        return diverse_topics

    def _extract_topics_from_response(self, response: str) -> List[Dict[str, Any]]:
        """
        Extract structured topics from Perplexity response.

        Args:
            response: Raw response from Perplexity

        Returns:
            List of structured topic dictionaries
        """
        topics = []

        # Simple parsing - split by topic markers
        sections = response.split("[TITEL]:")

        for section in sections[1:]:  # Skip first empty section
            try:
                # Extract title
                title_end = section.find("[KATEGORIE]:")
                if title_end == -1:
                    title_end = section.find("\n")
                title = section[:title_end].strip()

                # Extract category
                category = ""
                if "[KATEGORIE]:" in section:
                    cat_start = section.find("[KATEGORIE]:") + len("[KATEGORIE]:")
                    cat_end = section.find("[DER FAKT]:")
                    if cat_end == -1:
                        cat_end = section.find("\n", cat_start)
                    category = section[cat_start:cat_end].strip()

                # Extract fact
                fact = ""
                if "[DER FAKT]:" in section:
                    fact_start = section.find("[DER FAKT]:") + len("[DER FAKT]:")
                    fact_end = section.find("[WARUM RELEVANT]:")
                    if fact_end == -1:
                        fact_end = section.find("[QUELLE]:")
                    if fact_end == -1:
                        fact_end = len(section)
                    fact = section[fact_start:fact_end].strip()

                # Extract relevance
                relevance = ""
                if "[WARUM RELEVANT]:" in section:
                    rel_start = section.find("[WARUM RELEVANT]:") + len("[WARUM RELEVANT]:")
                    rel_end = section.find("[QUELLE]:")
                    if rel_end == -1:
                        rel_end = len(section)
                    relevance = section[rel_start:rel_end].strip()

                if title and fact:
                    topics.append({
                        "title": title,
                        "category": category or "Allgemein",
                        "fact": fact,
                        "relevance": relevance,
                        "source": "perplexity_research"
                    })
            except Exception as e:
                logger.warning(f"Failed to parse topic section: {e}")
                continue

        return topics
