import { app } from 'electron';
import * as fs from 'fs';
import * as path from 'path';

export type AutoUpdateMode = 'auto' | 'off' | 'version';

export interface LocalApiSettings {
  enabled: boolean;
  port: number;
  exposeOnLan: boolean;
  scalarEnabled: boolean;
  docusaurusEnabled: boolean;
  allowedSignalingServers: string[];
}

export interface DesktopSettings {
  autoUpdateMode: AutoUpdateMode;
  autoStart: boolean;
  closeToTray: boolean;
  hardwareAcceleration: boolean;
  ignoredGameProcesses: string[];
  localApi: LocalApiSettings;
  manifestUrls: string[];
  preferredVersion: string | null;
  vaapiVideoEncode: boolean;
}

export interface DesktopSettingsSnapshot extends DesktopSettings {
  runtimeHardwareAcceleration: boolean;
  restartRequired: boolean;
}

const DEFAULT_LOCAL_API_SETTINGS: LocalApiSettings = {
  enabled: false,
  port: 17878,
  exposeOnLan: false,
  scalarEnabled: false,
  docusaurusEnabled: false,
  allowedSignalingServers: []
};
const DEFAULT_DESKTOP_SETTINGS: DesktopSettings = {
  autoUpdateMode: 'auto',
  autoStart: true,
  closeToTray: true,
  hardwareAcceleration: true,
  ignoredGameProcesses: [],
  localApi: { ...DEFAULT_LOCAL_API_SETTINGS },
  manifestUrls: [],
  preferredVersion: null,
  vaapiVideoEncode: false
};

function normalizeAutoUpdateMode(value: unknown): AutoUpdateMode {
  return value === 'off' || value === 'version' ? value : 'auto';
}

function normalizePreferredVersion(value: unknown): string | null {
  return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;
}

function normalizeManifestUrls(value: unknown): string[] {
  if (!Array.isArray(value)) {
    return [];
  }

  const manifestUrls: string[] = [];

  for (const entry of value) {
    if (typeof entry !== 'string') {
      continue;
    }

    const nextUrl = entry.trim();

    if (!nextUrl || manifestUrls.includes(nextUrl)) {
      continue;
    }

    manifestUrls.push(nextUrl);
  }

  return manifestUrls;
}

function normalizeIgnoredGameProcesses(value: unknown): string[] {
  if (!Array.isArray(value)) {
    return [];
  }

  const ignored: string[] = [];

  for (const entry of value) {
    if (typeof entry !== 'string') {
      continue;
    }

    const trimmed = entry.trim().toLowerCase()
      .replace(/\.(exe|bin|app|out)$/iu, '');

    if (!trimmed || trimmed.length > 96 || ignored.includes(trimmed)) {
      continue;
    }

    ignored.push(trimmed);
  }

  return ignored.sort();
}

function normalizePort(value: unknown, fallback: number): number {
  if (typeof value !== 'number' || !Number.isFinite(value)) {
    return fallback;
  }

  const port = Math.floor(value);

  if (port < 1 || port > 65535) {
    return fallback;
  }

  return port;
}

function normalizeAllowedSignalingServers(value: unknown): string[] {
  if (!Array.isArray(value)) {
    return [];
  }

  const urls: string[] = [];

  for (const entry of value) {
    if (typeof entry !== 'string') {
      continue;
    }

    const trimmed = entry.trim().replace(/\/+$/u, '');

    if (!trimmed || urls.includes(trimmed)) {
      continue;
    }

    if (!/^https?:\/\//iu.test(trimmed)) {
      continue;
    }

    urls.push(trimmed);
  }

  return urls;
}

function normalizeLocalApiSettings(value: unknown): LocalApiSettings {
  const source = (value && typeof value === 'object') ? value as Partial<LocalApiSettings> : {};

  return {
    enabled: typeof source.enabled === 'boolean' ? source.enabled : DEFAULT_LOCAL_API_SETTINGS.enabled,
    port: normalizePort(source.port, DEFAULT_LOCAL_API_SETTINGS.port),
    exposeOnLan: typeof source.exposeOnLan === 'boolean' ? source.exposeOnLan : DEFAULT_LOCAL_API_SETTINGS.exposeOnLan,
    scalarEnabled: typeof source.scalarEnabled === 'boolean' ? source.scalarEnabled : DEFAULT_LOCAL_API_SETTINGS.scalarEnabled,
    docusaurusEnabled: typeof source.docusaurusEnabled === 'boolean' ? source.docusaurusEnabled : DEFAULT_LOCAL_API_SETTINGS.docusaurusEnabled,
    allowedSignalingServers: normalizeAllowedSignalingServers(source.allowedSignalingServers)
  };
}

