import { SimpleLocalClient, SimpleLocalMapper, type IServiceCallRequest, type IServiceCallResult, type ISimpleLocalEntitySnapshot, type ISimpleLocalSnapshot } from '../../core/index.js';
import { MoehlenhoffAlpha2Mapper } from './moehlenhoff_alpha2.mapper.js';
import type { IMoehlenhoffAlpha2Config, IMoehlenhoffAlpha2HeatArea, IMoehlenhoffAlpha2HeatControl, IMoehlenhoffAlpha2IoDevice, IMoehlenhoffAlpha2RawApiData } from './moehlenhoff_alpha2.types.js';
import { moehlenhoffAlpha2DefaultPort, moehlenhoffAlpha2DefaultTimeoutMs, moehlenhoffAlpha2Profile } from './moehlenhoff_alpha2.types.js';

interface IMoehlenhoffAlpha2Endpoint {
  protocol: 'http' | 'https';
  host: string;
  port?: number;
}

export class MoehlenhoffAlpha2Client extends SimpleLocalClient<IMoehlenhoffAlpha2Config> {
  private cachedSnapshot?: ISimpleLocalSnapshot;
  private latestRawData?: IMoehlenhoffAlpha2RawApiData;

  constructor(private readonly configArg: IMoehlenhoffAlpha2Config) {
    super(moehlenhoffAlpha2Profile, configArg);
  }

  public async getSnapshot(forceRefreshArg = false): Promise<ISimpleLocalSnapshot> {
    if (!forceRefreshArg && this.cachedSnapshot) {
      return SimpleLocalMapper.clone(this.cachedSnapshot);
    }

    if (this.hasLiveHttpConfig()) {
      try {
        const rawData = await this.fetchRawData();
        this.latestRawData = rawData;
        this.cachedSnapshot = MoehlenhoffAlpha2Mapper.toSnapshot({ config: this.configArg, rawData, online: true, source: 'http' });
      } catch (errorArg) {
        this.cachedSnapshot = MoehlenhoffAlpha2Mapper.toSnapshot({ config: this.configArg, online: false, source: 'runtime', error: errorMessage(errorArg) });
      }
      return SimpleLocalMapper.clone(this.cachedSnapshot);
    }

    return super.getSnapshot(forceRefreshArg);
  }

  public async refresh(): Promise<IServiceCallResult> {
    this.cachedSnapshot = undefined;
    const snapshot = await this.getSnapshot(true);
    const success = snapshot.online && !snapshot.error;
    return { success, error: success ? undefined : snapshot.error, data: snapshot };
  }

  public async execute(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    if (this.configArg.client?.execute || this.configArg.commandExecutor) {
      return super.execute(requestArg);
    }
    if (!this.hasLiveHttpConfig()) {
      return super.execute(requestArg);
    }

    try {
      const rawData = this.latestRawData || await this.fetchRawData();
      const command = this.commandForRequest(requestArg, rawData);
      const response = await this.sendCommand(command.deviceId, command.xml);
      this.cachedSnapshot = undefined;
      this.latestRawData = undefined;
      return { success: true, data: { command, response } };
    } catch (errorArg) {
      return { success: false, error: errorMessage(errorArg) };
    }
  }

  private async fetchRawData(): Promise<IMoehlenhoffAlpha2RawApiData> {
    const endpoint = this.endpoint();
    if (!endpoint) {
      throw new Error('Mohlenhoff Alpha 2 local HTTP requires config.host or config.url.');
    }
    const xml = await this.requestText('/data/static.xml', 'GET');
    const parsed = parseStaticXml(xml);
    const deviceId = this.configArg.uniqueId || this.configArg.deviceId || parsed.base?.id || endpoint.host;
    const rawData: IMoehlenhoffAlpha2RawApiData = {
      ...parsed,
      device: {
        id: deviceId,
        name: this.configArg.name || parsed.base?.name || moehlenhoffAlpha2Profile.defaultName,
        manufacturer: 'Mohlenhoff',
        model: 'Alpha 2',
        host: endpoint.host,
        port: endpoint.port || moehlenhoffAlpha2DefaultPort,
        protocol: endpoint.protocol,
        configurationUrl: `${endpoint.protocol}://${endpoint.host}${endpoint.port && endpoint.port !== moehlenhoffAlpha2DefaultPort ? `:${endpoint.port}` : ''}`,
        attributes: cleanAttributes({ baseId: parsed.base?.id, cooling: parsed.base?.cooling }),
      },
      entities: this.entitiesFromRaw(deviceId, parsed),
      fetchedAt: new Date().toISOString(),
    };
    return rawData;
  }

