import type { FeatureDependencies } from "../../../baseDeviceFeatures";
import { DeviceStateWriter } from "../../../deviceStateWriter";
import {
	parseQ10CarpetDpPayload,
	parseQ10RestrictedZoneDpPayload,
	parseQ10SuspectedPointsDpPayload,
	parseQ10VirtualWallDpPayload
} from "../../../../map/q10/Q10YxMapParser";
import type { Q10RuntimeStatePatch } from "../../../../map/q10/types";
import { normalizeRoborockRoomDisplayName } from "../../../../roomNameNormalizer";
import { VACUUM_CONSTANTS } from "../../vacuumConstants";

type Q10ShadowDataServiceHost = {
	applyCleanRecordList: (data: Record<string, unknown>) => Promise<void>;
	applyConsumables: (data: Record<string, unknown>) => Promise<void>;
	applyStatusSnapshot: (resultObj: Record<string, unknown>) => Promise<void>;
	cleanupFloorMetadata: (folder: string) => Promise<void>;
	processStatusProperty: (property: string, value: ioBroker.StateValue) => Promise<void>;
	requestTimerRefresh: () => Promise<void>;
};

export class Q10ShadowDataService {
	private q10SkipNextTimerRefreshFromDp93 = false;
	private q10AwaitingTimerListResult = false;
	private readonly stateWriter: DeviceStateWriter;

	constructor(
		private readonly deps: FeatureDependencies,
		private readonly duid: string,
		private readonly host: Q10ShadowDataServiceHost
	) {
		this.stateWriter = new DeviceStateWriter(deps, duid);
	}

	public skipNextTimerRefreshFromDp93(): void {
		this.q10SkipNextTimerRefreshFromDp93 = true;
	}

	public markTimerListRequestPending(): void {
		this.q10AwaitingTimerListResult = true;
	}

	private normalizeQ10BooleanNumberFlags(statusData: Record<string, unknown>): void {
		for (const key of ["map_save_switch", "recent_clean_record", "valley_point_charging"] as const) {
			if (typeof statusData[key] === "boolean") {
				statusData[key] = statusData[key] ? 1 : 0;
			}
		}
	}

	private decodeQ10ShadowBytes(value: unknown): Uint8Array | null {
		if (typeof value !== "string" || value.length === 0) return null;

		try {
			return new Uint8Array(Buffer.from(value, "base64"));
		} catch {
			return null;
		}
	}

	private q10WeekDataToWeekArray(weekData: number): number[] {
		const weeks: number[] = [];
		if (((weekData >> 6) & 1) === 1) {
			weeks.push(0);
		}
		for (let day = 1; day < 7; day++) {
			if (((weekData >> (day - 1)) & 1) === 1) {
				weeks.push(day);
			}
		}
		return weeks;
	}

	private formatQ10Time(value: number): string {
		return value.toString().padStart(2, "0");
	}

	private async resolveQ10FloorName(mapId: number): Promise<string> {
		const floorState = await this.deps.adapter.getStateAsync(`Devices.${this.duid}.floors.${mapId}.name`);
		return typeof floorState?.val === "string" && floorState.val.trim() ? floorState.val : `Map ${mapId}`;
	}

	private getDefaultRoomName(): string | undefined {
		return this.deps.adapter.translationManager?.get("default_room_name");
	}

	private normalizeQ10RoomIds(value: unknown): number[] {
		if (!Array.isArray(value)) return [];
		return value
			.map((entry) => Number(entry))
			.filter((entry) => Number.isInteger(entry) && entry > 0);
	}

	private async applyQ10CurrentCleanRoomIds(dp91: unknown): Promise<void> {
		let roomIds: number[] = [];
		if (dp91 && typeof dp91 === "object" && !Array.isArray(dp91)) {
			const payload = dp91 as Record<string, unknown>;
			roomIds = this.normalizeQ10RoomIds(payload.room_id_list);
		}

		await this.stateWriter.ensureAndSetValueState("deviceStatus.current_clean_room_ids", {
			name: "current_clean_room_ids",
			type: "string",
			role: "json"
		}, JSON.stringify(roomIds));
	}

