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-weather-subtitle]');
  const tempEl = root.querySelector('[data-weather-temp]');
  const unitEl = root.querySelector('[data-weather-unit]');
  const humidityEl = root.querySelector('[data-weather-humidity]');
  const windEl = root.querySelector('[data-weather-wind]');
  const rainEl = root.querySelector('[data-weather-rain]');
  const uvEl = root.querySelector('[data-weather-uv]');
  const statusEl = root.querySelector('[data-weather-status]');
  if (!(subtitleEl instanceof HTMLElement) || !(tempEl instanceof HTMLElement) || !(unitEl instanceof HTMLElement) || !(humidityEl instanceof HTMLElement) || !(windEl instanceof HTMLElement) || !(rainEl instanceof HTMLElement) || !(uvEl instanceof HTMLElement) || !(statusEl instanceof HTMLElement)) return;

  const subtitle = typeof state.subtitle === 'string' ? state.subtitle : '';
  const configuredToolName = typeof state.tool_name === 'string' ? state.tool_name.trim() : '';
  const configuredForecastToolName = typeof state.forecast_tool_name === 'string' ? state.forecast_tool_name.trim() : 'exec';
  const forecastCommand = typeof state.forecast_command === 'string' ? state.forecast_command.trim() : '';
  const providerPrefix = typeof state.provider_prefix === 'string' ? state.provider_prefix.trim() : '';
  const temperatureName = typeof state.temperature_name === 'string' ? state.temperature_name.trim() : '';
  const humidityName = typeof state.humidity_name === 'string' ? state.humidity_name.trim() : '';
  const uvName = typeof state.uv_name === 'string' ? state.uv_name.trim() : '';
  const morningStartHourRaw = Number(state.morning_start_hour);
  const morningEndHourRaw = Number(state.morning_end_hour);
  const morningScoreRaw = Number(state.morning_score);
  const defaultScoreRaw = Number(state.default_score);
  const refreshMsRaw = Number(state.refresh_ms);
  const refreshMs = Number.isFinite(refreshMsRaw) && refreshMsRaw >= 60000 ? refreshMsRaw : 24 * 60 * 60 * 1000;
  const morningStartHour = Number.isFinite(morningStartHourRaw) ? morningStartHourRaw : 6;
  const morningEndHour = Number.isFinite(morningEndHourRaw) ? morningEndHourRaw : 11;
  const morningScore = Number.isFinite(morningScoreRaw) ? morningScoreRaw : 84;
  const defaultScore = Number.isFinite(defaultScoreRaw) ? defaultScoreRaw : 38;

  subtitleEl.textContent = subtitle || providerPrefix || 'Waiting for weather data';
  const updateLiveContent = (snapshot) => {
    host.setLiveContent(snapshot);
  };

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

  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 stripExecFooter = (value) => String(value || '').replace(/\n+\s*Exit code:\s*\d+\s*$/i, '').trim();

  const extractExecJson = (toolResult) => {
    const parsedText = stripExecFooter(toolResult?.content);
    if (!parsedText) return null;
    try {
      return JSON.parse(parsedText);
    } catch {
      return 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 findEntry = (entries, candidates) => {
    const normalizedCandidates = candidates.map((value) => normalizeText(value)).filter(Boolean);
    if (normalizedCandidates.length === 0) return null;
    const exactMatch = entries.find((entry) => normalizedCandidates.includes(normalizeText(entry.name)));
    if (exactMatch) return exactMatch;
    return entries.find((entry) => {
      const entryName = normalizeText(entry.name);
      return normalizedCandidates.some((candidate) => entryName.includes(candidate));
    }) || null;
  };

  const resolveForecastBundle = async () => {
    if (!forecastCommand) return null;
    const toolResult = await host.callTool(configuredForecastToolName || 'exec', {
      command: forecastCommand,
      max_output_chars: 200000,
    });
    const payload = extractExecJson(toolResult);
    return payload && typeof payload === 'object' ? payload : null;
  };

  const firstForecastEntry = (bundle, key, metricKey = '') => {
    const source = bundle && typeof bundle === 'object' ? bundle[key] : null;
    const forecast = source && typeof source === 'object' && Array.isArray(source.forecast) ? source.forecast : [];
    if (!metricKey) {
      return forecast.length > 0 && forecast[0] && typeof forecast[0] === 'object' ? forecast[0] : null;
    }
    return forecast.find((entry) => entry && typeof entry === 'object' && entry[metricKey] !== null && entry[metricKey] !== undefined) || null;
  };

  const estimateUvIndex = (cloudCoverage) => {
    const now = new Date();
    const hour = now.getHours() + now.getMinutes() / 60;
    const daylightPhase = Math.sin(((hour - 6) / 12) * Math.PI);
    if (!Number.isFinite(daylightPhase) || daylightPhase <= 0) return 0;
    const normalizedCloudCoverage = Number.isFinite(cloudCoverage)
      ? Math.min(Math.max(cloudCoverage, 0), 100)
      : null;
    const cloudFactor = normalizedCloudCoverage === null
      ? 1
      : Math.max(0.2, 1 - normalizedCloudCoverage * 0.0065);
    return Math.max(0, Math.round(7 * daylightPhase * cloudFactor));
  };

  const computeWeatherScore = () => {
    const now = new Date();
    const hour = now.getHours() + now.getMinutes() / 60;
    if (hour >= morningStartHour && hour < morningEndHour) return morningScore;
    return defaultScore;
  };

  const refresh = async () => {
    const resolvedToolName = await resolveToolName();
    if (!resolvedToolName) {
      const errorText = 'Missing tool_name';
      setStatus('No tool', 'var(--theme-status-danger)');
      updateLiveContent({
        kind: 'weather',
        subtitle: subtitleEl.textContent || null,
        tool_name: null,
        temperature: null,
        temperature_unit: String(state.unit || '°F'),
        humidity: null,
        wind: null,
        rain: null,
        uv: null,
        status: 'No tool',
        error: errorText,
      });
      return;
    }

    setStatus('Refreshing', 'var(--theme-status-muted)');
    try {
      const [toolResult, forecastBundle] = await Promise.all([
        host.callTool(resolvedToolName, {}),
        resolveForecastBundle(),
      ]);
      const entries = parseLiveContextEntries(extractLiveContextText(toolResult)).filter((entry) => normalizeText(entry.domain) === 'sensor');
      const prefix = providerPrefix || 'OpenWeatherMap';
      const temperatureEntry = findEntry(entries, [
        temperatureName,
        `${prefix} Temperature`,
      ]);
      const humidityEntry = findEntry(entries, [
        humidityName,
        `${prefix} Humidity`,
      ]);
      const uvSensorEntry = findEntry(entries, [
        uvName,
        `${prefix} UV index`,
      ]);

      const temperature = Number(temperatureEntry?.state);
      tempEl.textContent = Number.isFinite(temperature) ? String(Math.round(temperature)) : '--';
      unitEl.textContent = String(temperatureEntry?.attributes?.unit_of_measurement || state.unit || '°F');

      const humidity = Number(humidityEntry?.state);
      humidityEl.textContent = Number.isFinite(humidity) ? `${Math.round(humidity)}%` : '--';

      const nwsEntry = firstForecastEntry(forecastBundle, 'nws');
      const uvEntry = firstForecastEntry(forecastBundle, 'uv', 'uv_index');
      const nwsSource = forecastBundle && typeof forecastBundle === 'object' && forecastBundle.nws && typeof forecastBundle.nws === 'object' ? forecastBundle.nws : null;
      const uvSource = forecastBundle && typeof forecastBundle === 'object' && forecastBundle.uv && typeof forecastBundle.uv === 'object' ? forecastBundle.uv : null;

      const windSpeed = Number(nwsEntry?.wind_speed);
      const windUnit = String(nwsSource?.wind_speed_unit || 'mph');
      windEl.textContent = Number.isFinite(windSpeed) ? `${Math.round(windSpeed)} ${windUnit}` : '--';

      const rainChance = Number(nwsEntry?.precipitation_probability);
      rainEl.textContent = Number.isFinite(rainChance) ? `${Math.round(rainChance)}%` : '--';

      const liveUvValue = Number(uvSensorEntry?.state);
      const forecastUvValue = Number(uvEntry?.uv_index);
      const cloudCoverage = Number.isFinite(Number(nwsEntry?.cloud_coverage))
        ? Number(nwsEntry?.cloud_coverage)
        : Number(uvSource?.forecast?.[0]?.cloud_coverage);
      const estimatedUvValue = estimateUvIndex(cloudCoverage);
      const uvValue = Number.isFinite(liveUvValue)
        ? liveUvValue
        : (Number.isFinite(forecastUvValue) ? forecastUvValue : estimatedUvValue);
      const uvEstimated = !Number.isFinite(liveUvValue) && !Number.isFinite(forecastUvValue);
      uvEl.textContent = Number.isFinite(uvValue)
        ? `${uvEstimated && uvValue > 0 ? '~' : ''}${Math.round(uvValue)}`
        : '--';

      subtitleEl.textContent = subtitle || prefix || 'Weather';
      setStatus('Live', 'var(--theme-status-live)');
      updateLiveContent({
        kind: 'weather',
        subtitle: subtitleEl.textContent || null,
        tool_name: resolvedToolName,
        temperature: Number.isFinite(temperature) ? Math.round(temperature) : null,
        temperature_unit: unitEl.textContent || null,
        humidity: Number.isFinite(humidity) ? Math.round(humidity) : null,
        wind: windEl.textContent || null,
        rain: rainEl.textContent || null,
        uv: Number.isFinite(uvValue) ? Math.round(uvValue) : null,
        uv_estimated: uvEstimated,
        score: computeWeatherScore(),
        status: 'Live',
      });
    } catch (error) {
      const errorText = String(error);
      setStatus('Unavailable', 'var(--theme-status-danger)');
      tempEl.textContent = '--';
      unitEl.textContent = String(state.unit || '°F');
      humidityEl.textContent = '--';
      windEl.textContent = '--';
      rainEl.textContent = '--';
      uvEl.textContent = '--';
      updateLiveContent({
        kind: 'weather',
        subtitle: subtitleEl.textContent || null,
        tool_name: resolvedToolName,
        temperature: null,
        temperature_unit: unitEl.textContent || null,
        humidity: null,
        wind: null,
        rain: null,
        uv: null,
        score: computeWeatherScore(),
        status: 'Unavailable',
        error: errorText,
      });
    }
  };

  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();
    },
  };
}