  private entitiesFromRaw(deviceIdArg: string, rawDataArg: IMoehlenhoffAlpha2RawApiData): ISimpleLocalEntitySnapshot[] {
    const heatAreas = rawDataArg.heatAreas || [];
    const heatAreaIds = new Set(heatAreas.map((heatAreaArg) => heatAreaArg.ID));
    const entities: ISimpleLocalEntitySnapshot[] = heatAreas.map((heatAreaArg) => ({
      id: `heat_area_${heatAreaArg.NR}`,
      uniqueId: heatAreaArg.ID,
      name: stringValue(heatAreaArg.HEATAREA_NAME) || `Heat Area ${heatAreaArg.NR}`,
      platform: 'climate',
      state: numberValue(heatAreaArg.T_TARGET) ?? null,
      writable: true,
      attributes: cleanAttributes({
        heatAreaId: heatAreaArg.ID,
        heatAreaNumber: heatAreaArg.NR,
        currentTemperature: numberValue(heatAreaArg.T_ACTUAL),
        targetTemperature: numberValue(heatAreaArg.T_TARGET),
        minTemperature: numberValue(heatAreaArg.T_TARGET_MIN),
        maxTemperature: numberValue(heatAreaArg.T_TARGET_MAX),
        hvacMode: rawDataArg.base?.cooling ? 'cool' : 'heat',
        hvacAction: heatAreaArg._HEATCTRL_STATE ? rawDataArg.base?.cooling ? 'cooling' : 'heating' : 'idle',
        presetMode: presetMode(heatAreaArg.HEATAREA_MODE),
      }),
    }));

    for (const heatControl of rawDataArg.heatControls || []) {
      if (!heatControl.INUSE || !heatControl._HEATAREA_ID || !heatAreaIds.has(heatControl._HEATAREA_ID) || heatControl.ACTOR_PERCENT === undefined) {
        continue;
      }
      const heatArea = heatAreas.find((heatAreaArg) => heatAreaArg.ID === heatControl._HEATAREA_ID);
      entities.push({
        id: `heat_control_${heatControl.NR}_valve_opening`,
        uniqueId: `${heatControl.ID}:valve_opening`,
        name: `${stringValue(heatArea?.HEATAREA_NAME) || `Heat Area ${heatControl.HEATAREA_NR}`} Heat Control ${heatControl.NR} Valve Opening`,
        platform: 'sensor',
        state: numberValue(heatControl.ACTOR_PERCENT) ?? null,
        unit: '%',
        writable: false,
        attributes: cleanAttributes({ heatControlId: heatControl.ID, heatAreaId: heatControl._HEATAREA_ID }),
      });
    }

    for (const ioDevice of rawDataArg.ioDevices || []) {
      if (!ioDevice._HEATAREA_ID || !heatAreaIds.has(ioDevice._HEATAREA_ID)) {
        continue;
      }
      const heatArea = heatAreas.find((heatAreaArg) => heatAreaArg.ID === ioDevice._HEATAREA_ID);
      entities.push({
        id: `io_device_${ioDevice.NR}_battery`,
        uniqueId: `${ioDevice.ID}:battery`,
        name: `${stringValue(heatArea?.HEATAREA_NAME) || `Heat Area ${ioDevice.HEATAREA_NR}`} IO Device ${ioDevice.NR} Battery`,
        platform: 'binary_sensor',
        state: (numberValue(ioDevice.BATTERY) ?? 2) < 2,
        deviceClass: 'battery',
        writable: false,
        attributes: cleanAttributes({ ioDeviceId: ioDevice.ID, heatAreaId: ioDevice._HEATAREA_ID, battery: ioDevice.BATTERY }),
      });
    }

    entities.push({
      id: 'sync_time',
      uniqueId: `${deviceIdArg}:sync_time`,
      name: 'Sync Time',
      platform: 'button',
      state: null,
      writable: true,
      attributes: { entityCategory: 'diagnostic' },
    });

    return entities;
  }