	private async applyQ10ShadowConsumables(
		topLevelDps: Record<string, unknown>,
		commonDps: Record<string, unknown>
	): Promise<void> {
		const shadowConsumables = [
			{ value: topLevelDps["125"], stateKey: "main_brush_work_time", deviceName: "main_brush" },
			{ value: topLevelDps["126"], stateKey: "side_brush_work_time", deviceName: "side_brush" },
			{ value: topLevelDps["127"], stateKey: "filter_work_time", deviceName: "filter" },
			{ value: commonDps["67"], stateKey: "sensor_dirty_time", deviceName: "sensor" }
		] as const;

		const availableShadowConsumables = shadowConsumables.filter((entry) => entry.value !== undefined);
		if (!availableShadowConsumables.length) return;

		await this.stateWriter.ensureFolder("consumables");
		await this.stateWriter.ensureFolder("resetConsumables");

		for (const entry of availableShadowConsumables) {
			const remainingHours = this.normalizeQ10ShadowConsumableHours(entry.deviceName, entry.value);
			if (remainingHours === undefined) continue;

			const localizedName = this.getLocalizedConsumableName(entry.deviceName);
			await this.stateWriter.ensureAndSetValueState(`consumables.${entry.stateKey}`, {
				name: `${localizedName} remaining time`,
				type: "number",
				unit: "h"
			}, remainingHours);

			await this.stateWriter.ensureState(`resetConsumables.reset_${entry.deviceName}`, {
				name: `Reset ${localizedName}`,
				type: "boolean",
				role: "button",
				write: true,
				def: false
			}, { resetParam: entry.stateKey });
		}
	}

	private getLocalizedConsumableName(deviceName: string): string {
		const translationKey =
			VACUUM_CONSTANTS.consumableTranslationKeys[deviceName as keyof typeof VACUUM_CONSTANTS.consumableTranslationKeys];
		return translationKey
			? this.deps.adapter.translationManager.get(translationKey, deviceName)
			: deviceName;
	}

	private getConsumableLifeSpanHours(deviceName: string): number {
		switch (deviceName) {
			case "main_brush": return 300;
			case "side_brush": return 200;
			case "filter": return 150;
			case "sensor": return 30;
			default: return 0;
		}
	}

	private normalizeQ10ShadowConsumableHours(deviceName: string, value: unknown): number | undefined {
		const numericValue = Number(value);
		if (!Number.isFinite(numericValue)) return undefined;

		const maxHours = this.getConsumableLifeSpanHours(deviceName);
		if (numericValue <= 100) {
			// Q10 shadow snapshots seem to ship already-condensed remaining-life values.
			return Math.max(0, Math.round(numericValue));
		}

		if (maxHours > 0) {
			const remainingHours = Math.round((maxHours * 3600 - numericValue) / 3600);
			return Math.max(0, remainingHours);
		}

		return Math.max(0, Math.round(numericValue));
	}

	public async applyQ10StatusFromDpResult(dpResult: Record<string, unknown>): Promise<void> {
		const resultObj: Record<string, unknown> = { ...dpResult };
		if (resultObj.state !== undefined) resultObj.status = resultObj.state;
		if (resultObj.fan_power !== undefined) resultObj.wind = resultObj.fan_power;
		if (resultObj.water_box_mode !== undefined) resultObj.water = resultObj.water_box_mode;

		try {
			await this.host.applyStatusSnapshot(resultObj);
		} catch (e: unknown) {
			this.deps.adapter.rLog("System", this.duid, "Warn", "B01", undefined, `Q10 applyQ10StatusFromDpResult: ${this.deps.adapter.errorMessage(e)}`, "warn");
		}
	}

	public async applyQ10NetworkFromDp81(net81: Record<string, unknown>): Promise<void> {
		if (!net81 || typeof net81 !== "object") return;

		try {
			await this.stateWriter.ensureFolder("networkInfo");
			const keys: Array<{ key: string; stateKey: string }> = [
				{ key: "ipAdress", stateKey: "ipAdress" },
				{ key: "mac", stateKey: "mac" },
				{ key: "signal", stateKey: "rssi" },
				{ key: "wifiName", stateKey: "ssid" }
			];

			for (const { key, stateKey } of keys) {
				if (net81[key] === undefined) continue;
				await this.stateWriter.ensureAndSetValueState(`networkInfo.${stateKey}`, {
					name: stateKey,
					type: typeof net81[key] === "number" ? "number" : "string",
				}, net81[key] as ioBroker.StateValue);
			}
		} catch (e: unknown) {
			this.deps.adapter.rLog("System", this.duid, "Warn", "B01", undefined, `Q10 applyQ10NetworkFromDp81: ${this.deps.adapter.errorMessage(e)}`, "warn");
		}
	}

