const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const os = require('os');
const path = require('path');
const sharp = require('sharp');
require('../src/common');
const library = require('../src/web/lib/media/weather-icon-library');
const weatherIcons = require('../src/web/public/js/shared/weather-icons');
const { isWeatherIconSetUsed } = require('../src/web/routes/settings/weather-icons');
const vm = require('node:vm');
const placeholderContext = { window: {} };
vm.runInNewContext(fs.readFileSync(path.join(__dirname, '../src/web/public/js/shared/placeholder-utils.js'), 'utf8'), placeholderContext);
const placeholders = placeholderContext.window.placeholderUtils;
test('weather icon picker warns about each missing condition', function () {
const source = fs.readFileSync(path.join(__dirname, '../src/web/public/js/settings/weather-icons.js'), 'utf8');
assert.match(source, /window\.showToast\('Add images for: ' \+ labels\.join\(', '\) \+ '\.', 'warning'\)/);
assert.match(source, /replace\(\/\^Upload\\s\+\|\\s\+icon\$\/g, ''\)/);
});
test('weather editor and player render day or night variants from one selected set', function () {
const sets = [{ id: 'abc', name: 'Colour', icons: { clear: '/media/weather-icons/abc/clear-123abc.png' }, nightIcons: { clear: '/media/weather-icons/abc/night-clear-456def.png' } }];
const location = { id: 1, responseJson: { current: { weather_code: 0, is_day: 1 } } };
let editor;
const editorContext = { window: { pulseWeatherIconSets: sets, pulseWeatherIcons: weatherIcons, placeholderUtils: placeholders,
pulseRegionTypes: { register: function (_type, module) { editor = module; } } }, document: { addEventListener: function () {} } };
vm.runInNewContext(fs.readFileSync(path.join(__dirname, '../src/web/public/js/regions/type/weather.js'), 'utf8'), editorContext);
const region = { id: 1, region_key: 'weather', label: 'Forecast', baseStyle: '' };
const content = { weather_location_id: 1, weather_icon_set_id: 'abc', value: '{{current.icon(48,24)}}' };
const card = editor.renderEditorCard({ region: region, current: content, weatherLocations: [location] });
assert.match(card, /name="region_weather_icon_set_id_1"/);
assert.match(card, /value="abc" selected/);
assert.match(card, /row g-3 align-items-end">
Colour<\/option>/);
assert.doesNotMatch(disabledCard, /value="abc" selected disabled/);
sets[0].enabled = true;
const preview = editor.renderPreview(region, content, { weatherLocations: [location] });
assert.match(preview, /clear-123abc.png/);
assert.match(preview, /width:48px;height:24px/);
const topPreview = editor.renderPreview(region, Object.assign({}, content, { value: '{{current.icon(48,96,top)}}' }), { weatherLocations: [location] });
assert.match(topPreview, /vertical-align:top/);
let player;
const playerContext = { window: { pulseWeatherIcons: weatherIcons, placeholderUtils: placeholders,
pulsePlayerRegionTypes: { register: function (_type, module) { player = module; } } },
initialData: { weatherLocations: [location], weatherIconSets: sets }, escapeHtml: String, renderEditorJsContent: String };
vm.runInNewContext(fs.readFileSync(path.join(__dirname, '../src/player/regions/weather.js'), 'utf8'), playerContext);
assert.match(player.renderRegion(region, content), /clear-123abc.png/);
assert.match(player.renderRegion(region, Object.assign({}, content, { value: '{{current.icon(48,96,bottom)}}' })), /vertical-align:bottom/);
location.responseJson.current.is_day = 0;
assert.match(player.renderRegion(region, content), /night-clear-456def.png/);
location.responseJson.current.is_day = 1;
assert.match(player.renderRegion(region, Object.assign({}, content, { weather_icon_set_id: '' })), /bi-sun/);
location.responseJson.current.weather_code = 61;
assert.match(player.renderRegion(region, content), /bi-cloud-rain/);
});
test('weather icons map exact WMO codes and fall back for missing or unsafe images', function () {
assert.equal(weatherIcons.conditionForCode(3), 'overcast');
assert.equal(weatherIcons.conditionForCode(85), 'snow');
assert.equal(weatherIcons.conditionForCode(null), '');
assert.equal(weatherIcons.conditionForCode(4), '');
const sets = [{ id: 'abc', icons: { clear: '/media/weather-icons/abc/clear-123abc.png', rain: 'javascript:alert(1)' } }];
assert.equal(weatherIcons.imageForCode(sets, 'abc', 0), sets[0].icons.clear);
assert.equal(weatherIcons.imageForCode(sets, 'abc', 61), '');
assert.equal(weatherIcons.imageForCode(sets, 'abc', 45), '');
sets[0].enabled = false;
assert.equal(weatherIcons.imageForCode(sets, 'abc', 0), sets[0].icons.clear);
assert.match(weatherIcons.renderImage(sets[0].icons.clear, 48, 24), /width:48px;height:24px/);
assert.match(weatherIcons.renderImage(sets[0].icons.clear, 48, 24), /display:inline-flex;vertical-align:middle;align-items:center;justify-content:center/);
assert.match(weatherIcons.renderImage(sets[0].icons.clear, 48, 24), /vertical-align:middle.*line-height:0/);
assert.match(weatherIcons.renderImage(sets[0].icons.clear, 48, 96, 'bottom'), /vertical-align:bottom/);
assert.match(weatherIcons.renderImage(sets[0].icons.clear, 48, 24), /object-fit:contain/);
});
test('weather icon edit controls use the standard colour and save before cancel', function () {
const html = require('../src/web/view').renderView('settings/weather-icons/list', {
sets: [{ id: 'example', name: 'Example', enabled: true, conditions: [] }],
currentUser: { permissionKeys: ['weather-icons.read', 'weather-icons.update'] }
});
assert.match(html, /class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#edit-set-example">Edit<\/button>/);
assert.match(html, /