  private commandForRequest(requestArg: IServiceCallRequest, rawDataArg: IMoehlenhoffAlpha2RawApiData): { deviceId: string; xml: string } {
    const baseId = rawDataArg.base?.id;
    if (!baseId) {
      throw new Error('Mohlenhoff Alpha 2 command requires base ID from /data/static.xml.');
    }

    if (requestArg.service === 'set_hvac_mode') {
      const mode = stringValue(requestArg.data?.hvac_mode ?? requestArg.data?.hvacMode ?? requestArg.data?.mode)?.toLowerCase();
      if (mode !== 'cool' && mode !== 'heat') {
        throw new Error('Mohlenhoff Alpha 2 set_hvac_mode requires data.hvac_mode heat or cool.');
      }
      return { deviceId: baseId, xml: `<COOLING>${mode === 'cool' ? 1 : 0}</COOLING>` };
    }

    if (requestArg.service === 'set_temperature') {
      const targetTemperature = numberValue(requestArg.data?.temperature ?? requestArg.data?.targetTemperature);
      if (targetTemperature === undefined) {
        throw new Error('Mohlenhoff Alpha 2 set_temperature requires data.temperature.');
      }
      const heatArea = this.heatAreaForRequest(requestArg, rawDataArg);
      const updates: Record<string, unknown> = { T_TARGET: targetTemperature };
      const heatAreaMode = numberValue(heatArea.HEATAREA_MODE);
      if (heatAreaMode === 1) {
        updates[rawDataArg.base?.cooling ? 'T_COOL_DAY' : 'T_HEAT_DAY'] = targetTemperature;
      } else if (heatAreaMode === 2) {
        updates[rawDataArg.base?.cooling ? 'T_COOL_NIGHT' : 'T_HEAT_NIGHT'] = targetTemperature;
      }
      return { deviceId: deviceIdFromHeatArea(heatArea, baseId), xml: heatAreaXml(heatArea, updates) };
    }

    if (requestArg.service === 'press') {
      return { deviceId: baseId, xml: `<DATETIME>${datetimeValue(requestArg.data?.datetime ?? requestArg.data?.value)}</DATETIME>` };
    }

    throw new Error(`Unsupported Mohlenhoff Alpha 2 service: ${requestArg.service}`);
  }

  private heatAreaForRequest(requestArg: IServiceCallRequest, rawDataArg: IMoehlenhoffAlpha2RawApiData): IMoehlenhoffAlpha2HeatArea {
    const heatAreas = rawDataArg.heatAreas || [];
    const explicit = stringValue(requestArg.data?.heatAreaId ?? requestArg.data?.heat_area_id ?? requestArg.data?.id);
    const target = `${requestArg.target.entityId || ''} ${requestArg.target.deviceId || ''}`;
    const heatArea = explicit
      ? heatAreas.find((heatAreaArg) => heatAreaArg.ID === explicit || String(heatAreaArg.NR) === explicit)
      : heatAreas.find((heatAreaArg) => target.includes(heatAreaArg.ID) || target.includes(`heat_area_${heatAreaArg.NR}`));
    if (heatArea) {
      return heatArea;
    }
    if (heatAreas.length === 1) {
      return heatAreas[0];
    }
    throw new Error('Mohlenhoff Alpha 2 set_temperature requires data.heatAreaId when multiple heat areas exist.');
  }

  private async sendCommand(deviceIdArg: string, commandArg: string): Promise<string> {
    const xml = `<?xml version="1.0" encoding="UTF-8"?>\n<Devices><Device><ID>${escapeXml(deviceIdArg)}</ID>${commandArg}</Device></Devices>`;
    return this.requestText('/data/changes.xml', 'POST', xml);
  }