	public async applyQ10MapInfoFromDpResult(resultItem: Record<string, unknown>): Promise<void> {
		const mapInfoList = resultItem.map_info;
		if (!Array.isArray(mapInfoList) || mapInfoList.length === 0) return;

		try {
			const floorsFolder = "floors";
			await this.stateWriter.ensureFolder(floorsFolder);

			for (const key of ["max_multi_map", "max_bak_map", "multi_map_count"]) {
				if (resultItem[key] === undefined) continue;
				await this.stateWriter.ensureAndSetValueState(`${floorsFolder}.${key}`, {
					name: key,
					type: "number",
				}, Number(resultItem[key]));
			}

			for (const map of mapInfoList) {
				const m = map as Record<string, unknown>;
				const mapFlag = m.mapFlag ?? m.mapflag;
				if (mapFlag === undefined) continue;

				const mapId = typeof mapFlag === "number" ? mapFlag : Number(mapFlag);
				const name = (m.name as string) || `Map ${mapId}`;
				const folder = `floors.${mapId}`;

				await this.host.cleanupFloorMetadata(this.stateWriter.path(folder));
				await this.stateWriter.ensureFolder(folder, name);
				await this.stateWriter.ensureAndSetValueState(`${folder}.name`, { name: "Floor Name", type: "string" }, name);

				const addTime = m.add_time;
				if (typeof addTime === "number" && Number.isFinite(addTime)) {
					await this.stateWriter.ensureAndSetValueState(`${folder}.add_time`, {
						name: "Created At",
						type: "string",
					}, this.deps.adapter.formatRoborockDate(addTime));
				}

				const rooms = m.rooms;
				if (!Array.isArray(rooms)) continue;

				for (const room of rooms) {
					const r = room as Record<string, unknown>;
					const roomId = r.id;
					if (roomId === undefined) continue;

					const rid = typeof roomId === "number" ? roomId : Number(roomId);
					const rawRoomName =
						typeof r.iot_name === "string" && r.iot_name.trim()
							? r.iot_name
							: typeof r.name === "string"
								? r.name
								: "";
					const roomName = normalizeRoborockRoomDisplayName(rawRoomName, () => this.getDefaultRoomName());
					await this.stateWriter.ensureState(`${folder}.${rid}`, {
						name: roomName,
						type: "boolean",
						role: "value",
						def: false,
						read: true,
						write: true
					});
				}
			}
		} catch (e: unknown) {
			this.deps.adapter.rLog("System", this.duid, "Warn", "B01", undefined, `Q10 applyQ10MapInfoFromDpResult: ${this.deps.adapter.errorMessage(e)}`, "warn");
		}
	}

	public async applyQ10ConsumablesFromDpResult(dpResult: Record<string, unknown>): Promise<void> {
		try {
			await this.host.applyConsumables(dpResult);
		} catch (e: unknown) {
			this.deps.adapter.rLog("System", this.duid, "Warn", "B01", undefined, `Q10 applyQ10ConsumablesFromDpResult: ${this.deps.adapter.errorMessage(e)}`, "warn");
		}
	}

	public async applyQ10TimersFromDpResult(dpResult: unknown): Promise<void> {
		if (!Array.isArray(dpResult)) return;

		try {
			this.q10AwaitingTimerListResult = false;
			await this.stateWriter.ensureFolder("schedules");
			for (const timer of dpResult) {
				if (!Array.isArray(timer) || timer.length < 3) continue;

				const [id, enabledValue, segments] = timer;
				const cron = Array.isArray(segments) ? segments[0] : "";
				const folder = `schedules.${id}`;

				await this.stateWriter.ensureFolder(folder);
				await this.stateWriter.ensureAndSetState(`${folder}.enabled`, {
					name: "Enabled",
					type: "boolean",
					role: "switch",
					read: true,
					write: true
				}, enabledValue === "on");

				await this.stateWriter.ensureAndSetValueState(`${folder}.cron`, {
					name: "CRON",
					type: "string",
					role: "text"
				}, String(cron ?? ""));
			}
		} catch (e: unknown) {
			this.q10AwaitingTimerListResult = false;
			this.deps.adapter.rLog("System", this.duid, "Warn", "B01", undefined, `Q10 applyQ10TimersFromDpResult: ${this.deps.adapter.errorMessage(e)}`, "warn");
		}
	}