export function getDesktopSettingsSnapshot(): DesktopSettingsSnapshot {
  const storedSettings = readDesktopSettings();
  const runtimeHardwareAcceleration = app.isHardwareAccelerationEnabled();

  return {
    ...storedSettings,
    runtimeHardwareAcceleration,
    restartRequired: storedSettings.hardwareAcceleration !== runtimeHardwareAcceleration
  };
}

export function readDesktopSettings(): DesktopSettings {
  const filePath = getDesktopSettingsPath();

  try {
    if (!fs.existsSync(filePath)) {
      return { ...DEFAULT_DESKTOP_SETTINGS };
    }

    const raw = fs.readFileSync(filePath, 'utf8');
    const parsed = JSON.parse(raw) as Partial<DesktopSettings>;

    return {
      autoUpdateMode: normalizeAutoUpdateMode(parsed.autoUpdateMode),
      autoStart: typeof parsed.autoStart === 'boolean'
        ? parsed.autoStart
        : DEFAULT_DESKTOP_SETTINGS.autoStart,
      closeToTray: typeof parsed.closeToTray === 'boolean'
        ? parsed.closeToTray
        : DEFAULT_DESKTOP_SETTINGS.closeToTray,
      vaapiVideoEncode: typeof parsed.vaapiVideoEncode === 'boolean'
        ? parsed.vaapiVideoEncode
        : DEFAULT_DESKTOP_SETTINGS.vaapiVideoEncode,
      hardwareAcceleration: typeof parsed.hardwareAcceleration === 'boolean'
        ? parsed.hardwareAcceleration
        : DEFAULT_DESKTOP_SETTINGS.hardwareAcceleration,
      ignoredGameProcesses: normalizeIgnoredGameProcesses(parsed.ignoredGameProcesses),
      localApi: normalizeLocalApiSettings(parsed.localApi),
      manifestUrls: normalizeManifestUrls(parsed.manifestUrls),
      preferredVersion: normalizePreferredVersion(parsed.preferredVersion)
    };
  } catch {
    return { ...DEFAULT_DESKTOP_SETTINGS };
  }
}

export function updateDesktopSettings(patch: Partial<DesktopSettings>): DesktopSettingsSnapshot {
  const previousSettings = readDesktopSettings();
  const mergedSettings = {
    ...previousSettings,
    ...patch,
    localApi: patch.localApi
      ? { ...previousSettings.localApi, ...patch.localApi }
      : previousSettings.localApi
  };
  const nextSettings: DesktopSettings = {
    autoUpdateMode: normalizeAutoUpdateMode(mergedSettings.autoUpdateMode),
    autoStart: typeof mergedSettings.autoStart === 'boolean'
      ? mergedSettings.autoStart
      : DEFAULT_DESKTOP_SETTINGS.autoStart,
    closeToTray: typeof mergedSettings.closeToTray === 'boolean'
      ? mergedSettings.closeToTray
      : DEFAULT_DESKTOP_SETTINGS.closeToTray,
    hardwareAcceleration: typeof mergedSettings.hardwareAcceleration === 'boolean'
      ? mergedSettings.hardwareAcceleration
      : DEFAULT_DESKTOP_SETTINGS.hardwareAcceleration,
    ignoredGameProcesses: normalizeIgnoredGameProcesses(mergedSettings.ignoredGameProcesses),
    localApi: normalizeLocalApiSettings(mergedSettings.localApi),
    manifestUrls: normalizeManifestUrls(mergedSettings.manifestUrls),
    preferredVersion: normalizePreferredVersion(mergedSettings.preferredVersion),
    vaapiVideoEncode: typeof mergedSettings.vaapiVideoEncode === 'boolean'
      ? mergedSettings.vaapiVideoEncode
      : DEFAULT_DESKTOP_SETTINGS.vaapiVideoEncode
  };
  const filePath = getDesktopSettingsPath();

  fs.mkdirSync(path.dirname(filePath), { recursive: true });
  fs.writeFileSync(filePath, JSON.stringify(nextSettings, null, 2), 'utf8');

  return getDesktopSettingsSnapshot();
}

function getDesktopSettingsPath(): string {
  return path.join(app.getPath('userData'), 'desktop-settings.json');
}