  private async requestText(pathArg: '/data/static.xml' | '/data/changes.xml', methodArg: 'GET' | 'POST', bodyArg?: string): Promise<string> {
    const endpoint = this.endpoint();
    if (!endpoint) {
      throw new Error('Mohlenhoff Alpha 2 local HTTP requires config.host or config.url.');
    }
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), this.configArg.timeoutMs || moehlenhoffAlpha2DefaultTimeoutMs);
    try {
      const response = await globalThis.fetch(this.urlFor(endpoint, pathArg), {
        method: methodArg,
        headers: cleanAttributes({
          accept: methodArg === 'GET' ? 'application/xml, text/xml, text/plain;q=0.9, */*;q=0.8' : 'text/plain, */*;q=0.8',
          'content-type': bodyArg ? 'application/xml; charset=utf-8' : undefined,
        }) as Record<string, string>,
        body: bodyArg,
        signal: controller.signal,
      });
      const text = await response.text();
      if (!response.ok) {
        throw new Error(`Mohlenhoff Alpha 2 ${pathArg} request failed with ${response.status}: ${text.slice(0, 160)}`);
      }
      return text;
    } finally {
      clearTimeout(timer);
    }
  }

  private hasLiveHttpConfig(): boolean {
    return Boolean(this.endpoint());
  }

  private endpoint(): IMoehlenhoffAlpha2Endpoint | undefined {
    if (this.configArg.url) {
      try {
        const url = new URL(this.configArg.url.includes('://') ? this.configArg.url : `http://${this.configArg.url}`);
        if (url.protocol !== 'http:' && url.protocol !== 'https:') {
          return undefined;
        }
        return {
          protocol: url.protocol === 'https:' ? 'https' : 'http',
          host: url.hostname,
          port: url.port ? Number(url.port) : this.configArg.port || moehlenhoffAlpha2DefaultPort,
        };
      } catch {
        return undefined;
      }
    }
    if (!this.configArg.host) {
      return undefined;
    }
    return {
      protocol: this.configArg.useTls ? 'https' : 'http',
      host: this.configArg.host,
      port: this.configArg.port || moehlenhoffAlpha2DefaultPort,
    };
  }

  private urlFor(endpointArg: IMoehlenhoffAlpha2Endpoint, pathArg: string): string {
    const port = endpointArg.port && !((endpointArg.protocol === 'https' && endpointArg.port === 443) || (endpointArg.protocol === 'http' && endpointArg.port === 80)) ? `:${endpointArg.port}` : '';
    return `${endpointArg.protocol}://${endpointArg.host}${port}${pathArg}`;
  }
}

const parseStaticXml = (xmlArg: string): IMoehlenhoffAlpha2RawApiData => {
  const deviceBody = tagBody(xmlArg, 'Device') || xmlArg;
  const baseId = tagText(deviceBody, 'ID') || 'alpha2';
  const heatControls = blockRecords(deviceBody, 'HEATCTRL').map((recordArg) => convertHeatControl(baseId, recordArg));
  const heatAreas = blockRecords(deviceBody, 'HEATAREA').map((recordArg) => convertHeatArea(baseId, recordArg, heatControls));
  const ioDevices = blockRecords(deviceBody, 'IODEVICE').map((recordArg) => convertIoDevice(baseId, recordArg));
  return {
    base: {
      id: baseId,
      name: tagText(deviceBody, 'NAME') || baseId,
      cooling: boolValue(tagText(deviceBody, 'COOLING')),
    },
    heatAreas,
    heatControls,
    ioDevices,
  };
};

const convertHeatArea = (baseIdArg: string, recordArg: Record<string, string>, heatControlsArg: IMoehlenhoffAlpha2HeatControl[]): IMoehlenhoffAlpha2HeatArea => {
  const nr = numberValue(recordArg.nr) || 0;
  const heatArea: IMoehlenhoffAlpha2HeatArea = convertRecord(recordArg, heatAreaTypes) as IMoehlenhoffAlpha2HeatArea;
  heatArea.NR = nr;
  heatArea.ID = `${baseIdArg}:${nr}`;
  heatArea._HEATCTRL_STATE = 0;
  for (const heatControl of heatControlsArg) {
    if (heatControl.INUSE && heatControl.HEATAREA_NR === nr && numberValue(heatControl.HEATCTRL_STATE)) {
      heatArea._HEATCTRL_STATE = numberValue(heatControl.HEATCTRL_STATE) || 0;
      break;
    }
  }
  return heatArea;
};