	public async applyQ10LocalTimerBlob(dpTimer: unknown): Promise<void> {
		const bytes = this.decodeQ10ShadowBytes(dpTimer);
		if (!bytes || bytes.length < 4) return;

		try {
			await this.stateWriter.ensureFolder("schedules");

			const timerCount = bytes[3] ?? 0;
			let offset = 4;

			for (let index = 0; index < timerCount; index++) {
				if (offset + 14 > bytes.length) break;

				const lock = bytes[offset] ?? 0;
				offset += 1;
				const autoAreaId = Buffer.from(bytes.slice(offset, offset + 4)).readUInt32BE(0);
				offset += 4;
				const effective = bytes[offset] ?? 0;
				offset += 1;
				const weekData = bytes[offset] ?? 0;
				offset += 1;
				const hour = bytes[offset] ?? 0;
				offset += 1;
				const minute = bytes[offset] ?? 0;
				offset += 1;
				const mapId = Buffer.from(bytes.slice(offset, offset + 4)).readUInt32BE(0);
				offset += 4;
				const roomCount = bytes[offset] ?? 0;
				offset += 1;

				const rooms: number[] = [];
				for (let roomIndex = 0; roomIndex < roomCount; roomIndex++) {
					if (offset >= bytes.length) break;
					rooms.push(bytes[offset] ?? 0);
					offset += 1;
				}

				if (offset + 5 > bytes.length) break;
				const cleanMode = bytes[offset] ?? 0;
				offset += 1;
				const fanPower = bytes[offset] ?? 0;
				offset += 1;
				const waterBoxMode = bytes[offset] ?? 0;
				offset += 1;
				const cleanCount = bytes[offset] ?? 0;
				offset += 1;
				const cleanLine = bytes[offset] ?? 0;
				offset += 1;

				const folder = `schedules.local_${(index + 1).toString().padStart(2, "0")}`;
				const timeText = `${this.formatQ10Time(hour)}:${this.formatQ10Time(minute)}`;
				const weeks = this.q10WeekDataToWeekArray(weekData);
				const mapName = mapId > 0 ? await this.resolveQ10FloorName(mapId) : "";

				await this.stateWriter.ensureFolder(folder, timeText);
				await this.stateWriter.ensureAndSetValueState(`${folder}.enabled`, { name: "Enabled", type: "boolean", role: "switch" }, effective === 1);
				await this.stateWriter.ensureAndSetValueState(`${folder}.locked`, { name: "Locked", type: "boolean" }, lock === 1);
				await this.stateWriter.ensureAndSetValueState(`${folder}.time`, { name: "Start Time", type: "string", role: "text" }, timeText);
				await this.stateWriter.ensureAndSetValueState(`${folder}.hour`, { name: "Hour", type: "number" }, hour);
				await this.stateWriter.ensureAndSetValueState(`${folder}.minute`, { name: "Minute", type: "number" }, minute);
				await this.stateWriter.ensureAndSetValueState(`${folder}.weeks`, { name: "Repeat Days", type: "string", role: "json" }, JSON.stringify(weeks));
				await this.stateWriter.ensureAndSetValueState(`${folder}.auto_area_id`, { name: "Auto Area ID", type: "number" }, autoAreaId);
				await this.stateWriter.ensureAndSetValueState(`${folder}.clean_mode`, { name: "Clean Mode", type: "number" }, cleanMode);
				await this.stateWriter.ensureAndSetValueState(`${folder}.fan_power`, { name: "Fan Power", type: "number" }, fanPower);
				await this.stateWriter.ensureAndSetValueState(`${folder}.water_box_mode`, { name: "Water Level", type: "number" }, waterBoxMode);
				await this.stateWriter.ensureAndSetValueState(`${folder}.clean_count`, { name: "Clean Count", type: "number" }, cleanCount);
				await this.stateWriter.ensureAndSetValueState(`${folder}.clean_line`, { name: "Clean Line", type: "number" }, cleanLine);
				await this.stateWriter.ensureAndSetValueState(`${folder}.room_count`, { name: "Room Count", type: "number" }, roomCount);
				await this.stateWriter.ensureAndSetValueState(`${folder}.rooms`, { name: "Rooms", type: "string", role: "json" }, JSON.stringify(rooms));
				await this.stateWriter.ensureAndSetValueState(`${folder}.map_id`, { name: "Map ID", type: "number" }, mapId);
				await this.stateWriter.ensureAndSetValueState(`${folder}.map_name`, { name: "Map Name", type: "string", role: "text" }, mapName);
			}
		} catch (e: unknown) {
			this.deps.adapter.rLog("System", this.duid, "Warn", "B01", undefined, `Q10 applyQ10LocalTimerBlob: ${this.deps.adapter.errorMessage(e)}`, "warn");
		}
	}

