# ============================================================
# MODULE: Agent Launchpad & Workflow Templates — FASE 4
# HSEQ Intelligence Dashboard
# ============================================================

import json
import sqlite3
from datetime import datetime
from flask import jsonify, request
from indexer import DB_PATH
from search import search_documents, get_db


def init_db_agents():
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    c.execute('''CREATE TABLE IF NOT EXISTS agent_tasks (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        agent_id TEXT NOT NULL,
        agent_name TEXT NOT NULL,
        workflow_id TEXT,
        task_description TEXT NOT NULL,
        context TEXT,
        status TEXT DEFAULT 'pending',
        result TEXT,
        created_at TEXT DEFAULT CURRENT_TIMESTAMP,
        started_at TEXT,
        completed_at TEXT,
        metadata TEXT
    )''')
    conn.commit()
    conn.close()


AGENTS = [
    {"id": "hseq_specialist", "name": "HSEQ Specialist", "emoji": "🔬",
     "description": "Health, Safety, Environment & Quality — expert in BRZO, Arbowet, Milieu",
     "skills": ["BRZO compliance", "Risicoanalyse", "Inspectievoorbereiding", "HSEQ advies"],
     "deliverable_note": "DOCX rapport + XLSX risicotabel + HTML dashboard"},
    {"id": "compliance_auditor", "name": "Compliance Auditor", "emoji": "⚖️",
     "description": "Compliance & auditing specialist — wet- en regelgeving",
     "skills": ["Compliance audits", "Wetgeving interpretatie", "Gap-analyses", "Certificering"],
     "deliverable_note": "DOCX rapport + XLSX gap-analyse + HTML overzicht"},
    {"id": "risk_management", "name": "Risk Management Specialist", "emoji": "📊",
     "description": "Risicomanagement — HAZOP, LOPA, QRA, Bow-Tie",
     "skills": ["HAZOP", "LOPA", "QRA", "Bow-Tie analyse", "Risicomatrix"],
     "deliverable_note": "DOCX rapport + XLSX risicomatrix + HTML dashboard"},
    {"id": "qa_engineer", "name": "QA Engineer", "emoji": "✅",
     "description": "Quality Assurance — ISO 9001, KAM, procesvalidatie",
     "skills": ["ISO 9001", "KAM", "Procesvalidatie", "Kwaliteitscontrole"],
     "deliverable_note": "DOCX rapport + XLSX checklist + HTML overzicht"},
    {"id": "technical_writer", "name": "Technical Writer", "emoji": "📝",
     "description": "Technische documentatie — procedures, handleidingen, rapporten",
     "skills": ["Procedures", "Handleidingen", "Technische rapporten"],
     "deliverable_note": "DOCX procedure + XLSX bijlagen + HTML preview"},
    {"id": "environmental_compliance", "name": "Environmental Compliance Manager", "emoji": "🌍",
     "description": "Milieu & omgeving — emissies, vergunningen, Omgevingswet",
     "skills": ["Emissies", "Vergunningen", "Omgevingswet", "Milieurapportage"],
     "deliverable_note": "DOCX rapport + XLSX data + HTML dashboard"},
    {"id": "training_generator", "name": "Training Generator", "emoji": "🎓",
     "description": "Training ontwikkeling — toolbox talks, e-learning, VCA",
     "skills": ["Toolbox talks", "Training ontwerp", "VCA", "E-learning"],
     "deliverable_note": "DOCX inhoud + HTML presentatie + HTML quiz"},
    {"id": "presentation_specialist", "name": "Presentation Specialist", "emoji": "📊",
     "description": "Presentaties & document design — PPTX, rapportages",
     "skills": ["PPTX generatie", "Rapportage design", "Data visualisatie"],
     "deliverable_note": "DOCX rapport + HTML presentatie + HTML dashboard"},
    {"id": "software_architect", "name": "Software Architect", "emoji": "💻",
     "description": "Software ontwikkeling & systeemarchitectuur",
     "skills": ["Python", "Flask", "Database design", "API ontwikkeling"],
     "deliverable_note": "DOCX documentatie + XLSX schema + HTML preview"},
    {"id": "project_manager", "name": "Project Manager", "emoji": "📋",
     "description": "Projectmanagement — planning, resources, voortgang",
     "skills": ["Planning", "Resource management", "Risicomanagement"],
     "deliverable_note": "DOCX rapport + XLSX planning + HTML dashboard"},
]


