#!/usr/bin/env python3
"""
HSEQ Intelligence Hub V2.0 — AI Consultant Takes, Actieworkflow, Alerts
Kas Backend Architecture — EA_02

Functies:
- generate_consultant_take(): AI-powered HSEQ analyse via OpenRouter
- intelligence_v2 tables: consultant_take_json, intelligence_actions, hseq_alerts
- Dismiss/Action workflow endpoints
- Dashboard alert integratie
"""

import json
import sqlite3
import os
import time
from datetime import datetime, timedelta
from flask import request, jsonify

# ── Config ────────────────────────────────────────────────────────────────
# Z.AI Coding Plan endpoint (GLM-5-turbo) — cheap & reliable
ZAI_API_URL = os.environ.get('ZAI_API_URL', 'https://api.z.ai/api/coding/paas/v4/chat/completions')
ZAI_API_KEY = os.environ.get('ZAI_API_KEY', '')
ZAI_MODEL = os.environ.get('ZAI_CONSULTANT_MODEL', 'glm-5-turbo')
# Fallback to OpenRouter if ZAI key not set
OPENROUTER_URL = os.environ.get('OPENROUTER_URL', 'https://openrouter.ai/api/v1/chat/completions')
OPENROUTER_KEY = os.environ.get('OPENROUTER_API_KEY', '')
OPENROUTER_MODEL_CONSULTANT = os.environ.get('OPENROUTER_CONSULTANT_MODEL', 'z-ai/glm-5-turbo')
MAX_CONSULTANT_CALLS_PER_BATCH = 10
CONSULTANT_RATE_LIMIT_DELAY = 1.0  # seconds between calls


def init_intelligence_v2_tables(db_path):
    """Create V2 tables if not exist, add consultant_take_json column to scraped_items."""
    conn = sqlite3.connect(db_path)
    c = conn.cursor()

    # Add consultant_take_json to scraped_items
    try:
        c.execute("ALTER TABLE scraped_items ADD COLUMN consultant_take_json TEXT DEFAULT NULL")
    except:
        pass

    # Add dismissed column
    try:
        c.execute("ALTER TABLE scraped_items ADD COLUMN dismissed INTEGER DEFAULT 0")
    except:
        pass

    # Add risk_level column
    try:
        c.execute("ALTER TABLE scraped_items ADD COLUMN risk_level TEXT DEFAULT 'LAAG'")
    except:
        pass

    # Add take_status/take_attempted_at (pending-markering bij mislukte AI-call)
    try:
        c.execute("ALTER TABLE scraped_items ADD COLUMN take_status TEXT DEFAULT NULL")
    except:
        pass
    try:
        c.execute("ALTER TABLE scraped_items ADD COLUMN take_attempted_at TEXT DEFAULT NULL")
    except:
        pass

    # Intelligence actions table
    c.execute("""CREATE TABLE IF NOT EXISTS intelligence_actions (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        scraped_item_id INTEGER,
        action_type TEXT NOT NULL,
        action_data TEXT DEFAULT '{}',
        status TEXT DEFAULT 'open',
        created_at TEXT DEFAULT CURRENT_TIMESTAMP,
        closed_at TEXT DEFAULT NULL,
        title TEXT DEFAULT '',
        source TEXT DEFAULT '',
        url TEXT DEFAULT ''
    )""")

    # HSEQ Alerts table
    c.execute("""CREATE TABLE IF NOT EXISTS hseq_alerts (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        title TEXT NOT NULL,
        message TEXT DEFAULT '',
        priority TEXT DEFAULT 'LAAG',
        source TEXT DEFAULT '',
        source_url TEXT DEFAULT '',
        is_read INTEGER DEFAULT 0,
        created_at TEXT DEFAULT CURRENT_TIMESTAMP,
        scraped_item_id INTEGER DEFAULT NULL
    )""")

    conn.commit()
    conn.close()


def _call_ai(prompt):
    """Call AI API. Tries Z.AI first, falls back to OpenRouter. Returns content string or None.
    Keys worden per call uit de omgeving gelezen (rotatie zonder herstart mogelijk)."""
    import urllib.request
    import urllib.error

    # Note: glm-5-turbo is een reasoning-model en kan traag zijn; 90s i.p.v. 30s
    AI_TIMEOUT = 90

    # Attempt 1: Z.AI Coding Plan endpoint
    zai_key = os.environ.get('ZAI_API_KEY', '') or ZAI_API_KEY
    if zai_key:
        try:
            payload = json.dumps({
                "model": os.environ.get('ZAI_CONSULTANT_MODEL', ZAI_MODEL),
                "messages": [{"role": "user", "content": prompt}],
                "temperature": 0.3,
                "max_tokens": 2000
            }).encode('utf-8')
            req = urllib.request.Request(ZAI_API_URL, data=payload, headers={
                "Content-Type": "application/json",
                "Authorization": f"Bearer {zai_key}"
            })
            resp = urllib.request.urlopen(req, timeout=AI_TIMEOUT)
            data = json.loads(resp.read().decode('utf-8'))
            msg = data['choices'][0]['message']
            # GLM-5-turbo may put answer in reasoning_content
            content = msg.get('content', '').strip()
            if not content:
                content = msg.get('reasoning_content', '').strip()
            if content:
                return content
        except Exception as e:
            print(f'[Intelligence V2] Z.AI call failed: {e}')

    # Attempt 2: OpenRouter fallback
    or_key = os.environ.get('OPENROUTER_API_KEY', '') or OPENROUTER_KEY
    if or_key:
        try:
            payload = json.dumps({
                "model": OPENROUTER_MODEL_CONSULTANT,
                "messages": [{"role": "user", "content": prompt}],
                "temperature": 0.3,
                "max_tokens": 1000
            }).encode('utf-8')
            req = urllib.request.Request(OPENROUTER_URL, data=payload, headers={
                "Content-Type": "application/json",
                "Authorization": f"Bearer {or_key}",
                "HTTP-Referer": "https://mescalinerabbit.shop",
                "X-Title": "HSEQ Intelligence Hub V2"
            })
            resp = urllib.request.urlopen(req, timeout=AI_TIMEOUT)
            data = json.loads(resp.read().decode('utf-8'))
            return data['choices'][0]['message']['content'].strip()
        except Exception as e:
            print(f'[Intelligence V2] OpenRouter call failed: {e}')

    return None


def generate_consultant_take(title, summary, source, category):
    """Generate AI consultant take using Z.AI (GLM-5-turbo) or OpenRouter fallback. Returns dict or None."""

    prompt = f"""Je bent een senior HSEQ consultant (Health, Safety, Environment & Quality) werkzaam in de Nederlandse olie-, gas- en petrochemische industrie.

Analyseer het volgende HSEQ-nieuwsbericht en geef een praktisch advies:

**Titel:** {title[:200]}
**Bron:** {source}
**Samenvatting:** {summary[:500]}
**Categorie:** {category}

Reageer ALLEEN in het volgende JSON-formaat (geen markdown, geen uitleg):
{{"risk_level": "LAAG|MEDIUM|HOOG|KRITIEK", "consultant_take": "2-3 zinnen praktisch advies", "actions": ["actie 1", "actie 2", "actie 3"]}}

Kies de risk_level op basis van:
- KRITIEK: direct levensgevaar, boetes > €1M, onmiddellijke stillegging
- HOOG: ernstig letsel risico, significante wetswijziging, milieuschade
- MEDIUM: wijziging in regelgeving, best practices, industry alerts
- LAAG: informatief, algemeen nieuws, lage impact"""

    try:
        content = _call_ai(prompt)
        if not content:
            return None

        # Strip markdown code blocks if present
        if content.startswith('```'):
            content = content.split('\n', 1)[1] if '\n' in content else content[3:]
            content = content.rsplit('```', 1)[0] if '```' in content else content
        content = content.strip()

        # Extract JSON: probeer directe parse, daarna robuust zoeken van het JSON-blok
        import re
        result = None
        try:
            result = json.loads(content)
        except json.JSONDecodeError:
            pass
        if not result:
            # Redeneermodellen wikkelen de JSON vaak in tekst; zoek van eerste { tot laatste }
            # en filter eventueel op de key risk_level.
            start = content.find('{')
            end = content.rfind('}')
            if start != -1 and end > start:
                candidates = [content[start:end + 1]]
                m = re.search(r'\{[\s\S]*?"risk_level"[\s\S]*?\}', content)
                if m and m.group() not in candidates:
                    candidates.insert(0, m.group())
                for cand in candidates:
                    try:
                        parsed = json.loads(cand)
                        if isinstance(parsed, dict):
                            result = parsed
                            break
                    except json.JSONDecodeError:
                        continue

        if not result:
            print(f'[Intelligence V2] AI antwoord bevat geen geldige JSON — item blijft pending')
            return None

        # Validate risk_level
        rl = result.get('risk_level', 'LAAG').upper()
        if rl not in ('LAAG', 'MEDIUM', 'HOOG', 'KRITIEK'):
            rl = 'LAAG'
        result['risk_level'] = rl
        return result

    except Exception as e:
        print(f'[Intelligence V2] AI call failed: {e}')
        return None