	public async applyQ10NotDisturbData(dpValue: unknown): Promise<void> {
		const bytes = this.decodeQ10ShadowBytes(dpValue);
		if (!bytes || bytes.length < 6) return;

		try {
			await this.host.processStatusProperty("not_disturb_start_hour", bytes[1] ?? 0);
			await this.host.processStatusProperty("not_disturb_start_minute", bytes[2] ?? 0);
			await this.host.processStatusProperty("not_disturb_end_hour", bytes[3] ?? 0);
			await this.host.processStatusProperty("not_disturb_end_minute", bytes[4] ?? 0);
			await this.host.processStatusProperty(
				"not_disturb_time",
				`${this.formatQ10Time(bytes[1] ?? 0)}:${this.formatQ10Time(bytes[2] ?? 0)}-${this.formatQ10Time(bytes[3] ?? 0)}:${this.formatQ10Time(bytes[4] ?? 0)}`
			);
		} catch (e: unknown) {
			this.deps.adapter.rLog("System", this.duid, "Warn", "B01", undefined, `Q10 applyQ10NotDisturbData: ${this.deps.adapter.errorMessage(e)}`, "warn");
		}
	}

	public async applyQ10ValleyPointChargingData(dpValue: unknown): Promise<void> {
		const bytes = this.decodeQ10ShadowBytes(dpValue);
		if (!bytes || bytes.length < 6) return;

		try {
			await this.host.processStatusProperty("valley_point_charging_start_hour", bytes[1] ?? 0);
			await this.host.processStatusProperty("valley_point_charging_start_minute", bytes[2] ?? 0);
			await this.host.processStatusProperty("valley_point_charging_end_hour", bytes[3] ?? 0);
			await this.host.processStatusProperty("valley_point_charging_end_minute", bytes[4] ?? 0);
			await this.host.processStatusProperty(
				"valley_point_charging_time",
				`${this.formatQ10Time(bytes[1] ?? 0)}:${this.formatQ10Time(bytes[2] ?? 0)}-${this.formatQ10Time(bytes[3] ?? 0)}:${this.formatQ10Time(bytes[4] ?? 0)}`
			);
		} catch (e: unknown) {
			this.deps.adapter.rLog("System", this.duid, "Warn", "B01", undefined, `Q10 applyQ10ValleyPointChargingData: ${this.deps.adapter.errorMessage(e)}`, "warn");
		}
	}

	public async applyQ10MultiMapListFromDp61(dp61: Record<string, unknown>): Promise<void> {
		const mapList = Array.isArray(dp61.data) ? dp61.data : [];
		if (mapList.length === 0) return;

		try {
			await this.stateWriter.ensureFolder("floors");
			for (const entry of mapList) {
				if (!entry || typeof entry !== "object") continue;
				const map = entry as Record<string, unknown>;
				const mapId = map.id;
				if (mapId === undefined || mapId === null || mapId === "") continue;

				const mapIdText = String(mapId);
				const name = typeof map.name === "string" && map.name.trim() ? map.name : `Map ${mapIdText}`;
				const folder = `floors.${mapIdText}`;

				await this.host.cleanupFloorMetadata(this.stateWriter.path(folder));
				await this.stateWriter.ensureFolder(folder, name);
				await this.stateWriter.ensureAndSetValueState(`${folder}.name`, { name: "Floor Name", type: "string" }, name);

				const timestamp = map.timestamp;
				if (typeof timestamp === "number" && Number.isFinite(timestamp)) {
					await this.stateWriter.ensureAndSetValueState(`${folder}.add_time`, {
						name: "Created At",
						type: "string",
					}, this.deps.adapter.formatRoborockDate(timestamp));
				}
			}
		} catch (e: unknown) {
			this.deps.adapter.rLog("System", this.duid, "Warn", "B01", undefined, `Q10 applyQ10MultiMapListFromDp61: ${this.deps.adapter.errorMessage(e)}`, "warn");
		}
	}