WORKFLOWS = [
    {"id": "rie_opstellen", "name": "RI&E Opstellen",
     "description": "Volledige Risico-Inventarisatie & Evaluatie opstellen",
     "agents": ["hseq_specialist", "risk_management"],
     "questions": [
         {"id": "company", "label": "Bedrijfsnaam", "type": "text"},
         {"id": "sector", "label": "Sector", "type": "select", "options": ["Petrochemie", "Chemie", "Oil & Gas", "Offshore", "Bouw", "Industrie", "Overig"]},
         {"id": "employees", "label": "Aantal medewerkers", "type": "select", "options": ["1-10", "11-50", "51-200", "200+"]},
         {"id": "activities", "label": "Hoofdactiviteiten", "type": "textarea"},
         {"id": "hazardous_substances", "label": "Worden er gevaarlijke stoffen gebruikt?", "type": "select", "options": ["Ja", "Nee", "Onbekend"]},
         {"id": "existing_rie", "label": "Is er al een RI&E?", "type": "select", "options": ["Ja, moet geactualiseerd", "Nee, moet nieuw", "Onbekend"]},
     ],
     "output": "RI&E document (DOCX)"},
    {"id": "tra_maken", "name": "TRA Maken",
     "description": "Taakrisicoanalyse opstellen voor specifieke werkzaamheden",
     "agents": ["hseq_specialist", "qa_engineer"],
     "questions": [
         {"id": "task", "label": "Taak/werkzaamheid", "type": "text"},
         {"id": "location", "label": "Locatie", "type": "text"},
         {"id": "frequency", "label": "Frequentie", "type": "select", "options": ["Dagelijks", "Wekelijks", "Maandelijks", "Incidenteel"]},
         {"id": "hazards", "label": "Bekende gevaren", "type": "textarea"},
         {"id": "ppe", "label": "Vereiste PBM", "type": "text"},
     ],
     "output": "TRA document"},
    {"id": "training_prep", "name": "Training Prep",
     "description": "Training voorbereiden met presentatie en quiz",
     "agents": ["training_generator", "presentation_specialist"],
     "questions": [
         {"id": "topic", "label": "Onderwerp", "type": "text"},
         {"id": "target_audience", "label": "Doelgroep", "type": "select", "options": ["Operateurs", "Supervisors", "Management", "Contractors", "Alle medewerkers"]},
         {"id": "duration", "label": "Duur", "type": "select", "options": ["30 min", "1 uur", "2 uur", "Halve dag", "Hele dag"]},
         {"id": "level", "label": "Niveau", "type": "select", "options": ["Basis", "Gevorderd", "Specialist"]},
     ],
     "output": "PPTX + Quiz"},
    {"id": "compliance_check", "name": "Compliance Check",
     "description": "Uitgebreide compliance check tegen relevante wetgeving",
     "agents": ["compliance_auditor"],
     "questions": [
         {"id": "company", "label": "Bedrijfsnaam", "type": "text"},
         {"id": "regulations", "label": "Relevante wetgeving", "type": "multiselect", "options": ["BRZO", "Seveso", "Arbowet", "Omgevingswet", "PGS", "REACH/CLP", "ISO 45001", "ISO 14001"]},
         {"id": "scope", "label": "Scope van de check", "type": "textarea"},
     ],
     "output": "Rapport + aanbevelingen"},
    {"id": "audit_prep", "name": "Audit Voorbereiding",
     "description": "Voorbereiding op interne of externe audit",
     "agents": ["qa_engineer", "compliance_auditor"],
     "questions": [
         {"id": "audit_type", "label": "Type audit", "type": "select", "options": ["ISO 45001", "ISO 14001", "ISO 9001", "VCA", "ILT inspectie", "BRZO inspectie", "Interne audit"]},
         {"id": "scope", "label": "Auditscope", "type": "textarea"},
         {"id": "date", "label": "Geplande datum", "type": "text"},
         {"id": "previous_findings", "label": "Eerdere bevindingen", "type": "textarea"},
     ],
     "output": "Checklist + voorbereiding"},
    {"id": "incident_analyse", "name": "Incident Analyse",
     "description": "Uitgebreide analyse van een incident met verbetermaatregelen",
     "agents": ["hseq_specialist"],
     "questions": [
         {"id": "incident_type", "label": "Type incident", "type": "select", "options": ["Lekkage", "Brand/ontploffing", "Blessure", "Milieu-incident", "Near miss", "Bruikbare afwijking"]},
         {"id": "description", "label": "Beschrijving van het incident", "type": "textarea"},
         {"id": "location", "label": "Locatie", "type": "text"},
         {"id": "date", "label": "Datum", "type": "text"},
         {"id": "immediate_actions", "label": "Genomen directe maatregelen", "type": "textarea"},
     ],
     "output": "Analyse + verbetermaatregelen"},
]


