import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { Observable, shareReplay } from 'rxjs';
import { map } from 'rxjs/operators';

import type { MouseHighlightTarget } from './mouse-payload.util';

const MOUSE_SVG_PATH = '/svg/visual/mouse.svg';

@Injectable({ providedIn: 'root' })
export class MouseSvgHighlightService {
  private readonly sanitizer = inject(DomSanitizer);
  private readonly http = inject(HttpClient);

  private readonly baseSvg$ = this.http.get(MOUSE_SVG_PATH, { responseType: 'text' }).pipe(
    shareReplay({ bufferSize: 1, refCount: false }),
  );

  /**
   * SECURITY: bypassSecurityTrustHtml используется для SVG, загруженных из собственного public/.
   * НЕ передавать пользовательский контент через этот метод — XSS-риск.
   */

  svgWithHighlight(targets: MouseHighlightTarget[] | null, animated = true): Observable<SafeHtml> {
    return this.baseSvg$.pipe(
      map((svg) => this.injectHighlight(svg, targets ?? [], animated)),
      map((html) => this.sanitizer.bypassSecurityTrustHtml(html)),
    );
  }

  private injectHighlight(svgText: string, targets: MouseHighlightTarget[], animated: boolean): string {
    let normalized = this.ensureMouseIds(svgText);
    const uniq = [...new Set(targets)];
    const hasLeft = uniq.includes('left');
    const hasRight = uniq.includes('right');
    const hasMiddle = uniq.includes('middle') || uniq.includes('wheel');
    const hasAny = hasLeft || hasRight || hasMiddle;

    let surfaceFill = 'var(--sg-keyboard-key-surface-idle)';
    if (hasLeft && hasRight) {
      surfaceFill = 'var(--sg-keyboard-key-pressed-fill)';
    } else if (hasLeft) {
      surfaceFill = 'url(#sg-mouse-left-fill)';
    } else if (hasRight) {
      surfaceFill = 'url(#sg-mouse-right-fill)';
    }

    const wheelFill = hasMiddle
      ? 'var(--sg-keyboard-key-pressed-fill)'
      : 'var(--sg-keyboard-key-surface-idle)';
    const wheelOpacity = hasAny || hasMiddle ? '1' : '0.98';
    const surfaceAnim = animated && hasAny
      ? 'sgInputHighlightFill var(--sg-input-highlight-duration) var(--sg-input-highlight-easing)'
      : 'none';
    const wheelAnim = animated && hasMiddle
      ? 'sgInputHighlightPop var(--sg-input-highlight-duration) var(--sg-input-highlight-easing)'
      : 'none';
    const keyframes = animated
      ? `@keyframes sgInputHighlightPop{0%{opacity:.45;transform:scale(var(--sg-input-highlight-from-scale));}100%{opacity:1;transform:scale(1);}}@keyframes sgInputHighlightFill{0%{opacity:.72;}100%{opacity:1;}}`
      : '';

    const defsAndStyles = `<defs><linearGradient id="sg-mouse-left-fill" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" stop-color="var(--sg-keyboard-key-pressed-fill)"/><stop offset="58%" stop-color="var(--sg-keyboard-key-pressed-fill)"/><stop offset="58%" stop-color="var(--sg-keyboard-key-surface-idle)"/><stop offset="100%" stop-color="var(--sg-keyboard-key-surface-idle)"/></linearGradient><linearGradient id="sg-mouse-right-fill" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" stop-color="var(--sg-keyboard-key-surface-idle)"/><stop offset="42%" stop-color="var(--sg-keyboard-key-surface-idle)"/><stop offset="42%" stop-color="var(--sg-keyboard-key-pressed-fill)"/><stop offset="100%" stop-color="var(--sg-keyboard-key-pressed-fill)"/></linearGradient></defs><style type="text/css"><![CDATA[#SG_MOUSE_SURFACE{fill:${surfaceFill}!important;animation:${surfaceAnim};}#SG_MOUSE_WHEEL{fill:${wheelFill}!important;opacity:${wheelOpacity};transform-box:fill-box;transform-origin:center;animation:${wheelAnim};}${keyframes}]]></style>`;
    normalized = normalized.replace(/<\/svg>/i, `${defsAndStyles}</svg>`);
    return normalized;
  }

  private ensureMouseIds(svgText: string): string {
    let next = svgText;
    if (!next.includes('id="SG_MOUSE_SURFACE"')) {
      next = next.replace(/<path\b(?![^>]*\bid=)/i, '<path id="SG_MOUSE_SURFACE"');
    }
    if (!next.includes('id="SG_MOUSE_WHEEL"')) {
      next = next.replace(/<rect\b(?![^>]*\bid=)/i, '<rect id="SG_MOUSE_WHEEL"');
    }
    return next;
  }
}