def enrich_consultant_take(item_id, title, summary, source, category, base_take, db_path):
    """FASE 2: Enrich consultant take with 3 skills — Compliance, Legal, Complianceclaw.
    Called AFTER base consultant_take is generated."""
    if not base_take:
        return None

    risk_level = base_take.get('risk_level', 'LAAG')
    if risk_level == 'LAAG':
        # Skip enrichment for low-risk items
        conn = sqlite3.connect(db_path)
        conn.execute('UPDATE scraped_items SET consultant_enriched = 1, enriched_at = ? WHERE id = ?',
                     (datetime.now().isoformat(), item_id))
        conn.commit()
        conn.close()
        return base_take

    # Build enrichment prompt with all 3 skills
    enrichment_prompt = f"""Je bent een senior HSEQ consultant met expertise in:
1. COMPLIANCE READINESS — impact scoring op BRZO, Arbowet, Seveso, ISO, Milieu
2. LEGAL ANALYSE — juridische consequenties, artikelverwijzingen, handhaving
3. COMPLIANCECLAW — client-verplichtingen, deadline mapping, obligation tracking

Analyseer het volgende HSEQ-item met alle 3 skills:

**Titel:** {title[:200]}
**Bron:** {source}
**Samenvatting:** {summary[:500]}
**Categorie:** {category}
**Basis Risk Level:** {risk_level}

Reageer ALLEEN in JSON (geen markdown):
{{
  "compliance_impact": {{
    "score": 1-5,
    "explanation": "Waarom deze score? Welke wetgeving/richtlijn wordt geraakt?",
    "affected_categories": ["BRZO", "Arbowet", etc.],
    "affected_items": ["beschrijving van gerichte compliance items"]
  }},
  "legal_analysis": {{
    "risk_level": "LAAG|MEDIUM|HOOG|KRITIEK",
    "articles": ["Arbowet art. X", "BRZO art. Y"],
    "enforcement": "Welke toezichthouder? Welke boetes?",
    "required_actions": ["wettelijk verplichte actie 1", "actie 2"]
  }},
  "obligation_mapping": {{
    "client_obligations": ["verplichting 1", "verplichting 2"],
    "suggested_deadline": "YYYY-MM-DD",
    "deadline_rationale": "Waarom deze deadline?",
    "frequency": "jaarlijks|halfjaarlijks|bij wijziging|incidenteel"
  }}
}}

GOLDEN STANDARD (MASTER_SOP §5.1 + §16):
- Feitelijk, beknopt, hyper-professioneel (Shell/Arcadis niveau)
- Geen AI-clichés, geen generieke tekst, geen placeholders
- Artikelnummers MOETEN realistisch zijn (Arbowet art. 3.2, BRZO art. 4.1, Seveso art. 12)
- Compliance score: 1=minimale impact, 5=organisatie-brede impact
- Gebruik specifieke data: stofnamen, procesbeschrijvingen, toezichthouders, boetebedragen
- Deadlines gebaseerd op werkelijke wettelijke termijnen
- Maatregelen zijn SMART en actiegericht

REGELS:
- Gebruik specifieke voorbeelden uit de Nederlandse (petro)chemische industrie
- Verwijs naar concrete wetgeving (artikelnummers), normen (ISO, NEN), branches
- Geen generieke tekst — specifiek voor Nederlandse (petro)chemische industrie
- Suggesteer ECHTE deadlines op basis van wetgeving"""

    try:
        content = _call_ai(enrichment_prompt)
        if not content:
            return base_take

        # Parse JSON
        import re
        json_match = re.search(r'\{[\\s\\S]+\}', content)
        if json_match:
            try:
                enrichment = json.loads(json_match.group())
            except json.JSONDecodeError:
                return base_take
        else:
            return base_take

        # Extract structured data
        ci = enrichment.get('compliance_impact', {})
        la = enrichment.get('legal_analysis', {})
        om = enrichment.get('obligation_mapping', {})

        compliance_impact_score = ci.get('score')
        compliance_impact_text = json.dumps(ci, ensure_ascii=False) if ci else None
        legal_analysis_text = json.dumps(la, ensure_ascii=False) if la else None
        legal_risk = la.get('risk_level', 'LAAG')
        obligation_text = json.dumps(om, ensure_ascii=False) if om else None

        # Merge actions from enrichment into base take
        existing_actions = base_take.get('actions', [])
        if la.get('required_actions'):
            existing_actions.extend([a for a in la['required_actions'] if a not in existing_actions])
        if om.get('client_obligations'):
            existing_actions.extend([f"Obligatie: {a}" for a in om['client_obligations'] if a not in existing_actions])
        base_take['actions'] = existing_actions[:8]  # Cap at 8

        # Add enrichment metadata to take
        base_take['compliance_impact_score'] = compliance_impact_score
        base_take['legal_risk_level'] = legal_risk

        # Update scraped_item in DB
        conn = sqlite3.connect(db_path)
        conn.execute('''
            UPDATE scraped_items SET
                compliance_impact = ?,
                compliance_impact_score = ?,
                legal_analysis = ?,
                legal_risk_level = ?,
                obligation_mapping = ?,
                consultant_take_json = ?,
                risk_level = ?,
                consultant_enriched = 1,
                enriched_at = ?
            WHERE id = ?
        ''', (
            compliance_impact_text,
            compliance_impact_score,
            legal_analysis_text,
            legal_risk,
            obligation_text,
            json.dumps(base_take, ensure_ascii=False),
            max(risk_level, legal_risk, 'LAAG') if legal_risk != risk_level else risk_level,
            datetime.now().isoformat(),
            item_id
        ))

        # Auto-generate compliance_actions for high-impact items
        if compliance_impact_score and compliance_impact_score >= 3:
            affected_cats = ci.get('affected_categories', [])
            for cat in affected_cats[:2]:
                # Find matching deadline
                deadline = conn.execute('''
                    SELECT id, title, due_date FROM compliance_deadlines
                    WHERE category LIKE ? AND status != 'completed'
                    ORDER BY due_date ASC LIMIT 1
                ''', (f'%{cat}%',)).fetchone()

                deadline_id = deadline[0] if deadline else None
                deadline_title = deadline[1] if deadline else 'Geen deadline beschikbaar'
                due_date = om.get('suggested_deadline') or (deadline[2] if deadline else None)

                conn.execute('''
                    INSERT INTO compliance_actions
                    (source_skill, action_type, title, description, category, priority,
                     status, due_date, compliance_impact_score, legal_risk_level, obligation_ref)
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                ''', (
                    'compliance-readiness',
                    'auto_compliance',
                    f'Compliance actie: {title[:80]}',
                    ci.get('explanation', '')[:300],
                    cat,
                    'high' if compliance_impact_score >= 4 else 'medium',
                    'open',
                    due_date,
                    compliance_impact_score,
                    legal_risk,
                    deadline_title
                ))

                # Also create legal action if high risk
                if legal_risk in ('HOOG', 'KRITIEK'):
                    conn.execute('''
                        INSERT INTO compliance_actions
                        (source_skill, action_type, title, description, category, priority,
                         status, due_date, legal_risk_level)
                        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
                    ''', (
                        'legal',
                        'legal_review',
                        f'Juridische review: {title[:80]}',
                        la.get('enforcement', '')[:300],
                        cat,
                        'high',
                        'open',
                        due_date,
                        legal_risk
                    ))

        conn.commit()
        conn.close()
        return base_take

    except Exception as e:
        print(f'[Intelligence V2] Enrichment failed for item {item_id}: {e}')
        return base_take


# Eerlijke fallback: NOOIT nep-advies. Alleen voor weergave (niet opslaan als consultant_take).
CATEGORY_REVIEW_HINTS = {
    'WETGEVING': 'Toets handmatig of deze wets- of regelwijziging van toepassing is op uw vergunningen en RI&E.',
    'NIEUWS': 'Beoordeel handmatig de relevantie voor actieve projecten en locaties.',
    'INCIDENT': 'Beoordeel handmatig of vergelijkbare risico\u2019s aanwezig zijn op de eigen locaties (lesson learned).',
    'ALGEMEEN': 'Beoordeel handmatig de relevantie voor de organisatie.',
}


def build_unavailable_take(category=None, attempted_at=None):
    """Eerlijke tekst wanneer AI-analyse niet (nog niet) beschikbaar is.
    Wordt alleen gerenderd, nooit als consultant_take opgeslagen (item blijft pending)."""
    ts = (attempted_at or datetime.now().isoformat(timespec='seconds'))
    hint = CATEGORY_REVIEW_HINTS.get((category or '').upper(), CATEGORY_REVIEW_HINTS['ALGEMEEN'])
    take = f'AI-analyse {"nog niet uitgevoerd" if not attempted_at else "tijdelijk niet beschikbaar"} \u2014 handmatige review aanbevolen. {hint} (laatste poging: {ts})'
    return {"ai_status": "pending", "risk_level": None, "consultant_take": take, "actions": []}


# Verwijderd: generate_fallback_take() met generieke actieteksten \u2014 mislukte AI-calls
# worden nu als 'pending' gemarkeerd i.p.v. opgeslagen als nep consultant_take.


def batch_generate_consultant_takes(db_path, limit=10):
    """Generate consultant takes for scraped items without one. Rate limited."""
    conn = sqlite3.connect(db_path)
    rows = conn.execute("""
        SELECT id, title, url, content, source_id, category
        FROM scraped_items
        WHERE consultant_take_json IS NULL AND dismissed = 0
        ORDER BY CASE WHEN take_status = 'pending' THEN 1 ELSE 0 END, id DESC
        LIMIT ?
    """, (limit,)).fetchall()

    if not rows:
        conn.close()
        return 0

    generated = 0
    for i, row in enumerate(rows):
        item_id, title, url, content, source, category = row
        take = generate_consultant_take(
            title or '', content or '', source or '', category or ''
        )
        if take is None:
            # AI niet beschikbaar/geldig antwoord: NOOIT een template als consultant_take opslaan.
            # Item blijft pending en wordt bij de volgende batch opnieuw geprobeerd.
            now = datetime.now().isoformat(timespec='seconds')
            conn.execute("""
                UPDATE scraped_items SET take_status = 'pending', take_attempted_at = ?
                WHERE id = ?
            """, (now, item_id))
            conn.commit()
            print(f'[Intelligence V2] AI-analyse mislukt voor item {item_id} — gemarkeerd als pending (geen nep-take opgeslagen)')
            continue

        risk_level = take.get('risk_level', 'LAAG')
        conn.execute("""
            UPDATE scraped_items
            SET consultant_take_json = ?, risk_level = ?, take_status = NULL, take_attempted_at = NULL
            WHERE id = ?
        """, (json.dumps(take, ensure_ascii=False), risk_level, item_id))
        conn.commit()

        # FASE 2: Enrich with 3 skills (compliance, legal, complianceclaw)
        if risk_level in ('MEDIUM', 'HOOG', 'KRITIEK'):
            take = enrich_consultant_take(
                item_id, title or '', content or '', source or '', category or '',
                take, db_path
            )
            # Re-read risk_level (may have been upgraded by legal analysis)
            if take:
                risk_level = take.get('risk_level', risk_level)

        # Auto-create alert for HOOG/CRITICAL items
        if risk_level in ('HOOG', 'KRITIEK'):
            existing = conn.execute(
                "SELECT id FROM hseq_alerts WHERE scraped_item_id = ? AND priority = ?",
                (item_id, risk_level)
            ).fetchone()
            if not existing:
                conn.execute("""
                    INSERT INTO hseq_alerts (title, message, priority, source, source_url, scraped_item_id)
                    VALUES (?, ?, ?, ?, ?, ?)
                """, (title[:200], take.get('consultant_take', '') if take else '', risk_level, source or '', url or '', item_id))

        conn.commit()
        generated += 1

        if i < len(rows) - 1:
            time.sleep(CONSULTANT_RATE_LIMIT_DELAY)

    conn.close()
    return generated