const convertHeatControl = (baseIdArg: string, recordArg: Record<string, string>): IMoehlenhoffAlpha2HeatControl => {
  const nr = numberValue(recordArg.nr) || 0;
  const heatControl = convertRecord(recordArg, heatControlTypes) as IMoehlenhoffAlpha2HeatControl;
  heatControl.NR = nr;
  heatControl.ID = `${baseIdArg}:${nr}`;
  heatControl._HEATAREA_ID = heatControl.HEATAREA_NR ? `${baseIdArg}:${heatControl.HEATAREA_NR}` : null;
  return heatControl;
};

const convertIoDevice = (baseIdArg: string, recordArg: Record<string, string>): IMoehlenhoffAlpha2IoDevice => {
  const nr = numberValue(recordArg.nr) || 0;
  const ioDevice = convertRecord(recordArg, ioDeviceTypes) as IMoehlenhoffAlpha2IoDevice;
  ioDevice.NR = nr;
  ioDevice.ID = `${baseIdArg}:${nr}`;
  ioDevice._HEATAREA_ID = ioDevice.HEATAREA_NR ? `${baseIdArg}:${ioDevice.HEATAREA_NR}` : null;
  return ioDevice;
};

const blockRecords = (xmlArg: string, tagArg: string): Array<Record<string, string>> => {
  const records: Array<Record<string, string>> = [];
  const regex = new RegExp(`<${tagArg}([^>]*)>([\\s\\S]*?)<\\/${tagArg}>`, 'g');
  let match: RegExpExecArray | null;
  while ((match = regex.exec(xmlArg))) {
    records.push({ ...attributeRecord(match[1]), ...childrenRecord(match[2]) });
  }
  return records;
};

const childrenRecord = (xmlArg: string): Record<string, string> => {
  const record: Record<string, string> = {};
  const regex = /<([A-Z0-9_]+)>([\s\S]*?)<\/\1>/g;
  let match: RegExpExecArray | null;
  while ((match = regex.exec(xmlArg))) {
    record[match[1]] = decodeXml(match[2].trim());
  }
  return record;
};

const attributeRecord = (valueArg: string): Record<string, string> => {
  const record: Record<string, string> = {};
  const regex = /([a-zA-Z0-9_:-]+)="([^"]*)"/g;
  let match: RegExpExecArray | null;
  while ((match = regex.exec(valueArg))) {
    record[match[1]] = decodeXml(match[2]);
  }
  return record;
};

const tagBody = (xmlArg: string, tagArg: string): string | undefined => {
  const match = new RegExp(`<${tagArg}[^>]*>([\\s\\S]*?)<\\/${tagArg}>`).exec(xmlArg);
  return match?.[1];
};

const tagText = (xmlArg: string, tagArg: string): string | undefined => {
  const body = tagBody(xmlArg, tagArg);
  return body === undefined ? undefined : decodeXml(body.trim());
};

const heatAreaTypes: Record<string, 'boolean' | 'number' | 'string'> = {
  BLOCK_HC: 'boolean',
  HEATAREA_NAME: 'string',
  HEATAREA_MODE: 'number',
  HEATAREA_STATE: 'number',
  HEATINGSYSTEM: 'number',
  ISLOCKED: 'boolean',
  LIGHT: 'number',
  LOCK_AVAILABLE: 'boolean',
  LOCK_CODE: 'string',
  OFFSET: 'number',
  PARTY: 'boolean',
  PARTY_REMAININGTIME: 'number',
  PRESENCE: 'boolean',
  PROGRAM_SOURCE: 'number',
  PROGRAM_WEEK: 'number',
  PROGRAM_WEEKEND: 'number',
  RPM_MOTOR: 'number',
  SENSOR_EXT: 'number',
  T_ACTUAL: 'number',
  T_ACTUAL_EXT: 'number',
  T_COOL_DAY: 'number',
  T_COOL_NIGHT: 'number',
  T_FLOOR_DAY: 'number',
  T_HEAT_DAY: 'number',
  T_HEAT_NIGHT: 'number',
  T_TARGET: 'number',
  T_TARGET_ADJUSTABLE: 'boolean',
  T_TARGET_BASE: 'number',
  T_TARGET_MIN: 'number',
  T_TARGET_MAX: 'number',
};

const heatControlTypes: Record<string, 'boolean' | 'number' | 'string'> = {
  INUSE: 'boolean',
  HEATAREA_NR: 'number',
  ACTOR: 'number',
  ACTOR_PERCENT: 'number',
  HEATCTRL_STATE: 'number',
};