def register_agent_routes(flask_app, page_func, BASE_PATH="/hseq-dashboard"):

    @flask_app.route(BASE_PATH + '/agents')
    def agents_page():
        body = '''
<div class="card">
  <h2>🤖 Agent Launchpad</h2>
  <p style="color:#868E96;margin:4px 0 16px;font-size:13px">Start gespecialiseerde HSEQ-agents voor complexe taken.</p>
  <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px;margin-bottom:24px">
    {% for agent in agents %}
    <div class="card" style="padding:16px;cursor:pointer;border-left:4px solid #3B82F6" onclick="selectAgent('{{agent.id}}')">
      <div style="font-size:28px;margin-bottom:8px">{{agent.emoji}}</div>
      <div style="font-weight:700;font-size:14px;color:#003366">{{agent.name}}</div>
      <div style="font-size:12px;color:#868E96;margin-top:4px">{{agent.description}}</div>
      <div style="margin-top:8px;display:flex;flex-wrap:wrap;gap:4px">
        {% for skill in agent.skills[:3] %}
        <span style="background:#F0F7FF;color:#003366;padding:2px 6px;border-radius:4px;font-size:10px">{{skill}}</span>
        {% endfor %}
      </div>
      {% if agent.deliverable_note %}
      <div style="margin-top:8px;padding:4px 8px;background:#D3F9D8;border-radius:4px;font-size:10px;color:#2B8A3E;font-weight:600">📦 {{agent.deliverable_note}}</div>
      {% endif %}
    </div>
    {% endfor %}
  </div>
  <h3>📋 Workflow Templates</h3>
  <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px;margin-top:8px">
    {% for wf in workflows %}
    <div class="card" style="padding:16px;cursor:pointer;border-left:4px solid #10B981" onclick="startWorkflow('{{wf.id}}')">
      <div style="font-weight:700;font-size:14px;color:#003366">{{wf.name}}</div>
      <div style="font-size:12px;color:#868E96;margin-top:4px">{{wf.description}}</div>
      <div style="margin-top:8px;display:flex;justify-content:space-between;align-items:center">
        <span style="font-size:11px;color:#868E96">Agents: {{wf.agents|length}}</span>
        <span style="background:#D3F9D8;color:#2B8A3E;padding:2px 8px;border-radius:4px;font-size:11px">📦 {{wf.output}}</span>
      </div>
    </div>
    {% endfor %}
  </div>
</div>
<div id="briefing-panel" style="display:none" class="card" style="margin-top:16px">
  <h3 id="briefing-title">Taak</h3>
  <div id="briefing-form" style="margin-top:12px"></div>
  <div style="margin-top:16px">
    <button onclick="submitTask()" class="btn btn-primary" style="padding:12px">🚀 Start</button>
    <button onclick="closeBriefing()" class="btn btn-outline" style="margin-left:8px">Annuleren</button>
  </div>
</div>
<div class="card" style="margin-top:16px;display:flex;justify-content:space-between;align-items:center">
  <h3>📊 Taak Historie</h3>
  <div id="executor-status" style="font-size:12px;color:#868E96">⏳ Executor status laden...</div>
</div>
<div id="task-history" style="margin-top:12px"><div style="text-align:center;padding:20px;color:#868E96">Laden...</div></div>
<script>
var BASE='{{BASE_PATH}}';
var AGENTS={{agents_json|safe}};
var WORKFLOWS={{workflows_json|safe}};
var currentMode=null,currentId=null;

// URL param pre-fill from Intelligence Hub actions
(function(){
  var p=new URLSearchParams(window.location.search);
  var aid=p.get('agent_id'),td=p.get('task_description'),ctx=p.get('context');
  if(aid){setTimeout(function(){selectAgent(aid);if(td){var el=document.getElementById('task-desc');if(el)el.value=td;} if(ctx){var el2=document.getElementById('task-context');if(el2)el2.value=ctx;} document.getElementById('briefing-panel').scrollIntoView({behavior:'smooth'});},300);}
})();

function selectAgent(agentId){
  currentMode='agent';currentId=agentId;
  var agent=AGENTS.find(function(a){return a.id===agentId});
  document.getElementById('briefing-title').textContent=agent.emoji+' '+agent.name+' — Taak Starten';
  document.getElementById('briefing-form').innerHTML=
    '<div style="padding:12px;background:#F0F7FF;border-radius:8px;margin-bottom:12px"><strong>'+agent.name+'</strong><br><span style="font-size:12px;color:#868E96">'+agent.description+'</span></div>'+
    '<label style="display:block;font-size:12px;font-weight:600;margin-bottom:4px">Taakbeschrijving *</label>'+
    '<textarea id="task-desc" rows="4" placeholder="Beschrijf de taak..." style="width:100%;padding:8px;border:1px solid #dee2e6;border-radius:6px;font-size:13px"></textarea>'+
    '<label style="display:block;font-size:12px;font-weight:600;margin-top:8px;margin-bottom:4px">Context</label>'+
    '<textarea id="task-context" rows="2" placeholder="Optioneel..." style="width:100%;padding:8px;border:1px solid #dee2e6;border-radius:6px;font-size:13px"></textarea>'+
    '<div id="kb-results" style="margin-top:12px"></div>';
  document.getElementById('briefing-panel').style.display='block';
  document.getElementById('briefing-panel').scrollIntoView({behavior:'smooth'});
  var descEl=document.getElementById('task-desc');
  var debounce=null;
  descEl.addEventListener('input',function(){
    clearTimeout(debounce);
    debounce=setTimeout(function(){
      var q=descEl.value.trim();
      if(q.length<3)return;
      fetch(BASE+'/api/kb/search?q='+encodeURIComponent(q)).then(function(r){return r.json()}).then(function(data){
        if(data.results&&data.results.length){
          var html='<div style="font-size:11px;font-weight:600;color:#868E96;margin-bottom:4px">📚 Kennisbank:</div>';
          data.results.slice(0,5).forEach(function(d){html+='<div style="padding:4px 8px;font-size:12px;border-left:2px solid #3B82F6;margin-bottom:2px">'+d.title+'</div>';});
          document.getElementById('kb-results').innerHTML=html;
        }
      }).catch(function(){});
    },500);
  });
}

function startWorkflow(wfId){
  currentMode='workflow';currentId=wfId;
  var wf=WORKFLOWS.find(function(w){return w.id===wfId});
  document.getElementById('briefing-title').textContent='📋 '+wf.name;
  var html='<div style="padding:12px;background:#D3F9D8;border-radius:8px;margin-bottom:12px"><strong>'+wf.name+'</strong><br><span style="font-size:12px;color:#2B8A3E">'+wf.description+'</span><br><span style="font-size:11px;color:#868E96">Output: '+wf.output+'</span></div>';
  wf.questions.forEach(function(q){
    html+='<div style="margin-bottom:10px"><label style="display:block;font-size:12px;font-weight:600;margin-bottom:4px">'+q.label+'</label>';
    if(q.type==='select'){
      html+='<select id="wf-'+q.id+'" style="width:100%;padding:8px;border:1px solid #dee2e6;border-radius:6px"><option value="">- Selecteer -</option>';
      q.options.forEach(function(o){html+='<option value="'+o+'">'+o+'</option>';});
      html+='</select>';
    }else if(q.type==='multiselect'){
      html+='<div style="display:flex;flex-wrap:wrap;gap:6px">';
      q.options.forEach(function(o){html+='<label style="display:flex;align-items:center;gap:4px;font-size:12px;padding:4px 8px;background:#F8F9FA;border:1px solid #DEE2E6;border-radius:4px;cursor:pointer"><input type="checkbox" value="'+o+'"> '+o+'</label>';});
      html+='</div>';
    }else if(q.type==='textarea'){
      html+='<textarea id="wf-'+q.id+'" rows="2" style="width:100%;padding:8px;border:1px solid #dee2e6;border-radius:6px"></textarea>';
    }else{
      html+='<input id="wf-'+q.id+'" type="text" style="width:100%;padding:8px;border:1px solid #dee2e6;border-radius:6px">';
    }
    html+='</div>';
  });
  html+='<div id="kb-results" style="margin-top:12px"></div>';
  document.getElementById('briefing-form').innerHTML=html;
  document.getElementById('briefing-panel').style.display='block';
  document.getElementById('briefing-panel').scrollIntoView({behavior:'smooth'});
}

function closeBriefing(){document.getElementById('briefing-panel').style.display='none';}

function submitTask(){
  var data={mode:currentMode,id:currentId};
  if(currentMode==='agent'){
    data.task_description=document.getElementById('task-desc').value;
    data.context=document.getElementById('task-context').value;
    var agent=AGENTS.find(function(a){return a.id===currentId});
    data.agent_id=currentId;data.agent_name=agent?agent.name:currentId;
  }else{
    var wf=WORKFLOWS.find(function(w){return w.id===currentId});
    data.agent_id=wf.agents[0];data.agent_name=wf.name;data.workflow_id=currentId;
    var answers={};
    wf.questions.forEach(function(q){
      var el=document.getElementById('wf-'+q.id);if(!el)return;
      if(q.type==='multiselect'){answers[q.id]=Array.from(el.parentElement.querySelectorAll('input:checked')).map(function(c){return c.value;});}
      else{answers[q.id]=el.value;}
    });
    data.task_description=wf.name+': '+JSON.stringify(answers);data.context=JSON.stringify(answers);
  }
  fetch(BASE+'/api/agents/task',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(data)})
    .then(function(r){return r.json()}).then(function(result){
      if(result.ok){alert('Taak gestart! ID: '+result.task_id);closeBriefing();loadTaskHistory();}
      else{alert('Fout: '+(result.error||'Onbekend'));}
    }).catch(function(err){alert('Fout: '+err.message);});
}

function loadTaskHistory(){
  fetch(BASE+'/api/agents/tasks').then(function(r){return r.json()}).then(function(data){
    if(!data.tasks||!data.tasks.length){document.getElementById('task-history').innerHTML='<div style="text-align:center;padding:20px;color:#868E96">Nog geen taken.</div>';return;}
    var tbl=document.createElement('table');tbl.style.width='100%';tbl.style.fontSize='12px';tbl.style.borderCollapse='collapse';
    var thead=document.createElement('thead');var hr=document.createElement('tr');hr.style.background='#f8f9fa';hr.style.textAlign='left';
    ['Agent','Taak','Status','Datum',''].forEach(function(h){var th=document.createElement('th');th.style.padding='8px';th.textContent=h;hr.appendChild(th);});
    thead.appendChild(hr);tbl.appendChild(thead);
    var tbody=document.createElement('tbody');
    data.tasks.forEach(function(t){
      var sc=t.status==='completed'?'#2B8A3E':t.status==='running'?'#4263EB':t.status==='failed'?'#E03131':'#F59F00';
      var tr=document.createElement('tr');
      tr.style.borderBottom='1px solid #eee';
      var td1=document.createElement('td');td1.style.padding='8px';td1.style.fontWeight='600';td1.textContent=t.agent_name;tr.appendChild(td1);
      var td2=document.createElement('td');td2.style.padding='8px';td2.textContent=t.task_description.substring(0,60)+'...';tr.appendChild(td2);
      var td3=document.createElement('td');td3.id='task-status-'+t.id;td3.style.padding='8px';
      var sp=document.createElement('span');sp.style.background=sc;sp.style.color='#fff';sp.style.padding='2px 8px';sp.style.borderRadius='10px';sp.style.fontSize='11px';sp.textContent=t.status;td3.appendChild(sp);tr.appendChild(td3);
      var td4=document.createElement('td');td4.style.padding='8px';td4.style.fontSize='11px';td4.style.color='#868E96';td4.textContent=t.created_at;tr.appendChild(td4);
      var td5=document.createElement('td');td5.style.padding='8px';
      var bView=document.createElement('button');bView.className='btn btn-sm btn-outline';bView.textContent='👁️';bView.onclick=function(){viewTask(t.id)};td5.appendChild(bView);
      if(t.status==='failed'){var bR=document.createElement('button');bR.textContent='🔄';bR.style.cssText='margin-left:4px;padding:2px 6px;font-size:10px;background:#F59F00;color:#fff;border:none;border-radius:4px;cursor:pointer';bR.onclick=function(){retryTask(t.id)};td5.appendChild(bR);}
      if(t.status==='pending'||t.status==='running'){var bC=document.createElement('button');bC.textContent='✖';bC.style.cssText='margin-left:4px;padding:2px 6px;font-size:10px;background:#E03131;color:#fff;border:none;border-radius:4px;cursor:pointer';bC.onclick=function(){cancelTask(t.id)};td5.appendChild(bC);}
      tr.appendChild(td5);
      tbody.appendChild(tr);
    });
    tbl.appendChild(tbody);
    document.getElementById('task-history').innerHTML='';
    document.getElementById('task-history').appendChild(tbl);
  });
}

function viewTask(id){
  fetch(BASE+'/api/agents/task/'+id).then(function(r){return r.json()}).then(function(t){
    if(t.error){alert(t.error);return;}
    var html='<div style="padding:16px;background:#f8f9fa;border-radius:8px"><h4>'+t.agent_name+'</h4><p style="font-size:13px">'+t.task_description+'</p>';
    if(t.result){
      var preview=t.result.substring(0,500);
      if(t.result.length>500)preview+='...';
      html+='<div style="margin-top:12px;padding:12px;background:#fff;border-radius:6px;border:1px solid #dee2e6"><pre style="white-space:pre-wrap;font-size:12px;max-height:300px;overflow-y:auto">'+preview+'</pre></div>';
    }
    if(t.deliverable_file){
      try {
        var delivs=JSON.parse(t.deliverable_file);
        if(Array.isArray(delivs)&&delivs.length>0){
          html+='<div style="margin-top:12px;padding:12px;background:#D3F9D8;border-radius:6px;border:1px solid #2B8A3E">';
          html+='<div style="font-size:13px;font-weight:600;color:#2B8A3E;margin-bottom:8px">📦 Multi-Deliverable Suite ('+delivs.length+' bestanden)</div>';
          delivs.forEach(function(d){
            var fmt=d.format?d.format.toUpperCase():'FILE';
            var icon=fmt==='DOCX'?'📄':fmt==='XLSX'?'📊':'🌐';
            html+='<div style="margin:6px 0;display:flex;align-items:center;gap:8px">';
            html+='<span style="font-size:10px;background:#fff;padding:2px 6px;border-radius:3px;font-weight:600;color:#003366">'+icon+' '+fmt+'</span>';
            html+='<span style="font-size:12px">'+d.label+'</span>';
            html+='</div>';
          });
          html+='</div>';
        }
      } catch(e) {
        var fname=t.deliverable_file.split('/').pop();
        html+='<div style="margin-top:12px;padding:12px;background:#EBF4FF;border-radius:6px;border:1px solid #3B82F6">';
        html+='<div style="font-size:13px;font-weight:600;color:#003366;margin-bottom:8px">Deliverable gegenereerd</div>';
        html+='<a href="/hseq-deliverables/html/'+fname+'" target="_blank" style="display:inline-block;padding:8px 16px;background:#003366;color:#fff;border-radius:6px;text-decoration:none;font-weight:600;font-size:13px">Open Deliverable (HTML)</a>';
        html+='</div>';
      }
    }
    if(t.status==='failed')html+='<button onclick="retryTask('+t.id+')" style="margin-top:8px;padding:8px 12px;background:#F59F00;color:#fff;border:none;border-radius:6px;cursor:pointer;font-weight:600">🔄 Opnieuw proberen</button>';
    html+='</div>';
    document.getElementById('briefing-form').innerHTML=html;
    document.getElementById('briefing-title').textContent='📋 Resultaat';
    document.getElementById('briefing-panel').style.display='block';
  });
}

function retryTask(id){
  fetch(BASE+'/api/agents/task/'+id+'/retry',{method:'POST'}).then(function(r){return r.json()}).then(function(d){
    if(d.ok){alert('Taak opnieuw in queue!');loadTaskHistory();}
    else{alert('Fout: '+(d.error||'Onbekend'));}
  });
}

function cancelTask(id){
  if(!confirm('Taak annuleren?'))return;
  fetch(BASE+'/api/agents/task/'+id+'/cancel',{method:'POST'}).then(function(r){return r.json()}).then(function(d){
    if(d.ok){loadTaskHistory();}
    else{alert('Fout: '+(d.error||'Onbekend'));}
  });
}

loadTaskHistory();
pollExecutorStatus();
function pollExecutorStatus(){
  fetch(BASE+'/api/agents/executor/status').then(function(r){return r.json()}).then(function(s){
    var el=document.getElementById('executor-status');
    if(!el)return;
    var dot=s.executor_running?'🟢':'🔴';
    var label=s.executor_running?'Actief':'Gestopt';
    var cur=s.current_task?' — Verwerkt #'+s.current_task:'';
    el.innerHTML=dot+' Executor '+label+cur+' | Queue: '+s.pending_tasks;
  }).catch(function(){});
  setTimeout(pollExecutorStatus,5000);
}
function pollTaskUpdates(){
  fetch(BASE+'/api/agents/tasks').then(function(r){return r.json()}).then(function(data){
    if(!data.tasks)return;
    data.tasks.forEach(function(t){
      var el=document.getElementById('task-status-'+t.id);
      if(el){
        var sc=t.status==='completed'?'#2B8A3E':t.status==='running'?'#4263EB':t.status==='failed'?'#E03131':t.status==='cancelled'?'#868E96':'#F59F00';
        el.innerHTML='<span style="background:'+sc+';color:#fff;padding:2px 8px;border-radius:10px;font-size:11px">'+t.status+'</span>';
        if(t.status==='completed'||t.status==='failed'){loadTaskHistory();}
      }
    });
  }).catch(function(){});
  setTimeout(pollTaskUpdates,5000);
}
pollTaskUpdates();
</script>
'''
        return page_func(body,
            page_title='Agent Launchpad', active='agents',
            agents=AGENTS, workflows=WORKFLOWS,
            agents_json=json.dumps(AGENTS), workflows_json=json.dumps(WORKFLOWS))

    @flask_app.route(BASE_PATH + '/api/agents')
    def api_agents_list():
        return jsonify({'agents': AGENTS})

    @flask_app.route(BASE_PATH + '/api/agents/task', methods=['POST'])
    def api_agents_task_create():
        d = request.get_json()
        agent_id = d.get('agent_id', '')
        agent_name = d.get('agent_name', agent_id)
        task_desc = d.get('task_description', '')
        context = d.get('context', '')
        workflow_id = d.get('workflow_id')
        if not agent_id or not task_desc:
            return jsonify({'error': 'Agent en taakbeschrijving zijn verplicht'}), 400
        kb_context = ''
        try:
            results = search_documents(task_desc, limit=5)
            if results and results.get('results'):
                for r in results['results'][:3]:
                    kb_context += "\n--- %s ---\n%s\n" % (r.get('title',''), r.get('content','')[:500])
        except:
            pass
        conn = sqlite3.connect(DB_PATH)
        conn.execute('INSERT INTO agent_tasks (agent_id, agent_name, workflow_id, task_description, context, status, metadata) VALUES (?,?,?,?,?,?,?)',
            (agent_id, agent_name, workflow_id, task_desc, context or kb_context, 'pending',
             json.dumps({'kb_context': kb_context[:2000], 'submitted_context': context})))
        conn.commit()
        task_id = conn.execute('SELECT last_insert_rowid()').fetchone()[0]
        conn.close()
        return jsonify({'ok': True, 'task_id': task_id, 'message': 'Taak gestart voor %s' % agent_name})

    @flask_app.route(BASE_PATH + '/api/agents/tasks')
    def api_agents_tasks_list():
        conn = sqlite3.connect(DB_PATH)
        rows = conn.execute('SELECT id, agent_id, agent_name, workflow_id, task_description, status, created_at, completed_at FROM agent_tasks ORDER BY created_at DESC LIMIT 50').fetchall()
        conn.close()
        return jsonify({'tasks': [
            {'id':r[0],'agent_id':r[1],'agent_name':r[2],'workflow_id':r[3],
             'task_description':r[4],'status':r[5],'created_at':r[6],'completed_at':r[7]}
            for r in rows]})

    @flask_app.route(BASE_PATH + '/api/agents/task/<int:task_id>')
    def api_agents_task_get(task_id):
        conn = sqlite3.connect(DB_PATH)
        row = conn.execute('SELECT id, agent_id, agent_name, workflow_id, task_description, context, status, result, created_at, started_at, completed_at, metadata, deliverable_file FROM agent_tasks WHERE id=?', (task_id,)).fetchone()
        conn.close()
        if not row:
            return jsonify({'error': 'Taak niet gevonden'}), 404
        return jsonify({'id':row[0],'agent_id':row[1],'agent_name':row[2],'workflow_id':row[3],
            'task_description':row[4],'context':row[5],'status':row[6],'result':row[7],
            'created_at':row[8],'started_at':row[9],'completed_at':row[10],'metadata':row[11],
            'deliverable_file':row[12]})

    @flask_app.route(BASE_PATH + '/api/agents/workflows')
    def api_agents_workflows_list():
        return jsonify({'workflows': WORKFLOWS})

    @flask_app.route(BASE_PATH + '/api/agents/workflow/<workflow_id>/run', methods=['POST'])
    def api_agents_workflow_run(workflow_id):
        wf = next((w for w in WORKFLOWS if w['id'] == workflow_id), None)
        if not wf:
            return jsonify({'error': 'Workflow niet gevonden'}), 404
        d = request.get_json() or {}
        conn = sqlite3.connect(DB_PATH)
        conn.execute('INSERT INTO agent_tasks (agent_id, agent_name, workflow_id, task_description, context, status, metadata) VALUES (?,?,?,?,?,?,?)',
            (wf['agents'][0], wf['name'], workflow_id,
             wf['name']+': '+json.dumps(d), json.dumps(d), 'pending',
             json.dumps({'workflow_answers': d})))
        conn.commit()
        task_id = conn.execute('SELECT last_insert_rowid()').fetchone()[0]
        conn.close()
        return jsonify({'ok': True, 'task_id': task_id, 'workflow': wf['name']})

    @flask_app.route(BASE_PATH + '/api/kb/search')
    def api_kb_search():
        q = request.args.get('q', '').strip()
        if not q:
            return jsonify({'results': []})
        try:
            results = search_documents(q, limit=10)
            items = []
            for r in results.get('results', [])[:10]:
                items.append({'id': r.get('id'), 'title': r.get('title') or r.get('filename', ''), 'category': r.get('category', '')})
            return jsonify({'results': items})
        except:
            return jsonify({'results': []})