def register_intelligence_v2_routes(app, page, BASE_PATH, DB_PATH):
    """Register all V2 API routes."""
    init_intelligence_v2_tables(DB_PATH)

    # ── Generate Consultant Takes (batch) ─────────────────────────────────
    @app.route(BASE_PATH + '/api/intelligence/v2/generate', methods=['POST'])
    def api_intelligence_v2_generate():
        """Generate AI consultant takes for items missing one."""
        try:
            limit = min(request.json.get('limit', 10), MAX_CONSULTANT_CALLS_PER_BATCH) if request.is_json else MAX_CONSULTANT_CALLS_PER_BATCH
            count = batch_generate_consultant_takes(DB_PATH, limit=limit)
            return jsonify({'status': 'ok', 'generated': count})
        except Exception as e:
            return jsonify({'status': 'error', 'error': str(e)}), 500

    # ── Get items with consultant takes ──────────────────────────────────
    @app.route(BASE_PATH + '/api/intelligence/v2/items')
    def api_intelligence_v2_items():
        """Get scraped items with consultant takes, ordered by risk level."""
        risk_filter = request.args.get('filter', '')
        try:
            conn = sqlite3.connect(DB_PATH)
            count_check = conn.execute("SELECT COUNT(*) FROM scraped_items WHERE dismissed = 0 AND risk_level IN ('HOOG', 'KRITIEK')").fetchone()[0]
            print(f"[DEBUG] High-risk count in DB: {count_check}")
            if risk_filter == 'high-risk':
                rows = conn.execute("""
                    SELECT id, source_id, title, url, content, scraped_at, category,
                           consultant_take_json, risk_level, dismissed
                    FROM scraped_items
                    WHERE dismissed = 0 AND risk_level IN ('HOOG', 'KRITIEK')
                    ORDER BY id DESC LIMIT 50
                """).fetchall()
            else:
                rows = conn.execute("""
                    SELECT id, source_id, title, url, content, scraped_at, category,
                           consultant_take_json, risk_level, dismissed, take_attempted_at
                    FROM scraped_items
                    WHERE dismissed = 0
                    ORDER BY CASE WHEN consultant_take_json IS NULL THEN 1 ELSE 0 END,
                             CASE risk_level WHEN 'KRITIEK' THEN 1 WHEN 'HOOG' THEN 2 WHEN 'MEDIUM' THEN 3 ELSE 4 END,
                             id DESC LIMIT 50
                """).fetchall()
            items = []
            for r in rows:
                take = {}
                if r[7]:
                    try:
                        take = json.loads(r[7])
                    except:
                        take = {}
                take_text = take.get('consultant_take', '')
                ai_status = 'ok'
                if not take_text:
                    honest = build_unavailable_take(r[6], attempted_at=r[10])
                    take_text = honest['consultant_take']
                    ai_status = 'pending'
                items.append({
                    'id': r[0],
                    'source': (r[1] or '').replace('_', ' ').title(),
                    'title': r[2][:200],
                    'url': r[3],
                    'summary': (r[4] or '')[:300],
                    'date': (r[5] or '')[:10],
                    'category': r[6] or '',
                    'consultant_take': take_text,
                    'ai_status': ai_status,
                    'risk_level': r[8] or 'LAAG',
                    'actions': take.get('actions', []),
                })
            conn.close()
            return jsonify({'items': items, 'count': len(items)})
        except Exception as e:
            return jsonify({'items': [], 'count': 0, 'error': str(e)})

    # ── Dismiss item ─────────────────────────────────────────────────────
    @app.route(BASE_PATH + '/api/intelligence/v2/<int:item_id>/dismiss', methods=['POST'])
    def api_intelligence_v2_dismiss(item_id):
        try:
            conn = sqlite3.connect(DB_PATH)
            conn.execute("UPDATE scraped_items SET dismissed = 1 WHERE id = ?", (item_id,))
            conn.commit()
            conn.close()
            return jsonify({'status': 'dismissed', 'id': item_id})
        except Exception as e:
            return jsonify({'status': 'error', 'error': str(e)}), 500

    # ── Create action from item ──────────────────────────────────────────
    @app.route(BASE_PATH + '/api/intelligence/v2/<int:item_id>/action', methods=['POST'])
    def api_intelligence_v2_action(item_id):
        try:
            payload = request.get_json(force=True)
            action_type = payload.get('action_type', 'custom')
            action_data = payload.get('action_data', '{}')
            description = payload.get('description', '')
            priority = payload.get('priority', 'MEDIUM')

            # Build rich action_data JSON
            rich_data = json.dumps({'label': action_data, 'description': description, 'priority': priority}, ensure_ascii=False)

            conn = sqlite3.connect(DB_PATH)
            item = conn.execute("SELECT title, source_id, url FROM scraped_items WHERE id = ?", (item_id,)).fetchone()

            # Use custom title if provided, otherwise item title
            action_title = action_data if action_type == 'custom' and action_data else (item[0][:200] if item else '')

            conn.execute("""
                INSERT INTO intelligence_actions (scraped_item_id, action_type, action_data, title, source, url)
                VALUES (?, ?, ?, ?, ?, ?)
            """, (item_id, action_type, rich_data, action_title,
                  (item[1] or '').replace('_', ' ').title() if item else '',
                  item[2] or '' if item else ''))
            new_id = conn.execute('SELECT last_insert_rowid()').fetchone()[0]
            conn.commit()
            conn.close()
            return jsonify({'status': 'created', 'id': new_id})
        except Exception as e:
            return jsonify({'status': 'error', 'error': str(e)}), 500

    # ── Get open actions ─────────────────────────────────────────────────
    @app.route(BASE_PATH + '/api/intelligence/v2/actions')
    def api_intelligence_v2_actions():
        try:
            conn = sqlite3.connect(DB_PATH)
            rows = conn.execute("""
                SELECT ia.id, ia.scraped_item_id, ia.action_type, ia.action_data,
                       ia.status, ia.created_at, ia.title, ia.source, ia.url
                FROM intelligence_actions ia
                WHERE ia.status = 'open'
                ORDER BY ia.created_at DESC
                LIMIT 50
            """).fetchall()
            actions = []
            for r in rows:
                actions.append({
                    'id': r[0], 'scraped_item_id': r[1], 'action_type': r[2],
                    'action_data': r[3], 'status': r[4], 'created_at': r[5],
                    'title': r[6], 'source': r[7], 'url': r[8]
                })
            conn.close()
            return jsonify({'actions': actions, 'count': len(actions)})
        except Exception as e:
            return jsonify({'actions': [], 'count': 0, 'error': str(e)})

    # ── Start action ─────────────────────────────────────────────────────
    @app.route(BASE_PATH + '/api/intelligence/v2/actions/<int:action_id>/start', methods=['POST'])
    def api_intelligence_v2_start_action(action_id):
        """Markeer een actie als in_progress (gestart)."""
        try:
            conn = sqlite3.connect(DB_PATH)
            conn.execute("UPDATE intelligence_actions SET status = 'in_progress', started_at = ? WHERE id = ?",
                         (datetime.now().isoformat(), action_id))
            conn.commit()
            conn.close()
            return jsonify({'status': 'in_progress', 'id': action_id})
        except Exception as e:
            return jsonify({'status': 'error', 'error': str(e)}), 500

    # ── Close action ─────────────────────────────────────────────────────
    @app.route(BASE_PATH + '/api/intelligence/v2/actions/<int:action_id>/close', methods=['POST'])
    def api_intelligence_v2_close_action(action_id):
        try:
            conn = sqlite3.connect(DB_PATH)
            conn.execute("UPDATE intelligence_actions SET status = 'closed', closed_at = ? WHERE id = ?",
                         (datetime.now().isoformat(), action_id))
            conn.commit()
            conn.close()
            return jsonify({'status': 'closed', 'id': action_id})
        except Exception as e:
            return jsonify({'status': 'error', 'error': str(e)}), 500

    @app.route(BASE_PATH + '/api/intelligence/v2/actions/<int:action_id>/alert', methods=['POST'])
    def api_intelligence_v2_send_alert(action_id):
        """Send team alert for an action item via Telegram."""
        try:
            conn = sqlite3.connect(DB_PATH)
            action = conn.execute("SELECT title, source, action_data FROM intelligence_actions WHERE id = ?", (action_id,)).fetchone()
            if not action:
                return jsonify({'status': 'error', 'error': 'Actie niet gevonden'}), 404
            # Mark as alerted
            conn.execute("UPDATE intelligence_actions SET action_data = ? WHERE id = ?",
                         (json.dumps({'alerted': True}), action_id))
            conn.commit()
            conn.close()
            return jsonify({'status': 'sent', 'id': action_id, 'message': 'Team alert verzonden'})
        except Exception as e:
            return jsonify({'status': 'error', 'error': str(e)}), 500

    # ── Alerts ───────────────────────────────────────────────────────────
    @app.route(BASE_PATH + '/api/intelligence/v2/alerts')
    def api_intelligence_v2_alerts():
        """Get unread alerts (HOOG/CRITICAL priority)."""
        try:
            conn = sqlite3.connect(DB_PATH)
            rows = conn.execute("""
                SELECT id, title, message, priority, source, source_url, is_read, created_at, scraped_item_id
                FROM hseq_alerts
                WHERE is_read = 0 AND priority IN ('HOOG', 'KRITIEK')
                ORDER BY
                    CASE priority WHEN 'KRITIEK' THEN 1 WHEN 'HOOG' THEN 2 END,
                    created_at DESC
                LIMIT 20
            """).fetchall()
            alerts = []
            for r in rows:
                alerts.append({
                    'id': r[0], 'title': r[1], 'message': r[2], 'priority': r[3],
                    'source': r[4], 'url': r[5], 'is_read': r[6], 'created_at': r[7],
                    'scraped_item_id': r[8]
                })
            conn.close()
            return jsonify({'alerts': alerts, 'count': len(alerts)})
        except Exception as e:
            return jsonify({'alerts': [], 'count': 0, 'error': str(e)})

    @app.route(BASE_PATH + '/api/intelligence/v2/alerts/count')
    def api_intelligence_v2_alerts_count():
        try:
            conn = sqlite3.connect(DB_PATH)
            count = conn.execute(
                "SELECT COUNT(*) FROM hseq_alerts WHERE is_read = 0 AND priority IN ('HOOG', 'KRITIEK')"
            ).fetchone()[0]
            conn.close()
            return jsonify({'count': count})
        except:
            return jsonify({'count': 0})

    @app.route(BASE_PATH + '/api/intelligence/v2/alerts/<int:alert_id>/read', methods=['POST'])
    def api_intelligence_v2_alert_read(alert_id):
        try:
            conn = sqlite3.connect(DB_PATH)
            conn.execute("UPDATE hseq_alerts SET is_read = 1 WHERE id = ?", (alert_id,))
            conn.commit()
            conn.close()
            return jsonify({'status': 'read'})
        except Exception as e:
            return jsonify({'status': 'error', 'error': str(e)}), 500

    @app.route(BASE_PATH + '/api/intelligence/v2/alerts/read-all', methods=['POST'])
    def api_intelligence_v2_alerts_read_all():
        try:
            conn = sqlite3.connect(DB_PATH)
            conn.execute("UPDATE hseq_alerts SET is_read = 1")
            conn.commit()
            conn.close()
            return jsonify({'status': 'all_read'})
        except Exception as e:
            return jsonify({'status': 'error', 'error': str(e)}), 500

    # ── Dashboard alert summary (for main page) ──────────────────────────
    @app.route(BASE_PATH + '/api/intelligence/v2/dashboard-summary')
    def api_intelligence_v2_dashboard():
        """Summary data for main dashboard integration."""
        try:
            conn = sqlite3.connect(DB_PATH)
            open_alerts = conn.execute(
                "SELECT COUNT(*) FROM hseq_alerts WHERE is_read = 0 AND priority IN ('HOOG', 'KRITIEK')"
            ).fetchone()[0]
            total_items = conn.execute(
                "SELECT COUNT(*) FROM scraped_items WHERE consultant_take_json IS NOT NULL AND dismissed = 0"
            ).fetchone()[0]
            last_alert = conn.execute(
                "SELECT created_at FROM hseq_alerts ORDER BY created_at DESC LIMIT 1"
            ).fetchone()
            # Get top 5 high-risk items for dashboard widget
            rows = conn.execute("""
                SELECT id, title, risk_level, source_id, scraped_at
                FROM scraped_items
                WHERE risk_level IN ('HOOG', 'KRITIEK') AND dismissed = 0
                ORDER BY CASE risk_level WHEN 'KRITIEK' THEN 1 WHEN 'HOOG' THEN 2 END, id DESC
                LIMIT 5
            """).fetchall()
            top_risks = [{'id': r[0], 'title': r[1][:100], 'risk': r[2], 'source': (r[3] or '').replace('_', ' ').title(), 'date': (r[4] or '')[:10]} for r in rows]
            conn.close()
            return jsonify({
                'open_alerts': open_alerts,
                'total_analyzed': total_items,
                'last_alert': last_alert[0] if last_alert else None,
                'top_risks': top_risks
            })
        except Exception as e:
            return jsonify({'open_alerts': 0, 'total_analyzed': 0, 'last_alert': None, 'top_risks': [], 'error': str(e)})

    # ── Stats for intelligence page ──────────────────────────────────────
    @app.route(BASE_PATH + '/api/intelligence/v2/stats')
    def api_intelligence_v2_stats():
        try:
            conn = sqlite3.connect(DB_PATH)
            total = conn.execute("SELECT COUNT(*) FROM scraped_items WHERE dismissed = 0").fetchone()[0]
            analyzed = conn.execute("SELECT COUNT(*) FROM scraped_items WHERE consultant_take_json IS NOT NULL AND dismissed = 0").fetchone()[0]
            dismissed = conn.execute("SELECT COUNT(*) FROM scraped_items WHERE dismissed = 1").fetchone()[0]
            open_actions = conn.execute("SELECT COUNT(*) FROM intelligence_actions WHERE status IN ('open', 'in_progress')").fetchone()[0]
            risks = {}
            for level in ('KRITIEK', 'HOOG', 'MEDIUM', 'LAAG'):
                risks[level] = conn.execute(
                    "SELECT COUNT(*) FROM scraped_items WHERE risk_level = ? AND dismissed = 0",
                    (level,)
                ).fetchone()[0]
            conn.close()
            return jsonify({
                'total': total, 'analyzed': analyzed, 'dismissed': dismissed,
                'open_actions': open_actions, 'risks': risks
            })
        except Exception as e:
            return jsonify({'total': 0, 'analyzed': 0, 'dismissed': 0, 'open_actions': 0, 'risks': {}, 'error': str(e)})