	public async applyQ10ShadowDpPayload(dps: Record<string, unknown>): Promise<void> {
		if (!dps || typeof dps !== "object") return;

		const statusData: Record<string, unknown> = {};
		const liveMapPatch: Q10RuntimeStatePatch = {};
		const topLevelMap: Record<string, string> = {
			"121": "status",
			"122": "battery",
			"123": "fan_power",
			"124": "water_box_mode",
			"125": "main_brush_life",
			"126": "side_brush_life",
			"127": "filter_life",
			"136": "clean_times",
			"137": "clean_mode",
			"138": "clean_task_type",
			"139": "back_type",
			"141": "cleaning_progress",
			"142": "fleeing_goods"
		};

		for (const [dpId, field] of Object.entries(topLevelMap)) {
			if (dps[dpId] !== undefined) {
				statusData[field] = dps[dpId];
			}
		}

		let net81: Record<string, unknown> | undefined;
		const common = dps["101"];
		if (common && typeof common === "object" && !Array.isArray(common)) {
			const commonMap: Record<string, string> = {
				"6": "clean_time",
				"7": "clean_area",
				"25": "quiet_is_open",
				"26": "volume",
				"36": "voice_language",
				"37": "dust_switch",
				"40": "mop_state",
				"45": "auto_boost",
				"47": "child_lock",
				"50": "dust_setting",
				"51": "map_save_switch",
				"53": "recent_clean_record",
				"29": "total_clean_area",
				"30": "total_clean_count",
				"31": "total_clean_time",
				"60": "multi_map_switch",
				"76": "carpet_clean_type",
				"78": "clean_path_preference",
				"83": "robot_type",
				"86": "line_laser_obstacle_avoidance",
				"87": "cleaning_progress",
				"88": "ground_clean",
				"90": "fault",
				"93": "timer_type",
				"96": "add_clean_state",
				"104": "breakpoint_clean",
				"105": "valley_point_charging",
				"108": "voice_version",
				"109": "robot_country_code",
				"207": "user_plan"
			};

			const commonDps = common as Record<string, unknown>;
			for (const [dpId, field] of Object.entries(commonMap)) {
				if (commonDps[dpId] !== undefined) {
					statusData[field] = commonDps[dpId];
				}
			}

			if (commonDps["79"] && typeof commonDps["79"] === "object" && !Array.isArray(commonDps["79"])) {
				const timeZone = commonDps["79"] as Record<string, unknown>;
				if (timeZone.timeZoneSec !== undefined) statusData.time_zone = timeZone.timeZoneSec;
				if (timeZone.timeZoneCity !== undefined) statusData.time_zone_info = timeZone.timeZoneCity;
			}

			if (commonDps["92"] && typeof commonDps["92"] === "object" && !Array.isArray(commonDps["92"])) {
				const disturb = commonDps["92"] as Record<string, unknown>;
				if (disturb.disturb_light !== undefined) statusData.disturb_light = disturb.disturb_light;
				if (disturb.disturb_voice !== undefined) statusData.disturb_voice = disturb.disturb_voice;
				if (disturb.disturb_resume_clean !== undefined) statusData.disturb_resume_clean = disturb.disturb_resume_clean;
				if (disturb.disturb_dust_enable !== undefined) statusData.disturb_dust_enable = disturb.disturb_dust_enable;
			}

			const multiMapList = commonDps["61"];
			if (multiMapList && typeof multiMapList === "object" && !Array.isArray(multiMapList)) {
				await this.applyQ10MultiMapListFromDp61(multiMapList as Record<string, unknown>);
			}

			const cleanRecords = commonDps["52"];
			if (cleanRecords && typeof cleanRecords === "object" && !Array.isArray(cleanRecords)) {
				await this.host.applyCleanRecordList(cleanRecords as Record<string, unknown>);
			}

			if (commonDps["32"] !== undefined) {
				await this.applyQ10LocalTimerBlob(commonDps["32"]);
			}

			if (commonDps["33"] !== undefined) {
				await this.applyQ10NotDisturbData(commonDps["33"]);
			}

			if (commonDps["106"] !== undefined) {
				await this.applyQ10ValleyPointChargingData(commonDps["106"]);
			}

			if (commonDps["55"] !== undefined) {
				const bytes = this.decodeQ10ShadowBytes(commonDps["55"]);
				if (bytes) {
					const restricted = parseQ10RestrictedZoneDpPayload(Buffer.from(bytes));
					liveMapPatch.forbidAreas = restricted.forbidAreas;
					liveMapPatch.mopAreas = restricted.mopAreas;
					liveMapPatch.thresholdAreas = restricted.thresholdAreas;
				}
			}

			if (commonDps["57"] !== undefined) {
				const bytes = this.decodeQ10ShadowBytes(commonDps["57"]);
				if (bytes) {
					liveMapPatch.virtualWalls = parseQ10VirtualWallDpPayload(Buffer.from(bytes));
				}
			}

			if (commonDps["65"] && typeof commonDps["65"] === "object" && !Array.isArray(commonDps["65"])) {
				const dp65 = commonDps["65"] as Record<string, unknown>;
				if (Array.isArray(dp65.data)) {
					liveMapPatch.carpetAreas = parseQ10CarpetDpPayload(dp65.data);
				}
			}

			if (commonDps["98"] !== undefined) {
				liveMapPatch.suspectedPoints = [
					...(liveMapPatch.suspectedPoints ?? []),
					...parseQ10SuspectedPointsDpPayload(commonDps["98"], "easycard")
				];
			}
			if (commonDps["100"] !== undefined) {
				liveMapPatch.suspectedPoints = [
					...(liveMapPatch.suspectedPoints ?? []),
					...parseQ10SuspectedPointsDpPayload(commonDps["100"], "threshold")
				];
			}
			if (commonDps["103"] !== undefined) {
				liveMapPatch.suspectedPoints = [
					...(liveMapPatch.suspectedPoints ?? []),
					...parseQ10SuspectedPointsDpPayload(commonDps["103"], "cliff")
				];
			}

			if (commonDps["91"] !== undefined) {
				await this.applyQ10CurrentCleanRoomIds(commonDps["91"]);
			}

			if (commonDps["93"] !== undefined) {
				const currentTimerTypeState = await this.deps.adapter.getStateAsync(`Devices.${this.duid}.deviceStatus.timer_type`);
				const nextTimerType = Number(commonDps["93"]);
				const currentTimerType = currentTimerTypeState && currentTimerTypeState.val !== null && currentTimerTypeState.val !== undefined
					? Number(currentTimerTypeState.val)
					: Number.NaN;
				if (this.q10SkipNextTimerRefreshFromDp93) {
					this.q10SkipNextTimerRefreshFromDp93 = false;
				} else if (this.q10AwaitingTimerListResult) {
					// A list refresh is already in flight, so a repeated DP 93 echo must not trigger another 69 request.
				} else if (!Number.isFinite(currentTimerType) || currentTimerType !== nextTimerType) {
					await this.host.requestTimerRefresh();
				}
			}

			const candidateNet81 = commonDps["81"];
			if (candidateNet81 && typeof candidateNet81 === "object" && !Array.isArray(candidateNet81)) {
				net81 = candidateNet81 as Record<string, unknown>;
			}

			await this.applyQ10ShadowConsumables(dps, commonDps);
		}

		if (Object.keys(statusData).length > 0) {
			if (statusData.fan_power !== undefined) statusData.wind = statusData.fan_power;
			if (statusData.water_box_mode !== undefined) statusData.water = statusData.water_box_mode;
			this.normalizeQ10BooleanNumberFlags(statusData);
			await this.host.applyStatusSnapshot(statusData);
		}

		if (net81) {
			await this.applyQ10NetworkFromDp81(net81);
		}

		if (
			(liveMapPatch.virtualWalls !== undefined ||
				liveMapPatch.forbidAreas !== undefined ||
				liveMapPatch.mopAreas !== undefined ||
				liveMapPatch.thresholdAreas !== undefined ||
				liveMapPatch.carpetAreas !== undefined ||
				liveMapPatch.suspectedPoints !== undefined) &&
			typeof (this.deps.adapter as any).mapManager?.applyQ10LiveStatePatch === "function"
		) {
			await (this.deps.adapter as any).mapManager.applyQ10LiveStatePatch(this.duid, liveMapPatch);
		}
	}
}
