import { Injectable, inject } from '@angular/core';
import { Store } from '@ngrx/store';

import { selectCurrentUser } from '../../../../store/users/users.selectors';
import { ElectronBridgeService } from '../../../../core/platform/electron/electron-bridge.service';
import { PlatformService } from '../../../../core/platform';

export interface DebugExportEnvironment {
  appVersion: string;
  displayName: string;
  displayServer: string;
  gpu: string;
  operatingSystem: string;
  platform: string;
  userAgent: string;
  userId: string;
}

@Injectable({ providedIn: 'root' })
export class DebugConsoleEnvironmentService {
  private readonly store = inject(Store);
  private readonly electronBridge = inject(ElectronBridgeService);
  private readonly platformService = inject(PlatformService);
  private readonly currentUser = this.store.selectSignal(selectCurrentUser);

  getEnvironment(): DebugExportEnvironment {
    return {
      appVersion: this.resolveAppVersion(),
      displayName: this.resolveDisplayName(),
      displayServer: this.resolveDisplayServer(),
      gpu: this.resolveGpu(),
      operatingSystem: this.resolveOperatingSystem(),
      platform: this.resolvePlatform(),
      userAgent: navigator.userAgent,
      userId: this.currentUser()?.id ?? 'Unknown'
    };
  }

  getFilenameSafeDisplayName(): string {
    const name = this.resolveDisplayName();
    const sanitized = name
      .replace(/[^a-zA-Z0-9._-]/g, '_')
      .replace(/_+/g, '_')
      .replace(/^_|_$/g, '');

    return sanitized || 'unknown';
  }

  private resolveDisplayName(): string {
    return this.currentUser()?.displayName ?? 'Unknown';
  }

  private resolveAppVersion(): string {
    if (!this.platformService.isElectron)
      return 'web';

    const electronVersion = this.readElectronVersion();

    return electronVersion
      ? `${electronVersion} (Electron)`
      : 'Electron (unknown version)';
  }

  private resolvePlatform(): string {
    if (!this.platformService.isElectron)
      return 'Browser';

    const os = this.resolveOperatingSystem().toLowerCase();

    if (os.includes('windows'))
      return 'Windows Electron';

    if (os.includes('linux'))
      return 'Linux Electron';

    if (os.includes('mac'))
      return 'macOS Electron';

    return 'Electron';
  }

  private resolveOperatingSystem(): string {
    const ua = navigator.userAgent;

    if (ua.includes('Windows NT 10.0'))
      return 'Windows 10/11';

    if (ua.includes('Windows NT'))
      return 'Windows';

    if (ua.includes('Mac OS X')) {
      const match = ua.match(/Mac OS X ([\d._]+)/);
      const version = match?.[1]?.replace(/_/g, '.') ?? '';

      return version ? `macOS ${version}` : 'macOS';
    }

    if (ua.includes('Linux')) {
      const parts: string[] = ['Linux'];

      if (ua.includes('Ubuntu'))
        parts.push('(Ubuntu)');
      else if (ua.includes('Fedora'))
        parts.push('(Fedora)');
      else if (ua.includes('Debian'))
        parts.push('(Debian)');

      return parts.join(' ');
    }

    return navigator.platform || 'Unknown';
  }

  private resolveDisplayServer(): string {
    if (!navigator.userAgent.includes('Linux'))
      return 'N/A';

    const electronDisplayServer = this.readElectronDisplayServer();

    if (electronDisplayServer)
      return electronDisplayServer;

    try {
      const ua = navigator.userAgent.toLowerCase();

      if (ua.includes('wayland'))
        return 'Wayland';

      const isOzone = ua.includes('ozone');

      if (isOzone)
        return 'Ozone (Wayland likely)';

      if (ua.includes('x11'))
        return 'X11';
    } catch {
      // Ignore
    }

    return this.detectDisplayServerFromEnv();
  }

  private readElectronDisplayServer(): string | null {
    try {
      const displayServer = this.electronBridge.getApi()?.linuxDisplayServer;

      return typeof displayServer === 'string' && displayServer.trim().length > 0
        ? displayServer
        : null;
    } catch {
      return null;
    }
  }

  private detectDisplayServerFromEnv(): string {
    try {
      // Electron may expose env vars
      const api = this.electronBridge.getApi();

      if (!api)
        return 'Unknown (Linux)';
    } catch {
      // Not available
    }

    // Best-effort heuristic: check if WebGL context
    // mentions wayland in renderer string
    const gpu = this.resolveGpu().toLowerCase();

    if (gpu.includes('wayland'))
      return 'Wayland';

    return 'Unknown (Linux)';
  }

  private resolveGpu(): string {
    try {
      const canvas = document.createElement('canvas');
      const gl = canvas.getContext('webgl')
        ?? canvas.getContext('experimental-webgl');

      if (!gl || !(gl instanceof WebGLRenderingContext))
        return 'Unavailable';

      const ext = gl.getExtension('WEBGL_debug_renderer_info');

      if (!ext)
        return 'Unavailable (no debug info)';

      const vendor = gl.getParameter(ext.UNMASKED_VENDOR_WEBGL);
      const renderer = gl.getParameter(
        ext.UNMASKED_RENDERER_WEBGL
      );
      const parts: string[] = [];

      if (typeof renderer === 'string' && renderer.length > 0)
        parts.push(renderer);

      if (typeof vendor === 'string' && vendor.length > 0)
        parts.push(`(${vendor})`);

      return parts.length > 0
        ? parts.join(' ')
        : 'Unknown';
    } catch {
      return 'Unavailable';
    }
  }

  private readElectronVersion(): string | null {
    try {
      const ua = navigator.userAgent;
      const match = ua.match(/metoyou\/([\d.]+)/i)
        ?? ua.match(/Electron\/([\d.]+)/);

      return match?.[1] ?? null;
    } catch {
      return null;
    }
  }
}