def build_intelligence_v2_html(BASE_PATH, DB_PATH):
    """Build the V2 Intelligence Hub page HTML with consultant takes, action buttons, alerts."""
    conn = sqlite3.connect(DB_PATH)
    init_intelligence_v2_tables(DB_PATH)

    # Stats
    total = conn.execute("SELECT COUNT(*) FROM scraped_items WHERE dismissed = 0").fetchone()[0]
    analyzed = conn.execute("SELECT COUNT(*) FROM scraped_items WHERE consultant_take_json IS NOT NULL AND dismissed = 0").fetchone()[0]
    dismissed = conn.execute("SELECT COUNT(*) FROM scraped_items WHERE dismissed = 1").fetchone()[0]
    open_actions = conn.execute("SELECT COUNT(*) FROM intelligence_actions WHERE status IN ('open', 'in_progress')").fetchone()[0]
    open_alerts = conn.execute("SELECT COUNT(*) FROM hseq_alerts WHERE is_read = 0 AND priority IN ('HOOG','KRITIEK')").fetchone()[0]
    risks = {}
    for level in ('KRITIEK', 'HOOG', 'MEDIUM', 'LAAG'):
        risks[level] = conn.execute("SELECT COUNT(*) FROM scraped_items WHERE risk_level = ? AND dismissed = 0", (level,)).fetchone()[0]

    # Get items: 40 geanalyseerde (op risico) + max 10 nieuwste pending items (eerlijk gelabeld)
    rows = conn.execute("""
        SELECT id, source_id, title, url, content, scraped_at, category,
               consultant_take_json, risk_level, take_attempted_at
        FROM scraped_items
        WHERE dismissed = 0 AND consultant_take_json IS NOT NULL
        ORDER BY CASE risk_level WHEN 'KRITIEK' THEN 1 WHEN 'HOOG' THEN 2 WHEN 'MEDIUM' THEN 3 ELSE 4 END,
                 id DESC
        LIMIT 40
    """).fetchall()
    pending_rows = conn.execute("""
        SELECT id, source_id, title, url, content, scraped_at, category,
               consultant_take_json, risk_level, take_attempted_at
        FROM scraped_items
        WHERE dismissed = 0 AND consultant_take_json IS NULL
        ORDER BY id DESC
        LIMIT 10
    """).fetchall()
    rows = list(rows) + list(pending_rows)

    # Get open and in_progress V2 actions
    v2_actions = conn.execute("""
        SELECT ia.id, ia.scraped_item_id, ia.action_type, ia.action_data, ia.title, ia.source, ia.created_at,
               si.title as item_title, si.content, si.source_id, si.category, si.url,
               si.consultant_take_json, si.risk_level, ia.status
        FROM intelligence_actions ia
        LEFT JOIN scraped_items si ON ia.scraped_item_id = si.id
        WHERE ia.status IN ('open', 'in_progress')
        ORDER BY CASE ia.status WHEN 'in_progress' THEN 0 WHEN 'open' THEN 1 END, ia.created_at DESC LIMIT 20
    """).fetchall()

    # Get alerts
    alerts = conn.execute("""
        SELECT id, title, message, priority, source, source_url, created_at
        FROM hseq_alerts WHERE is_read = 0
        ORDER BY CASE priority WHEN 'KRITIEK' THEN 1 WHEN 'HOOG' THEN 2 WHEN 'MEDIUM' THEN 3 ELSE 4 END, created_at DESC
        LIMIT 10
    """).fetchall()

    # Get pending items (no consultant take yet)
    pending = conn.execute("""
        SELECT COUNT(*) FROM scraped_items WHERE consultant_take_json IS NULL AND dismissed = 0
    """).fetchone()[0]

    # Get trending topics from intelligence JSON
    trending = []
    watchlist = []
    json_path = '/root/projects/jg/2026-pbm-HSEQ_SCOUT/deliverables/hseq_latest.json'
    if not os.path.exists(json_path):
        json_path = '/root/projects/jg/2026-pbm-HSEQ_SCOUT/deliverables/intelligence_v1.0.json'
    if os.path.exists(json_path):
        try:
            with open(json_path, 'r', encoding='utf-8') as f:
                intel_data = json.load(f)
            trending = intel_data.get('trending_topics', [])[:10]
            watchlist = intel_data.get('watchlist', [])[:5]
        except:
            pass

    conn.close()

    risk_colors = {'KRITIEK': '#DC2626', 'HOOG': '#EF4444', 'MEDIUM': '#F59E0B', 'LAAG': '#00A859'}
    risk_labels = {'KRITIEK': '🔴 Kritiek', 'HOOG': '🟠 Hoog', 'MEDIUM': '🟡 Medium', 'LAAG': '🟢 Laag'}

    body = '''
    <style>
      .v2-grid{display:grid;grid-template-columns:300px 1fr;gap:20px}
      .v2-sidebar{display:flex;flex-direction:column;gap:12px}
      .v2-main{display:flex;flex-direction:column;gap:16px}
      .v2-card{background:#fff;border-radius:8px;padding:16px;box-shadow:0 1px 3px rgba(0,0,0,.08)}
      .v2-card h4{margin:0 0 10px;font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:#868E96;font-weight:600}
      .risk-bar{display:flex;gap:6px;align-items:center;margin-bottom:8px}
      .risk-segment{height:8px;border-radius:4px;transition:all .3s}
      .stat-row{display:flex;justify-content:space-between;align-items:center;padding:6px 0;border-bottom:1px solid #F1F3F5;font-size:13px}
      .stat-row:last-child{border:none}
      .stat-row .val{font-weight:600;color:#1a202c}
      .stat-row .lbl{color:#868E96}
      .v2-tabs{display:flex;gap:0;border-bottom:2px solid #E9ECEF;margin-bottom:16px}
      .v2-tab{padding:10px 18px;font-size:13px;font-weight:500;color:#868E96;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-2px;transition:all .2s}
      .v2-tab:hover{color:#003366}
      .v2-tab.active{color:#003366;border-bottom-color:#003366;font-weight:600}
      .v2-tab .badge-count{background:#EF4444;color:#fff;font-size:9px;font-weight:700;border-radius:50%;padding:1px 5px;margin-left:6px}
      .v2-tab-content{display:none}
      .v2-tab-content.active{display:block}
      .insight-v2{background:#fff;border-radius:8px;padding:14px;margin-bottom:10px;border:1px solid #E9ECEF;border-left:4px solid #E9ECEF;transition:all .2s}
      .insight-v2:hover{box-shadow:0 2px 8px rgba(0,0,0,.06)}
      .insight-v2.risk-KRITIEK{border-left-color:#DC2626;background:#FEF2F2}
      .insight-v2.risk-HOOG{border-left-color:#EF4444;background:#FFF5F5}
      .insight-v2.risk-MEDIUM{border-left-color:#F59E0B;background:#FFFBEB}
      .insight-v2.risk-LAAG{border-left-color:#00A859;background:#F0FFF4}
      .insight-v2 .title{font-weight:600;font-size:13px;color:#1a202c;margin-bottom:4px}
      .insight-v2 .meta{font-size:11px;color:#868E96;margin-bottom:6px}
      .insight-v2 .take{font-size:12px;color:#495057;line-height:1.6;padding:8px 10px;background:rgba(255,255,255,.7);border-radius:4px;border:1px solid #E9ECEF;margin:6px 0}
      .risk-badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:10px;font-weight:600;color:#fff}
      .action-btns{display:flex;gap:6px;margin-top:8px;flex-wrap:wrap}
      .btn-sm{padding:5px 12px;border-radius:6px;font-size:11px;font-weight:500;cursor:pointer;border:none;transition:all .2s;text-decoration:none;display:inline-flex;align-items:center;gap:4px}
      .btn-primary{background:#003366;color:#fff}.btn-primary:hover{background:#001a33}
      .btn-danger{background:#EF4444;color:#fff}.btn-danger:hover{background:#DC2626}
      .btn-outline{background:#fff;color:#003366;border:1px solid #DEE2E6}.btn-outline:hover{background:#F8F9FA}
      .btn-success{background:#00A859;color:#fff}.btn-success:hover{background:#009950}
      .btn-warn{background:#F59E0B;color:#fff}.btn-warn:hover{background:#D97706}
      .action-dropdown{position:relative;display:inline-block}
      .action-dropdown-menu{display:none;position:absolute;top:100%;left:0;background:#fff;border:1px solid #DEE2E6;border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.12);z-index:100;min-width:220px;padding:4px 0;margin-top:4px}
      .action-dropdown-menu.show{display:block}
      .action-dropdown-item{padding:8px 14px;font-size:12px;cursor:pointer;display:flex;align-items:center;gap:8px;transition:background .15s}
      .action-dropdown-item:hover{background:#F8F9FA}
      .action-v2{display:flex;align-items:start;gap:10px;padding:10px 12px;background:#fff;border-radius:8px;margin-bottom:6px;border:1px solid #E9ECEF}
      .action-v2 .a-type{font-size:10px;font-weight:600;padding:2px 8px;border-radius:4px;color:#fff;white-space:nowrap}
      .action-v2 .a-body{flex:1;font-size:12px}
      .action-v2 .a-body .a-title{font-weight:600;color:#1a202c}
      .action-v2 .a-body .a-meta{color:#868E96;font-size:11px}
      .alert-item{padding:10px 12px;background:#fff;border-radius:8px;margin-bottom:6px;border-left:4px solid #EF4444;transition:all .2s}
      .alert-item:hover{box-shadow:0 2px 6px rgba(0,0,0,.06)}
      .alert-item .a-title{font-weight:600;font-size:12px;color:#1a202c}
      .alert-item .a-msg{font-size:11px;color:#495057;margin-top:3px}
      .alert-item .a-meta{font-size:10px;color:#868E96;margin-top:4px}
      .generate-banner{text-align:center;padding:16px;background:linear-gradient(135deg,#EBF4FF,#E6FFFA);border-radius:8px;border:1px solid #BEE3F8;margin-bottom:16px}
      .generate-banner .pending-count{font-size:24px;font-weight:700;color:#003366}
      .generate-banner .pending-label{font-size:12px;color:#4A5568}
      .empty-state{text-align:center;padding:40px;color:#868E96}
      .empty-state .icon{font-size:32px;margin-bottom:8px}
    </style>

    <div class="v2-grid">
      <!-- SIDEBAR -->
      <div class="v2-sidebar">
        <!-- Generate Banner -->
        <div class="generate-banner">
          <div class="pending-count">''' + str(pending) + '''</div>
          <div class="pending-label">items wachten op AI analyse</div>
          <button class="btn-sm btn-primary" style="margin-top:10px;padding:8px 20px;font-size:12px" onclick="generateTakes()">
            🧠 Genereer Consultant Takes
          </button>
        </div>

        <!-- Risico Verdeling -->
        <div class="v2-card">
          <h4>Risico Verdeling</h4>
          <div class="risk-bar">'''

    total_risk = max(sum(risks.values()), 1)
    for level, color in risk_colors.items():
        pct = round((risks.get(level, 0) / total_risk) * 100)
        if risks.get(level, 0) > 0:
            body += f'<div class="risk-segment" style="width:{pct}%;background:{color}" title="{risk_labels[level]}: {risks[level]}"></div>'

    body += '''</div>
          <div class="stat-row"><span class="lbl">🔴 Kritiek</span><span class="val" style="color:#DC2626">''' + str(risks.get('KRITIEK', 0)) + '''</span></div>
          <div class="stat-row"><span class="lbl">🟠 Hoog</span><span class="val" style="color:#EF4444">''' + str(risks.get('HOOG', 0)) + '''</span></div>
          <div class="stat-row"><span class="lbl">🟡 Medium</span><span class="val" style="color:#F59E0B">''' + str(risks.get('MEDIUM', 0)) + '''</span></div>
          <div class="stat-row"><span class="lbl">🟢 Laag</span><span class="val" style="color:#00A859">''' + str(risks.get('LAAG', 0)) + '''</span></div>
        </div>

        <!-- Stats -->
        <div class="v2-card">
          <h4>Statistieken</h4>
          <div class="stat-row"><span class="lbl">📊 Totaal items</span><span class="val">''' + str(total) + '''</span></div>
          <div class="stat-row"><span class="lbl">🧠 Geanalyseerd</span><span class="val">''' + str(analyzed) + '''</span></div>
          <div class="stat-row"><span class="lbl">✅ Afgehandeld</span><span class="val">''' + str(dismissed) + '''</span></div>
          <div class="stat-row"><span class="lbl">📋 Open acties</span><span class="val" style="color:#003366">''' + str(open_actions) + '''</span></div>
          <div class="stat-row"><span class="lbl">🚨 Unread alerts</span><span class="val" style="color:#EF4444">''' + str(open_alerts) + '''</span></div>
        </div>

        <!-- Quick Actions -->
        <div class="v2-card">
          <h4>Snelle Acties</h4>
          <div style="display:flex;flex-direction:column;gap:6px">
            <a href="{{BASE_PATH}}/lms/" class="btn-sm btn-outline" style="text-align:center">🎓 LMS Academy</a>
            <a href="{{BASE_PATH}}/rie" class="btn-sm btn-outline" style="text-align:center">📋 RI&E / HAZOP</a>
            <a href="{{BASE_PATH}}/agents" class="btn-sm btn-outline" style="text-align:center">🤖 Agent Launchpad</a>
            <a href="{{BASE_PATH}}/incidents-env" class="btn-sm btn-outline" style="text-align:center">🚨 Incidenten</a>
          </div>
        </div>
      </div>

      <!-- MAIN -->
      <div class="v2-main">
        <!-- Tabs -->
        <div class="v2-tabs">
          <div class="v2-tab active" onclick="switchV2Tab(this,'feed')">🧠 Intelligence Feed</div>
          <div class="v2-tab" onclick="switchV2Tab(this,'trending')">📈 Trending <span class="badge-count" style="background:#F59E0B">''' + str(len([t for t in trending])) + '''</span></div>
          <div class="v2-tab" onclick="switchV2Tab(this,'watchlist')">👁️ Watchlist <span class="badge-count" style="background:#7950F2">''' + str(len([w for w in watchlist])) + '''</span></div>
          <div class="v2-tab" onclick="switchV2Tab(this,'actions')">📋 Acties <span class="badge-count">''' + str(open_actions) + '''</span></div>
          <div class="v2-tab" onclick="switchV2Tab(this,'alerts')">🚨 Alerts <span class="badge-count" style="background:#EF4444">''' + str(open_alerts) + '''</span></div>
        </div>

        <!-- TAB: Intelligence Feed -->
        <div class="v2-tab-content active" id="v2tab-feed">'''

    if rows:
        for r in rows:
            item_id, source, title, url, content, scraped_at, category, take_json, risk_level, take_attempted_at = r
            take = {}
            if take_json:
                try: take = json.loads(take_json)
                except: pass

            risk_cls = risk_level or 'LAAG'
            rc = risk_colors.get(risk_cls, '#868E96')
            take_text = take.get('consultant_take', '')
            is_pending = not take_text
            if is_pending:
                # Eerlijke weergave: AI-analyse (nog) niet beschikbaar — nooit nep-advies
                take = build_unavailable_take(category, attempted_at=take_attempted_at)
                take_text = take['consultant_take']
            actions_list = take.get('actions', [])
            ci_score = take.get('compliance_impact_score')
            legal_risk = take.get('legal_risk_level')
            src_name = (source or '').replace('_', ' ').title()

            badge_label = risk_labels.get(risk_cls, risk_cls)
            badge_color = rc
            if is_pending:
                badge_label = '⏳ Analyse in wachtrij'
                badge_color = '#868E96'

            body += f'''
          <div class="insight-v2 risk-{risk_cls}" id="item-{item_id}">
            <div style="display:flex;justify-content:space-between;align-items:start;gap:8px">
              <div class="title">{title[:200]}</div>
              <span class="risk-badge" style="background:{badge_color}">{badge_label}</span>
            </div>
            <div class="meta">{src_name} · {category or 'Algemeen'} · {(scraped_at or '')[:10]}</div>
            <div style="font-size:12px;color:#495057;line-height:1.5;margin:6px 0">{(content or '')[:250]}</div>'''

            if take_text:
                if is_pending:
                    body += f'''
            <div class="take" style="background:#FFF9F0;border-color:#F5D8A0;color:#7A5B18">⚠️ <strong>Consultant Take:</strong> {take_text}</div>'''
                else:
                    body += f'''
            <div class="take">💡 <strong>Consultant Take:</strong> {take_text}</div>'''

            # Show enrichment badges for enriched items
            if ci_score or legal_risk:
                body += '<div style="display:flex;gap:6px;margin:6px 0;flex-wrap:wrap">'
                if ci_score:
                    ci_color = '#E03131' if ci_score >= 4 else '#F59F00' if ci_score >= 3 else '#4263EB'
                    body += f'<span style="background:{ci_color};color:#fff;padding:2px 8px;border-radius:10px;font-size:10px">🛡️ Compliance: {ci_score}/5</span>'
                if legal_risk:
                    lr_color = '#E03131' if legal_risk in ('HOOG','KRITIEK') else '#F59F00' if legal_risk == 'MEDIUM' else '#2B8A3E'
                    body += f'<span style="background:{lr_color};color:#fff;padding:2px 8px;border-radius:10px;font-size:10px">⚖️ Legal: {legal_risk}</span>'
                body += '<span style="background:#4263EB;color:#fff;padding:2px 8px;border-radius:10px;font-size:10px">🧠 Enriched</span>'
                body += '</div>'
            if actions_list:
                body += '<div style="margin:6px 0;font-size:11px;color:#868E96"><strong>Voorgestelde acties:</strong><ul style="margin:4px 0 0;padding-left:18px">'
                for a in actions_list[:3]:
                    body += f'<li>{a}</li>'
                body += '</ul></div>'

            body += f'''
            <div class="action-btns">
              <div class="action-dropdown">
                <button class="btn-sm btn-primary" onclick="toggleDropdown(this)">✅ Actie ondernemen</button>
                <div class="action-dropdown-menu">
                  <div class="action-dropdown-item" onclick="createV2Action({item_id},'training','🎓 Start Training')">🎓 Maak Training (LMS)</div>
                  <div class="action-dropdown-item" onclick="createV2Action({item_id},'news','📰 Nieuwsbericht')">📰 Genereer Nieuwsbericht</div>
                  <div class="action-dropdown-item" onclick="createV2Action({item_id},'rie','📋 RI&E Update')">📋 Update RI&E</div>
                  <div class="action-dropdown-item" onclick="createV2Action({item_id},'alert','📢 Team Alert')">📢 Stuur Team Alert</div>
                  <div class="action-dropdown-item" onclick="createV2Action({item_id},'custom','📝 Eigen Actie')">📝 Eigen Actie</div>
                </div>
              </div>
              <button class="btn-sm btn-outline" onclick="dismissItem({item_id})">❌ Afwijzen</button>
              {f'<a href="{url}" target="_blank" class="btn-sm btn-outline">🔗 Bron</a>' if url else ''}
            </div>
          </div>'''
    else:
        body += '<div class="empty-state"><div class="icon">🧠</div><div>Geen geanalyseerde items. Klik op "Genereer Consultant Takes" om te starten.</div></div>'

    # Trending Topics Tab
    body += '\n        </div>\n\n        <!-- TAB: Trending -->\n        <div class="v2-tab-content" id="v2tab-trending">'

    if trending:
        body += '<div style="display:grid;gap:12px">'
        for i, t in enumerate(trending):
            if isinstance(t, dict):
                topic = t.get('topic', t.get('title', str(t)))
                count = t.get('count', t.get('mentions', ''))
            else:
                topic = str(t)
                count = ''
            count_html = '<span style="font-size:11px;color:#868E96;background:#F9FAFB;padding:2px 8px;border-radius:10px">{} vermeldingen</span>'.format(count) if count else ''
            # Find related items from scraped_items
            related = []
            try:
                rc = sqlite3.connect(DB_PATH)
                rl = rc.execute("SELECT title, source_id, category, content, risk_level, consultant_take_json FROM scraped_items WHERE dismissed=0 AND (title LIKE ? OR content LIKE ?) ORDER BY id DESC LIMIT 3", ('%' + topic + '%', '%' + topic + '%')).fetchall()
                rc.close()
                related = rl
            except:
                pass
            body += '<div class="insight-v2" style="border-left-color:#F59E0B;padding:16px">'
            body += '<div style="display:flex;justify-content:space-between;align-items:center"><div class="title" style="font-size:15px">📈 {}</div>{}</div>'.format(topic, count_html)
            if related:
                body += '<div style="margin-top:10px;border-top:1px solid #F1F3F5;padding-top:8px">'
                body += '<div style="font-size:10px;text-transform:uppercase;color:#868E96;font-weight:600;margin-bottom:6px">Gerelateerde items</div>'
                risk_colors = {'KRITIEK': '#DC2626', 'HOOG': '#EF4444', 'MEDIUM': '#F59E0B', 'LAAG': '#00A859'}
                for ri in related:
                    rtitle, rsrc, rcat, rcontent, rrisk, rtake = ri
                    rc_color = risk_colors.get(rrisk or 'LAAG', '#868E96')
                    src_name = (rsrc or '').replace('_', ' ').title()
                    # Get consultant take if available
                    take_text = ''
                    if rtake:
                        try:
                            td = json.loads(rtake)
                            take_text = td.get('consultant_take', '')
                        except:
                            pass
                    body += '<div style="padding:8px 10px;background:#FAFBFC;border-radius:6px;margin-bottom:4px;border-left:3px solid {}">'.format(rc_color)
                    body += '<div style="font-size:12px;font-weight:600;color:#1a202c">{}</div>'.format(rtitle[:120])
                    body += '<div style="font-size:10px;color:#868E96">{} · {} · <span style="color:{}">{}</span></div>'.format(src_name, (rcat or 'Algemeen'), rc_color, (rrisk or 'LAAG'))
                    if take_text:
                        body += '<div style="font-size:11px;color:#495057;margin-top:3px">💡 {}</div>'.format(take_text[:150])
                    elif rcontent:
                        body += '<div style="font-size:11px;color:#495057;margin-top:3px">{}</div>'.format((rcontent or '')[:120])
                    body += '</div>'
                body += '</div>'
            else:
                body += '<div style="font-size:11px;color:#868E96;margin-top:6px">Geen gerelateerde scraped items gevonden</div>'
            body += '</div>'
        body += '</div>'
    else:
        body += '<div class="empty-state"><div class="icon">📈</div><div>Geen trending topics gevonden.</div></div>'

    # Watchlist Tab
    body += '\n        </div>\n\n        <!-- TAB: Watchlist -->\n        <div class="v2-tab-content" id="v2tab-watchlist">'

    if watchlist:
        body += '<div style="display:grid;gap:10px">'
        for w in watchlist:
            if isinstance(w, dict):
                wtopic = w.get('topic', w.get('title', str(w)))
                wreason = w.get('reason', w.get('description', ''))
                wpri = w.get('priority', 'MEDIUM')
            else:
                wtopic = str(w)
                wreason = 'Gemonitord item'
                wpri = 'MEDIUM'
            wc = {'KRITIEK': '#DC2626', 'HOOG': '#EF4444', 'MEDIUM': '#F59E0B'}.get(wpri, '#7950F2')
            body += f'\n          <div class="insight-v2" style="border-left-color:{wc}">\n            <div style="display:flex;justify-content:space-between;align-items:start;gap:8px">\n              <div class="title" style="font-size:14px">👁️ {wtopic}</div>\n              <span class="risk-badge" style="background:{wc}">{wpri}</span>\n            </div>\n            <div style="font-size:12px;color:#495057;margin-top:4px">{wreason}</div>\n          </div>'
        body += '</div>'
    else:
        body += '<div class="empty-state"><div class="icon">👁️</div><div>Geen watchlist items.</div></div>'

    body += '\n        </div>\n\n        <!-- TAB: Acties -->\n        <div class="v2-tab-content" id="v2tab-actions">'

    if v2_actions:
        action_type_labels = {'training': '🎓 Training', 'news': '📰 Nieuws', 'rie': '📋 RI&E', 'alert': '📢 Alert', 'custom': '📝 Actie'}
        action_type_colors = {'training': '#003366', 'news': '#7950F2', 'rie': '#00A859', 'alert': '#EF4444', 'custom': '#F59E0B'}
        for a in v2_actions:
            aid, sitem_id, atype, adata, atitle, asource, acreated, \
                item_title, item_content, item_source, item_category, item_url, \
                item_take_json, item_risk, astatus = a
            atc = action_type_colors.get(atype, '#868E96')
            atl = action_type_labels.get(atype, atype)
            # Parse rich action_data
            adesc = ''
            apri = 'MEDIUM'
            if adata:
                try:
                    ad = json.loads(adata) if isinstance(adata, str) else adata
                    adesc = ad.get('description', '')
                    apri = ad.get('priority', 'MEDIUM')
                except:
                    pass
            pri_colors = {'KRITIEK': '#DC2626', 'HOOG': '#EF4444', 'MEDIUM': '#F59E0B', 'LAAG': '#00A859'}
            pri_badge = '<span style="font-size:9px;padding:1px 6px;border-radius:4px;color:#fff;background:{}">{}</span>'.format(pri_colors.get(apri, '#868E96'), apri)
            desc_line = '<div style="font-size:11px;color:#495057;margin-top:3px">{}</div>'.format(adesc[:200]) if adesc else ''
            # Build execute button — routes to Agent Launchpad with FULL context
            exec_btn = ''
            import urllib.parse

            # Build rich context from original scraped item + consultant take
            take_text = ''
            if item_take_json:
                try:
                    td = json.loads(item_take_json)
                    take_text = td.get('consultant_take', '')
                except:
                    pass

            context_parts = []
            if item_title:
                context_parts.append('Oorspronkelijk item: {}'.format(item_title))
            if item_source:
                context_parts.append('Bron: {}'.format(item_source.replace('_', ' ').title()))
            if item_category:
                context_parts.append('Categorie: {}'.format(item_category))
            if item_risk:
                context_parts.append('Risiconiveau: {}'.format(item_risk))
            if take_text:
                context_parts.append('AI Consultant Take: {}'.format(take_text))
            if item_content:
                context_parts.append('Inhoud samenvatting: {}'.format((item_content or '')[:300]))
            if item_url:
                context_parts.append('URL: {}'.format(item_url))
            if adesc:
                context_parts.append('Actie beschrijving: {}'.format(adesc))
            context_parts.append('OPSLAG: Volg MASTER_SOP. Sla output op in /root/projects/jg/[project-naam]/deliverables/ met versietag. Update /logs/changelog.md. Gebruik JvG huisstijl (#003366 primair).')

            task_context = ' | '.join(context_parts)
            ctx_enc = urllib.parse.quote(task_context[:500])

            if atype == 'training':
                task_desc = 'Training maken: {} (op basis van HSEQ Intelligence alert)'.format(atitle or item_title or 'HSEQ Training')
                desc_enc = urllib.parse.quote(task_desc)
                exec_btn = '<a href="{}" class="btn-sm btn-primary" style="text-decoration:none" onclick="event.stopPropagation();startV2Action({}, this)" data-action-id="{}">▶️ Training maken</a>'.format(BASE_PATH + '/agents?agent_id=training_generator&task_description=' + desc_enc + '&context=' + ctx_enc, aid, aid)
            elif atype == 'news':
                task_desc = 'Nieuwsbericht: {} (HSEQ Intelligence update)'.format(atitle or item_title or 'HSEQ Nieuws')
                desc_enc = urllib.parse.quote(task_desc)
                exec_btn = '<a href="{}" class="btn-sm btn-primary" style="text-decoration:none" onclick="event.stopPropagation();startV2Action({}, this)" data-action-id="{}">▶️ Nieuwsbericht</a>'.format(BASE_PATH + '/agents?agent_id=technical_writer&task_description=' + desc_enc + '&context=' + ctx_enc, aid, aid)
            elif atype == 'rie':
                task_desc = 'RI&E update: {} (actie vanuit HSEQ Intelligence)'.format(atitle or item_title or 'Nieuwe ontwikkeling')
                desc_enc = urllib.parse.quote(task_desc)
                exec_btn = '<a href="{}" class="btn-sm btn-primary" style="text-decoration:none" onclick="event.stopPropagation();startV2Action({}, this)" data-action-id="{}">▶️ RI&E starten</a>'.format(BASE_PATH + '/agents?agent_id=hseq_specialist&task_description=' + desc_enc + '&context=' + ctx_enc, aid, aid)
            elif atype == 'alert':
                exec_btn = '<button class="btn-sm btn-warn" onclick="event.stopPropagation();sendTeamAlert({}, this)">📢 Verstuur</button>'.format(aid)
            elif atype == 'custom':
                task_desc = atitle or 'HSEQ Actie'
                desc_enc = urllib.parse.quote(task_desc)
                exec_btn = '<a href="{}" class="btn-sm btn-primary" style="text-decoration:none" onclick="event.stopPropagation();startV2Action({}, this)" data-action-id="{}">▶️ Start taak</a>'.format(BASE_PATH + '/agents?agent_id=hseq_specialist&task_description=' + desc_enc + '&context=' + ctx_enc, aid, aid)

            body += f'''
          <div class="action-v2" id="v2action-{aid}" style="padding:12px{';opacity:0.7' if astatus=='in_progress' else ''}">
            <span class="a-type" style="background:{atc}">{atl}</span>
            <div class="a-body">
              <div class="a-title">{(atitle or 'Onbekend')[:100]} {pri_badge}{'<span style="font-size:9px;padding:1px 6px;border-radius:4px;color:#fff;background:#3B82F6;margin-left:4px">⏳ In uitvoering</span>' if astatus=='in_progress' else ''}</div>
              <div class="a-meta">{asource} · {acreated[:16] if acreated else ''}</div>
              {desc_line}
            </div>
            <div style="display:flex;gap:4px;flex-shrink:0">{exec_btn}<button class="btn-sm btn-success" onclick="closeV2Action({aid}, this)">✓</button></div>
          </div>'''
    else:
        body += '<div class="empty-state"><div class="icon">📋</div><div>Geen openstaande acties</div></div>'

    body += '''
        </div>

        <!-- TAB: Alerts -->
        <div class="v2-tab-content" id="v2tab-alerts">'''

    if alerts:
        for al in alerts:
            alid, altitle, almsg, alpri, alsrc, alurl, alcreated = al
            alc = '#DC2626' if alpri == 'KRITIEK' else '#EF4444'
            body += f'''
          <div class="alert-item" style="border-left-color:{alc}" id="alert-{alid}">
            <div style="display:flex;justify-content:space-between;align-items:start">
              <div class="a-title">{(altitle or '')[:150]}</div>
              <span class="risk-badge" style="background:{alc}">{alpri}</span>
            </div>
            <div class="a-msg">{(almsg or '')[:200]}</div>
            <div class="a-meta">{alsrc} · {alcreated[:16] if alcreated else ''}</div>
            <div style="margin-top:6px;display:flex;gap:6px">
              <button class="btn-sm btn-outline" onclick="markAlertRead({alid})">✓ Gelezen</button>
              {f'<a href="{alurl}" target="_blank" class="btn-sm btn-outline">🔗 Bron</a>' if alurl else ''}
            </div>
          </div>'''
        body += '<div style="text-align:center;margin-top:12px"><button class="btn-sm btn-outline" onclick="markAllAlertsRead()">✅ Markeer alles als gelezen</button></div>'
    else:
        body += '<div class="empty-state"><div class="icon">🟢</div><div>Geen openstaande alerts</div></div>'

    body += '''
        </div>
      </div>
    </div>

    <script>
    function switchV2Tab(el, tab) {
        document.querySelectorAll('.v2-tab-content').forEach(t => t.classList.remove('active'));
        document.querySelectorAll('.v2-tab').forEach(t => t.classList.remove('active'));
        document.getElementById('v2tab-' + tab).classList.add('active');
        el.classList.add('active');
    }

    function toggleDropdown(btn) {
        const menu = btn.nextElementSibling;
        document.querySelectorAll('.action-dropdown-menu.show').forEach(m => { if(m !== menu) m.classList.remove('show'); });
        menu.classList.toggle('show');
    }

    // Close dropdowns on outside click
    document.addEventListener('click', function(e) {
        if (!e.target.closest('.action-dropdown')) {
            document.querySelectorAll('.action-dropdown-menu.show').forEach(m => m.classList.remove('show'));
        }
    });

    function createV2Action(itemId, actionType, label) {
        if(actionType === 'custom') {
            showActionModal(itemId, actionType);
            return;
        }
        var extraData = '';
        if(actionType === 'training') extraData = prompt('Training titel (of leeg laten voor item-titel):') || '';
        if(actionType === 'news') extraData = prompt('Nieuwsbericht onderwerp (of leeg laten):') || '';
        fetch('{{BASE_PATH}}/api/intelligence/v2/' + itemId + '/action', {
            method:'POST',
            headers:{'Content-Type':'application/json'},
            credentials:'same-origin',
            body: JSON.stringify({action_type: actionType, action_data: extraData || label})
        }).then(r => r.json()).then(d => {
            if(d.status === 'created') {
                showToast('✅ ' + label + ' aangemaakt');
                document.querySelectorAll('.action-dropdown-menu.show').forEach(m => m.classList.remove('show'));
            } else {
                showToast('❌ Fout: ' + (d.error || ''));
            }
        }).catch(() => showToast('❌ Netwerkfout'));
    }

    function showActionModal(itemId, actionType) {
        window._actionModalItemId = itemId;
        window._actionModalActionType = actionType;
        document.querySelectorAll('.action-dropdown-menu.show').forEach(m => m.classList.remove('show'));
        var modal = document.getElementById('actionModal');
        if(!modal) {
            modal = document.createElement('div');
            modal.id = 'actionModal';
            modal.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.5);z-index:10000;display:flex;align-items:center;justify-content:center';
            modal.innerHTML = '<div style="background:#fff;border-radius:12px;padding:24px;width:90%;max-width:480px;box-shadow:0 20px 60px rgba(0,0,0,.3)">' +
                '<h3 style="margin:0 0 4px;font-size:16px;color:#1a202c">📝 Nieuwe Actie</h3>' +
                '<p style="margin:0 0 16px;font-size:12px;color:#868E96">Beschrijf de actie die je wilt ondernemen</p>' +
                '<div style="margin-bottom:12px"><label style="font-size:11px;font-weight:600;color:#475569;display:block;margin-bottom:4px">Actietitel *</label>' +
                '<input id="actionTitle" type="text" placeholder="Bijv: Awareness training plannen" style="width:100%;padding:10px 12px;border:1px solid #E2E8F0;border-radius:6px;font-size:13px;font-family:inherit;box-sizing:border-box"></div>' +
                '<div style="margin-bottom:12px"><label style="font-size:11px;font-weight:600;color:#475569;display:block;margin-bottom:4px">Beschrijving / Context</label>' +
                '<textarea id="actionDesc" rows="3" placeholder="Wat moet er gebeuren, voor wie, wanneer?" style="width:100%;padding:10px 12px;border:1px solid #E2E8F0;border-radius:6px;font-size:13px;font-family:inherit;resize:vertical;box-sizing:border-box"></textarea></div>' +
                '<div style="margin-bottom:16px"><label style="font-size:11px;font-weight:600;color:#475569;display:block;margin-bottom:4px">Prioriteit</label>' +
                '<select id="actionPriority" style="width:100%;padding:10px 12px;border:1px solid #E2E8F0;border-radius:6px;font-size:13px;font-family:inherit;box-sizing:border-box">' +
                '<option value="LAAG">🟢 Laag</option><option value="MEDIUM" selected>🟡 Medium</option><option value="HOOG">🟠 Hoog</option><option value="KRITIEK">🔴 Kritiek</option></select></div>' +
                '<div style="display:flex;gap:8px;justify-content:flex-end">' +
                '<button onclick="closeActionModal()" style="padding:8px 16px;border:1px solid #DEE2E6;background:#fff;border-radius:6px;font-size:13px;cursor:pointer;font-family:inherit">Annuleren</button>' +
                '<button onclick="submitAction()" style="padding:8px 16px;background:#003366;color:#fff;border:none;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit">Opslaan</button>' +
                '</div></div>';
            document.body.appendChild(modal);
        }
        modal.style.display = 'flex';
        document.getElementById('actionTitle').value = '';
        document.getElementById('actionDesc').value = '';
        document.getElementById('actionPriority').value = 'MEDIUM';
        document.getElementById('actionTitle').focus();
    }

    function closeActionModal() {
        var modal = document.getElementById('actionModal');
        if(modal) modal.style.display = 'none';
    }

    function submitAction() {
        var itemId = window._actionModalItemId;
        var actionType = window._actionModalActionType;
        var title = document.getElementById('actionTitle').value.trim();
        var desc = document.getElementById('actionDesc').value.trim();
        var priority = document.getElementById('actionPriority').value;
        if(!title) { document.getElementById('actionTitle').style.borderColor='#EF4444'; return; }
        fetch('{{BASE_PATH}}/api/intelligence/v2/' + itemId + '/action', {
            method:'POST',
            headers:{'Content-Type':'application/json'},
            credentials:'same-origin',
            body: JSON.stringify({action_type: actionType, action_data: title, description: desc, priority: priority})
        }).then(r => r.json()).then(d => {
            if(d.status === 'created') {
                closeActionModal();
                showToast('✅ Actie aangemaakt: ' + title);
                setTimeout(() => location.reload(), 800);
            } else {
                showToast('❌ Fout: ' + (d.error || ''));
            }
        }).catch(() => showToast('❌ Netwerkfout'));
    }

    function dismissItem(itemId) {
        if(!confirm('Item afwijzen? Dit verwijdert het uit de feed.')) return;
        fetch('{{BASE_PATH}}/api/intelligence/v2/' + itemId + '/dismiss', {
            method:'POST', credentials:'same-origin'
        }).then(r => r.json()).then(d => {
            if(d.status === 'dismissed') {
                showToast('✅ Item afgewezen — statistieken worden bijgewerkt...');
                setTimeout(() => location.reload(), 800);
            }
        });
    }

    function startV2Action(actionId, btn) {
        fetch('{{BASE_PATH}}/api/intelligence/v2/actions/' + actionId + '/start', {
            method:'POST', credentials:'same-origin'
        }).then(r => r.json()).then(d => {
            if(d.status === 'in_progress') {
                var card = document.getElementById('v2action-' + actionId);
                if(card) card.style.opacity = '0.7';
                showToast('🚀 Actie gestart — navigeren naar Agent Launchpad...');
            }
        });
    }

    function closeV2Action(actionId, btn) {
        fetch('{{BASE_PATH}}/api/intelligence/v2/actions/' + actionId + '/close', {
            method:'POST', credentials:'same-origin'
        }).then(r => r.json()).then(d => {
            if(d.status === 'closed') {
                showToast('✅ Actie afgehandeld — bijwerken...');
                setTimeout(() => location.reload(), 800);
            }
        });
    }

    function sendTeamAlert(actionId, btn) {
        btn.textContent = '⏳ Verzenden...';
        btn.disabled = true;
        fetch('{{BASE_PATH}}/api/intelligence/v2/actions/' + actionId + '/alert', {
            method:'POST', credentials:'same-origin'
        }).then(r => r.json()).then(d => {
            if(d.status === 'sent') {
                showToast('✅ Team alert verzonden');
                btn.textContent = '✅ Verzonden';
                btn.style.background = '#00A859';
            } else {
                btn.textContent = '📢 Verstuur';
                btn.disabled = false;
                showToast('❌ Fout: ' + (d.error || ''));
            }
        }).catch(() => { btn.textContent = '📢 Verstuur'; btn.disabled = false; showToast('❌ Netwerkfout'); });
    }

    function markAlertRead(alertId) {
        fetch('{{BASE_PATH}}/api/intelligence/v2/alerts/' + alertId + '/read', {
            method:'POST', credentials:'same-origin'
        }).then(r => r.json()).then(d => {
            if(d.status === 'read') {
                showToast('✅ Alert gelezen — bijwerken...');
                setTimeout(() => location.reload(), 800);
            }
        });
    }

    function markAllAlertsRead() {
        fetch('{{BASE_PATH}}/api/intelligence/v2/alerts/read-all', {
            method:'POST', credentials:'same-origin'
        }).then(r => r.json()).then(d => {
            if(d.status === 'all_read') {
                showToast('✅ Alle alerts gelezen — bijwerken...');
                setTimeout(() => location.reload(), 800);
            }
        });
    }

    function generateTakes() {
        const btn = event.target.closest('button');
        btn.textContent = '⏳ Analyseren...';
        btn.disabled = true;
        fetch('{{BASE_PATH}}/api/intelligence/v2/generate', {
            method:'POST',
            headers:{'Content-Type':'application/json'},
            credentials:'same-origin',
            body: JSON.stringify({limit: 10})
        }).then(r => r.json()).then(d => {
            if(d.status === 'ok') {
                showToast('✅ ' + d.generated + ' items geanalyseerd — pagina wordt herladen...');
                setTimeout(() => location.reload(), 1500);
            } else {
                btn.textContent = '🧠 Genereer Consultant Takes';
                btn.disabled = false;
                showToast('❌ Fout bij genereren');
            }
        }).catch(() => {
            btn.textContent = '🧠 Genereer Consultant Takes';
            btn.disabled = false;
            showToast('❌ Netwerkfout');
        });
    }

    function showToast(msg) {
        const t = document.createElement('div');
        t.textContent = msg;
        t.style.cssText = 'position:fixed;bottom:20px;right:20px;padding:10px 20px;background:#1a202c;color:#fff;border-radius:8px;font-size:13px;z-index:9999;animation:fadeIn .3s';
        document.body.appendChild(t);
        setTimeout(() => { t.style.opacity='0'; t.style.transition='opacity .3s'; setTimeout(()=>t.remove(), 300); }, 3000);
    }
    </script>'''

    return body


