/**
 * Herman Assistant — browser widget + gedeelde chat/voice logica
 */
window.HermanAssistant = (function () {
  var SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;

  function nowTime() {
    return new Date().toLocaleTimeString('nl-NL', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
  }

  function entityTypeLabel(t) {
    var m = {
      distributor: 'Distributeur', wholesaler: 'Groothandel', importer: 'Importeur',
      logistics: 'Logistiek', restaurant: 'Restaurant', caterer: 'Cateraar',
      butcher: 'Slager', doner: 'Döner',
    };
    return m[t] || t || '—';
  }

  function newSessionId(prefix) {
    return (prefix || 'br') + '-' + Date.now() + '-' + Math.random().toString(36).slice(2, 9);
  }

  function baseState(opts) {
    opts = opts || {};
    return {
      channel: opts.channel || 'browser',
      sessionPrefix: opts.sessionPrefix || 'br',
      open: false,
      hidden: false,
      status: 'idle',
      statusDetail: '',
      livePreview: '',
      liveInterim: false,
      recording: false,
      busy: false,
      speakReply: true,
      handsFreeMode: false,
      useBrowserPreview: !!SpeechRecognition,
      turns: [],
      manualText: '',
      pendingAction: null,
      resultsOpen: false,
      resultsTitle: '',
      resultsTotal: 0,
      resultsEntities: [],
      resultsOpenUrl: '',
      webbuilderOpen: false,
      webbuilderTitle: '',
      webbuilderProject: '',
      webbuilderPreview: '',
      webbuilderAgentsUrl: '/agents',
      webbuilderNas: '',
      sessionId: newSessionId(opts.sessionPrefix || 'br'),
      mediaRecorder: null,
      chunks: [],
      stream: null,
      recognition: null,
      holdIgnoreClick: false,
      _resumeTimer: null,
      _silenceTimer: null,
      _maxRecordTimer: null,

      initWidget: function () { /* overridden in browserWidget */ },

      toggleOpen: function () {
        this.open = !this.open;
        try { localStorage.setItem('herman_assistant_open', this.open ? '1' : '0'); } catch (e) { /* empty */ }
      },

      scrollLog: function () {
        var self = this;
        this.$nextTick(function () {
          var log = self.$refs.chatLog;
          if (log) log.scrollTop = log.scrollHeight;
        });
      },

      addTurn: function (role, text, meta) {
        this.turns.push({ role: role, text: text, meta: meta || {}, at: nowTime() });
        this.scrollLog();
      },

      handleHermanResponse: function (h) {
        if (!h) return;
        this.pendingAction = h.pending_action || (h.needs_confirmation ? this.pendingAction : null);
        if (!h.needs_confirmation && !h.pending_action) this.pendingAction = null;
        if (h.reply) {
          this.addTurn('agent', h.reply, {
            agent_label: h.agent_label,
            delegated: h.delegated_agents,
            routing_reason: h.routing_reason,
          });
        }
          var actions = h.ui_actions || [];
          for (var i = 0; i < actions.length; i++) {
            if (actions[i].type === 'show_export_results') this.openResultsModal(actions[i]);
            if (actions[i].type === 'open_webbuilder_build') this.openWebbuilderModal(actions[i]);
          }
          if (!actions.length && h.webbuilder_preview_url) {
            this.openWebbuilderModal({
              type: 'open_webbuilder_build',
              title: 'Website build — ' + (h.webbuilder_project || 'project'),
              project: h.webbuilder_project,
              preview_url: h.webbuilder_preview_url,
              agents_url: '/agents',
            });
          }
        if (this.speakReply && h.reply && window.speechSynthesis) {
          var self = this;
          window.speechSynthesis.cancel();
          var u = new SpeechSynthesisUtterance(h.reply.replace(/\*\*/g, '').slice(0, 800));
          u.lang = 'nl-NL';
          u.onend = function () { self.maybeResumeListening(300); };
          window.speechSynthesis.speak(u);
        } else {
          this.maybeResumeListening(h.needs_confirmation ? 800 : 500);
        }
      },

      maybeResumeListening: function (delay) {
        var self = this;
        if (!this.handsFreeMode || this.busy || this.recording) return;
        if (this._resumeTimer) clearTimeout(this._resumeTimer);
        this._resumeTimer = setTimeout(function () {
          if (self.handsFreeMode && !self.busy && !self.recording) self.startListen();
        }, delay || 500);
      },

      openResultsModal: function (action) {
        this.resultsTitle = action.title || 'Export Intel';
        this.resultsEntities = action.entities || [];
        this.resultsTotal = action.total || this.resultsEntities.length;
        this.resultsOpenUrl = action.open_url || '/export-intel';
        this.resultsOpen = true;
      },

      closeResultsModal: function () { this.resultsOpen = false; },

      openWebbuilderModal: function (action) {
        this.webbuilderTitle = action.title || 'Website build';
        this.webbuilderProject = action.project || '';
        this.webbuilderPreview = action.preview_url || '';
        this.webbuilderAgentsUrl = action.agents_url || '/agents';
        this.webbuilderNas = action.nas_path || '';
        this.webbuilderOpen = true;
      },

      closeWebbuilderModal: function () { this.webbuilderOpen = false; },

      confirmPending: function () {
        if (!this.pendingAction || !this.pendingAction.id) return;
        this.manualText = 'ja';
        this.sendText(this.pendingAction.id);
      },

      cancelPending: function () {
        this.pendingAction = null;
        this.manualText = 'nee';
        this.sendText();
      },

      entityTypeLabel: entityTypeLabel,

      _startRecognition: function () {
        if (!this.useBrowserPreview || !SpeechRecognition) return;
        var self = this;
        try {
          this.recognition = new SpeechRecognition();
          this.recognition.lang = 'nl-NL';
          this.recognition.interimResults = true;
          this.recognition.continuous = true;
          this.recognition.onresult = function (e) {
            var interim = '', final = '';
            for (var i = e.resultIndex; i < e.results.length; i++) {
              if (e.results[i].isFinal) final += e.results[i][0].transcript;
              else interim += e.results[i][0].transcript;
            }
            self.liveInterim = !!interim && !final;
            self.livePreview = final || interim;
            if (final && self.handsFreeMode && self.recording) self._scheduleSilenceStop();
          };
          this.recognition.start();
        } catch (e) { /* empty */ }
      },

      _stopRecognition: function () {
        if (this.recognition) {
          try { this.recognition.stop(); } catch (e) { /* empty */ }
          this.recognition = null;
        }
      },

      _stopStream: function () {
        if (this.stream) {
          this.stream.getTracks().forEach(function (t) { t.stop(); });
          this.stream = null;
        }
      },

      _scheduleSilenceStop: function () {
        var self = this;
        if (this._silenceTimer) clearTimeout(this._silenceTimer);
        this._silenceTimer = setTimeout(function () {
          if (self.recording && self.handsFreeMode) self.stopListen();
        }, 1600);
      },

      async startListen() {
        if (this.recording || this.busy) return;
        var self = this;
        this.livePreview = '';
        this.status = 'listening';
        this.statusDetail = 'Luisteren…';
        try {
          this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
          this.chunks = [];
          this.mediaRecorder = new MediaRecorder(this.stream);
          this.mediaRecorder.ondataavailable = function (e) {
            if (e.data && e.data.size) self.chunks.push(e.data);
          };
          this.mediaRecorder.onstop = function () {
            self._stopRecognition();
            self._stopStream();
            if (self._silenceTimer) clearTimeout(self._silenceTimer);
            if (self._maxRecordTimer) clearTimeout(self._maxRecordTimer);
            var blob = new Blob(self.chunks, { type: 'audio/webm' });
            self.recording = false;
            if (blob.size > 0) self.processVoice(blob);
            else { self.status = 'idle'; self.statusDetail = ''; }
          };
          this.mediaRecorder.start(250);
          this.recording = true;
          this._startRecognition();
          if (this.handsFreeMode) {
            if (this._maxRecordTimer) clearTimeout(this._maxRecordTimer);
            this._maxRecordTimer = setTimeout(function () {
              if (self.recording) self.stopListen();
            }, 18000);
          }
        } catch (e) {
          this.status = 'error';
          this.statusDetail = e.message;
          Cockpit.toast('Microfoon: ' + e.message, 'error');
        }
      },

      stopListen: function () {
        if (!this.recording || !this.mediaRecorder) return;
        this.mediaRecorder.stop();
      },

      toggleListen: function () {
        if (this.recording) this.stopListen();
        else this.startListen();
      },

      micClass: function () {
        if (this.recording) return 'is-listening';
        if (this.busy) return 'is-busy';
        return '';
      },

      onMicDown: function () { this.holdIgnoreClick = true; this.startListen(); },
      onMicUp: function () {
        if (this.recording && !this.handsFreeMode) this.stopListen();
        var self = this;
        setTimeout(function () { self.holdIgnoreClick = false; }, 250);
      },
      onMicClick: function () {
        if (this.holdIgnoreClick) return;
        this.toggleListen();
      },

      async processVoice(blob) {
        this.busy = true;
        this.status = 'processing';
        this.statusDetail = 'Whisper + Herman…';
        try {
          var fd = new FormData();
          fd.append('file', new File([blob], 'live.webm', { type: 'audio/webm' }));
          fd.append('session_id', this.sessionId);
          var r = await fetch('/api/voice/turn', { method: 'POST', body: fd });
          var j = await r.json();
          if (!r.ok) throw new Error(j.detail || j.error || 'Voice mislukt');
          var text = j.text || '';
          this.livePreview = text;
          this.manualText = text;
          if (text) this.addTurn('user', text, { source: 'voice' });
          this.handleHermanResponse(j.herman || {});
          this.status = 'idle';
          this.statusDetail = '';
        } catch (e) {
          this.status = 'error';
          this.statusDetail = e.message;
          Cockpit.toast(e.message, 'error');
        }
        this.busy = false;
      },

      async sendText(confirmActionId) {
        var text = (this.manualText || '').trim();
        if (!text) return;
        this.busy = true;
        this.status = 'processing';
        try {
          var body = { message: text, channel: this.channel, session_id: this.sessionId };
          if (confirmActionId) body.confirm_action_id = confirmActionId;
          var r = await Cockpit.api('/api/herman/chat', { method: 'POST', body: JSON.stringify(body) });
          this.addTurn('user', text, { source: 'text' });
          this.manualText = '';
          this.handleHermanResponse(r);
          this.status = 'idle';
        } catch (e) {
          Cockpit.toast(e.message, 'error');
          this.status = 'error';
        }
        this.busy = false;
      },

      formatDelegated: function (meta) {
        var d = (meta && meta.delegated) || [];
        return d.filter(function (a) { return String(a).toLowerCase() !== 'herman'; }).join(', ');
      },
    };
  }

  return {
    browserWidget: function () {
      var s = baseState({ channel: 'browser', sessionPrefix: 'br' });
      s.initWidget = function () {
        if (window.location.pathname.indexOf('/voice') === 0) this.hidden = true;
        if (window.location.pathname.indexOf('/herman') === 0) this.hidden = true;
        try {
          var raw = localStorage.getItem('herman_assistant_open');
          if (raw === '1') this.open = true;
        } catch (e) { /* empty */ }
      };
      return s;
    },
    chatPage: function () {
      var s = baseState({ channel: 'browser', sessionPrefix: 'hc' });
      s.imagePrompt = '';
      s.generating = false;
      s.lastImage = '';
      s.initChat = function () {
        this.open = true;
      };
      s.generateImage = async function () {
        if (!this.imagePrompt.trim()) return;
        this.generating = true;
        try {
          var r = await Cockpit.api('/api/ai/generate-image', {
            method: 'POST',
            body: JSON.stringify({ prompt: this.imagePrompt, width: 512, height: 512, steps: 15 }),
          });
          if (r.proxy_url) {
            this.lastImage = r.proxy_url;
            this.addTurn('agent', 'Afbeelding: ' + this.imagePrompt, { agent_label: 'Design', image_url: r.proxy_url });
          }
          Cockpit.toast('Afbeelding gegenereerd', 'success');
        } catch (e) { Cockpit.toast(e.message, 'error'); }
        this.generating = false;
      };
      return s;
    },
    entityTypeLabel: entityTypeLabel,
  };
})();

function hermanBrowserWidget() {
  return HermanAssistant.browserWidget();
}