const ioDeviceTypes: Record<string, 'boolean' | 'number' | 'string'> = {
  IODEVICE_TYPE: 'number',
  IODEVICE_ID: 'number',
  IODEVICE_VERS_HW: 'string',
  IODEVICE_VERS_SW: 'string',
  HEATAREA_NR: 'number',
  SIGNALSTRENGTH: 'number',
  BATTERY: 'number',
  IODEVICE_STATE: 'number',
  IODEVICE_COMERROR: 'number',
  ISON: 'boolean',
};

const convertRecord = (recordArg: Record<string, string>, typesArg: Record<string, 'boolean' | 'number' | 'string'>): Record<string, unknown> => {
  const converted: Record<string, unknown> = { ...recordArg };
  for (const [key, type] of Object.entries(typesArg)) {
    if (recordArg[key] === undefined) {
      continue;
    }
    if (type === 'boolean') {
      converted[key] = boolValue(recordArg[key]);
    } else if (type === 'number') {
      converted[key] = numberValue(recordArg[key]);
    } else {
      converted[key] = recordArg[key];
    }
  }
  delete converted.nr;
  return converted;
};

const heatAreaXml = (heatAreaArg: IMoehlenhoffAlpha2HeatArea, attributesArg: Record<string, unknown>): string => {
  const nr = heatAreaArg.NR || String(heatAreaArg.ID).split(':').pop();
  const attributes = Object.entries(attributesArg).map(([keyArg, valueArg]) => `<${keyArg}>${formatXmlValue(keyArg, valueArg)}</${keyArg}>`).join('');
  return `<HEATAREA nr="${escapeXml(String(nr))}">${attributes}</HEATAREA>`;
};

const deviceIdFromHeatArea = (heatAreaArg: IMoehlenhoffAlpha2HeatArea, fallbackArg: string): string => String(heatAreaArg.ID).includes(':') ? String(heatAreaArg.ID).split(':')[0] : fallbackArg;

const presetMode = (valueArg: unknown): string => numberValue(valueArg) === 1 ? 'day' : numberValue(valueArg) === 2 ? 'night' : 'auto';

const datetimeValue = (valueArg: unknown): string => {
  if (typeof valueArg === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(valueArg)) {
    return valueArg.slice(0, 19);
  }
  const date = valueArg instanceof Date ? valueArg : new Date();
  return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}T${pad2(date.getHours())}:${pad2(date.getMinutes())}:${pad2(date.getSeconds())}`;
};

const formatXmlValue = (keyArg: string, valueArg: unknown): string => {
  if (typeof valueArg === 'boolean') {
    return valueArg ? '1' : '0';
  }
  if (typeof valueArg === 'number' && (keyArg.startsWith('T_') || keyArg === 'OFFSET')) {
    return valueArg.toFixed(1);
  }
  return escapeXml(String(valueArg));
};

const boolValue = (valueArg: unknown): boolean => valueArg === true || valueArg === 1 || valueArg === '1' || valueArg === 'true';

const stringValue = (valueArg: unknown): string | undefined => typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : undefined;

const numberValue = (valueArg: unknown): number | undefined => {
  if (typeof valueArg === 'number' && Number.isFinite(valueArg)) {
    return valueArg;
  }
  if (typeof valueArg === 'string' && valueArg.trim()) {
    const parsed = Number(valueArg.trim());
    return Number.isFinite(parsed) ? parsed : undefined;
  }
  return undefined;
};

const cleanAttributes = (attributesArg: Record<string, unknown>): Record<string, unknown> => Object.fromEntries(Object.entries(attributesArg).filter(([, valueArg]) => valueArg !== undefined && valueArg !== null && valueArg !== ''));

const pad2 = (valueArg: number): string => String(valueArg).padStart(2, '0');

const escapeXml = (valueArg: string): string => valueArg.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;');

const decodeXml = (valueArg: string): string => valueArg.replace(/&apos;/g, "'").replace(/&quot;/g, '"').replace(/&gt;/g, '>').replace(/&lt;/g, '<').replace(/&amp;/g, '&');

const errorMessage = (errorArg: unknown): string => errorArg instanceof Error ? errorArg.message : String(errorArg);