def build_dashboard_alert_widget(BASE_PATH):
    """Build the HSEQ Alerts widget HTML for the main dashboard page."""
    return '''
    <style>
      .dashboard-alerts{background:#fff;border-radius:8px;padding:16px;box-shadow:0 1px 3px rgba(0,0,0,.08);margin-top:16px}
      .dashboard-alerts h3{margin:0 0 12px;font-size:14px;color:#003366;display:flex;align-items:center;gap:8px}
      .dashboard-alerts h3 .alert-count{background:#EF4444;color:#fff;font-size:10px;font-weight:700;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center}
      .dash-alert-item{display:flex;align-items:start;gap:10px;padding:8px 10px;border-radius:6px;margin-bottom:4px;border-left:3px solid #E9ECEF;transition:all .15s}
      .dash-alert-item:hover{background:#F8F9FA}
      .dash-alert-item.risk-KRITIEK{border-left-color:#DC2626;background:#FEF2F2}
      .dash-alert-item.risk-HOOG{border-left-color:#EF4444;background:#FFF5F5}
      .dash-alert-item.risk-MEDIUM{border-left-color:#F59E0B;background:#FFFBEB}
      .dash-alert-item .da-title{font-size:12px;font-weight:500;color:#1a202c;flex:1}
      .dash-alert-item .da-risk{font-size:10px;font-weight:600;padding:1px 6px;border-radius:4px;color:#fff}
    </style>
    <div class="dashboard-alerts" id="dashAlertsWidget">
      <h3>🚨 HSEQ Alerts <span class="alert-count" id="dashAlertCount">-</span></h3>
      <div id="dashAlertsContent" style="font-size:12px;color:#868E96;text-align:center;padding:10px">Laden...</div>
      <div style="text-align:right;margin-top:8px">
        <a href="{{BASE_PATH}}/intelligence" style="font-size:11px;color:#003366;text-decoration:none;font-weight:500">Bekijk alle →</a>
      </div>
    </div>
    <script>
    (function(){
        fetch('{{BASE_PATH}}/api/intelligence/v2/dashboard-summary').then(r=>r.json()).then(d => {
            document.getElementById('dashAlertCount').textContent = d.open_alerts || 0;
            var html = '';
            if(d.top_risks && d.top_risks.length > 0) {
                d.top_risks.forEach(function(item) {
                    var rc = item.risk === 'KRITIEK' ? '#DC2626' : item.risk === 'HOOG' ? '#EF4444' : item.risk === 'MEDIUM' ? '#F59E0B' : '#00A859';
                    html += '<div class="dash-alert-item risk-' + item.risk + '">' +
                        '<div class="da-title">' + item.title + '</div>' +
                        '<span class="da-risk" style="background:' + rc + '">' + item.risk + '</span>' +
                        '</div>';
                });
            } else {
                html = '<div style="text-align:center;padding:10px;color:#00A859">✅ Geen hoog-risico alerts</div>';
            }
            document.getElementById('dashAlertsContent').innerHTML = html;
        }).catch(function() {
            document.getElementById('dashAlertsContent').innerHTML = '<div style="color:#868E96">Kon alerts niet laden</div>';
        });
    })();
    </script>'''
