export function mount({ root, state, host }) {
  state = state || {};
  const __cleanup = [];
  const __setInterval = (...args) => {
    const id = window.setInterval(...args);
    __cleanup.push(() => window.clearInterval(id));
    return id;
  };
  const __setTimeout = (...args) => {
    const id = window.setTimeout(...args);
    __cleanup.push(() => window.clearTimeout(id));
    return id;
  };
  if (!(root instanceof HTMLElement)) return;

  const subtitleEl = root.querySelector('[data-sensor-subtitle]');
  const valueEl = root.querySelector('[data-sensor-value]');
  const unitEl = root.querySelector('[data-sensor-unit]');
  const statusEl = root.querySelector('[data-sensor-status]');
  const updatedEl = root.querySelector('[data-sensor-updated]');
  if (!(subtitleEl instanceof HTMLElement) || !(valueEl instanceof HTMLElement) || !(unitEl instanceof HTMLElement) || !(statusEl instanceof HTMLElement) || !(updatedEl instanceof HTMLElement)) return;

  const subtitle = typeof state.subtitle === 'string' ? state.subtitle : '';
  const configuredToolName = typeof state.tool_name === 'string' ? state.tool_name.trim() : '';
  const matchName = typeof state.match_name === 'string' ? state.match_name.trim() : '';
  const matchNames = Array.isArray(state.match_names)
    ? state.match_names.map((value) => String(value || '').trim()).filter(Boolean)
    : [];
  const searchTerms = Array.isArray(state.search_terms)
    ? state.search_terms.map((value) => String(value || '').trim()).filter(Boolean)
    : [];
  const deviceClass = typeof state.device_class === 'string' ? state.device_class.trim().toLowerCase() : '';
  const refreshMsRaw = Number(state.refresh_ms);
  const refreshMs = Number.isFinite(refreshMsRaw) && refreshMsRaw >= 1000 ? refreshMsRaw : 15000;
  const decimalsRaw = Number(state.value_decimals);
  const valueDecimals = Number.isFinite(decimalsRaw) && decimalsRaw >= 0 ? decimalsRaw : 0;
  const fallbackUnit = typeof state.unit === 'string' ? state.unit : '';
  const thresholds = state && typeof state.thresholds === 'object' && state.thresholds ? state.thresholds : {};
  const goodMax = Number(thresholds.good_max);
  const elevatedMax = Number(thresholds.elevated_max);
  const alertOnly = state.alert_only === true;
  const elevatedScoreRaw = Number(state.alert_score_elevated);
  const highScoreRaw = Number(state.alert_score_high);
  const elevatedScore = Number.isFinite(elevatedScoreRaw) ? elevatedScoreRaw : 88;
  const highScore = Number.isFinite(highScoreRaw) ? highScoreRaw : 98;

  subtitleEl.textContent = subtitle || matchName || matchNames[0] || 'Waiting for sensor data';
  unitEl.textContent = fallbackUnit || '--';
  const updateLiveContent = (snapshot) => {
    host.setLiveContent(snapshot);
  };

  const setStatus = (label, color) => {
    statusEl.textContent = label;
    statusEl.style.color = color;
  };

  const renderValue = (value) => {
    if (!Number.isFinite(value)) return '--';
    return valueDecimals > 0 ? value.toFixed(valueDecimals) : String(Math.round(value));
  };

  const stripQuotes = (value) => {
    const text = String(value ?? '').trim();
    if ((text.startsWith("'") && text.endsWith("'")) || (text.startsWith('"') && text.endsWith('"'))) {
      return text.slice(1, -1);
    }
    return text;
  };

  const normalizeText = (value) => String(value || '').trim().toLowerCase();

  const parseLiveContextEntries = (payloadText) => {
    const text = String(payloadText || '').replace(/\r/g, '');
    const startIndex = text.indexOf('- names: ');
    const relevant = startIndex >= 0 ? text.slice(startIndex) : text;
    const entries = [];
    let current = null;
    let inAttributes = false;

    const pushCurrent = () => {
      if (current) entries.push(current);
      current = null;
      inAttributes = false;
    };

    for (const rawLine of relevant.split('\n')) {
      if (rawLine.startsWith('- names: ')) {
        pushCurrent();
        current = {
          name: stripQuotes(rawLine.slice(9)),
          domain: '',
          state: '',
          areas: '',
          attributes: {},
        };
        continue;
      }
      if (!current) continue;
      const trimmed = rawLine.trim();
      if (!trimmed) continue;
      if (trimmed === 'attributes:') {
        inAttributes = true;
        continue;
      }
      if (rawLine.startsWith('  domain:')) {
        current.domain = stripQuotes(rawLine.slice(rawLine.indexOf(':') + 1));
        inAttributes = false;
        continue;
      }
      if (rawLine.startsWith('  state:')) {
        current.state = stripQuotes(rawLine.slice(rawLine.indexOf(':') + 1));
        inAttributes = false;
        continue;
      }
      if (rawLine.startsWith('  areas:')) {
        current.areas = stripQuotes(rawLine.slice(rawLine.indexOf(':') + 1));
        inAttributes = false;
        continue;
      }
      if (inAttributes && rawLine.startsWith('    ')) {
        const separatorIndex = rawLine.indexOf(':');
        if (separatorIndex >= 0) {
          const key = rawLine.slice(4, separatorIndex).trim();
          const value = stripQuotes(rawLine.slice(separatorIndex + 1));
          current.attributes[key] = value;
        }
        continue;
      }
      inAttributes = false;
    }

    pushCurrent();
    return entries;
  };

  const extractLiveContextText = (toolResult) => {
    if (toolResult && toolResult.parsed && typeof toolResult.parsed === 'object') {
      const parsed = toolResult.parsed;
      if (typeof parsed.result === 'string') return parsed.result;
    }
    if (typeof toolResult?.content === 'string') {
      try {
        const parsed = JSON.parse(toolResult.content);
        if (parsed && typeof parsed === 'object' && typeof parsed.result === 'string') {
          return parsed.result;
        }
      } catch {
        return toolResult.content;
      }
      return toolResult.content;
    }
    return '';
  };

  const allMatchNames = [matchName, ...matchNames].filter(Boolean);
  const allSearchTerms = [...allMatchNames, ...searchTerms].filter(Boolean);

  const scoreEntry = (entry) => {
    if (!entry || normalizeText(entry.domain) !== 'sensor') return Number.NEGATIVE_INFINITY;
    const entryName = normalizeText(entry.name);
    let score = 0;
    for (const candidate of allMatchNames) {
      const normalized = normalizeText(candidate);
      if (!normalized) continue;
      if (entryName === normalized) score += 100;
      else if (entryName.includes(normalized)) score += 40;
    }
    for (const term of allSearchTerms) {
      const normalized = normalizeText(term);
      if (!normalized) continue;
      if (entryName.includes(normalized)) score += 10;
    }
    const entryDeviceClass = normalizeText(entry.attributes?.device_class);
    if (deviceClass && entryDeviceClass === deviceClass) score += 30;
    if (fallbackUnit && normalizeText(entry.attributes?.unit_of_measurement) === normalizeText(fallbackUnit)) score += 8;
    return score;
  };

  const findSensorEntry = (entries) => {
    const scored = entries
      .map((entry) => ({ entry, score: scoreEntry(entry) }))
      .filter((item) => Number.isFinite(item.score) && item.score > 0)
      .sort((left, right) => right.score - left.score);
    return scored.length > 0 ? scored[0].entry : null;
  };

  const resolveToolName = async () => {
    if (configuredToolName) return configuredToolName;
    if (!host.listTools) return 'mcp_home_assistant_GetLiveContext';
    try {
      const tools = await host.listTools();
      const liveContextTool = Array.isArray(tools)
        ? tools.find((tool) => /(^|_)GetLiveContext$/i.test(String(tool?.name || '')))
        : null;
      return liveContextTool?.name || 'mcp_home_assistant_GetLiveContext';
    } catch {
      return 'mcp_home_assistant_GetLiveContext';
    }
  };

  const classify = (value) => {
    if (!Number.isFinite(value)) return { label: 'Unavailable', color: 'var(--theme-status-danger)' };
    if (Number.isFinite(elevatedMax) && value > elevatedMax) return { label: 'High', color: 'var(--theme-status-danger)' };
    if (Number.isFinite(goodMax) && value > goodMax) return { label: 'Elevated', color: 'var(--theme-status-warning)' };
    return { label: 'Good', color: 'var(--theme-status-live)' };
  };

  const computeAlertVisibility = (statusLabel) => {
    if (!alertOnly) return false;
    return statusLabel === 'Good' || statusLabel === 'Unavailable';
  };

  const computeAlertScore = (statusLabel, value) => {
    if (!alertOnly) return Number.isFinite(value) ? 0 : null;
    if (statusLabel === 'High') return highScore;
    if (statusLabel === 'Elevated') return elevatedScore;
    return 0;
  };

  const refresh = async () => {
    const resolvedToolName = await resolveToolName();
    if (!resolvedToolName) {
      const errorText = 'Missing tool_name';
      valueEl.textContent = '--';
      setStatus('No tool', 'var(--theme-status-danger)');
      updatedEl.textContent = errorText;
      updateLiveContent({
        kind: 'sensor',
        subtitle: subtitleEl.textContent || null,
        tool_name: null,
        match_name: matchName || matchNames[0] || null,
        value: null,
        display_value: '--',
        unit: fallbackUnit || null,
        status: 'No tool',
        updated_at: errorText,
        error: errorText,
      });
      return;
    }

    setStatus('Refreshing', 'var(--theme-status-muted)');
    try {
      const toolResult = await host.callTool(resolvedToolName, {});
      const entries = parseLiveContextEntries(extractLiveContextText(toolResult));
      const entry = findSensorEntry(entries);
      if (!entry) throw new Error('Matching sensor not found in live context');
      const attrs = entry.attributes && typeof entry.attributes === 'object' ? entry.attributes : {};
      const numericValue = Number(entry.state);
      const renderedValue = renderValue(numericValue);
      valueEl.textContent = renderedValue;
      const unit = fallbackUnit || String(attrs.unit_of_measurement || '--');
      unitEl.textContent = unit;
      subtitleEl.textContent = subtitle || entry.name || matchName || matchNames[0] || 'Sensor';
      const status = classify(numericValue);
      setStatus(status.label, status.color);
      const updatedText = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
      updatedEl.textContent = updatedText;
      updateLiveContent({
        kind: 'sensor',
        subtitle: subtitleEl.textContent || null,
        tool_name: resolvedToolName,
        match_name: entry.name || matchName || matchNames[0] || null,
        value: Number.isFinite(numericValue) ? numericValue : null,
        display_value: renderedValue,
        unit,
        status: status.label,
        updated_at: updatedText,
        score: computeAlertScore(status.label, numericValue),
        hidden: computeAlertVisibility(status.label),
      });
    } catch (error) {
      const errorText = String(error);
      valueEl.textContent = '--';
      setStatus('Unavailable', 'var(--theme-status-danger)');
      updatedEl.textContent = errorText;
      updateLiveContent({
        kind: 'sensor',
        subtitle: subtitleEl.textContent || null,
        tool_name: resolvedToolName,
        match_name: matchName || matchNames[0] || null,
        value: null,
        display_value: '--',
        unit: fallbackUnit || null,
        status: 'Unavailable',
        updated_at: errorText,
        error: errorText,
        score: alertOnly ? 0 : null,
        hidden: alertOnly,
      });
    }
  };

  host.setRefreshHandler(() => {
    void refresh();
  });
  void refresh();
  __setInterval(() => { void refresh(); }, refreshMs);

  return {
    destroy() {
      host.setRefreshHandler(null);
      host.setLiveContent(null);
      host.clearSelection();
      for (const cleanup of __cleanup.splice(0)) cleanup();
    },
  };
}
