import { Injectable, signal } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import {
  NavigationEnd,
  PRIMARY_OUTLET,
  Router,
  UrlTree,
} from '@angular/router';

@Injectable({
  providedIn: 'root',
})
export class LanguageService {
  currentLang = signal<'it' | 'en' | 'de' | 'fr'>('it');
  private readonly supportedLangs: Array<'it' | 'en' | 'de' | 'fr'> = [
    'it',
    'en',
    'de',
    'fr',
  ];

  constructor(
    private translate: TranslateService,
    private router: Router,
  ) {
    this.translate.addLangs(this.supportedLangs);
    this.translate.setDefaultLang('it');
    this.translate.onLangChange.subscribe((event) => {
      const lang =
        typeof event.lang === 'string' ? event.lang.toLowerCase() : null;
      if (this.isSupportedLang(lang) && lang !== this.currentLang()) {
        this.currentLang.set(lang);
      }
    });

    const initialTree = this.router.parseUrl(this.router.url);
    const initialSegments = this.getPrimarySegments(initialTree);
    const queryLang = this.getQueryLang(initialTree);
    const initialLang = this.isSupportedLang(initialSegments[0])
      ? initialSegments[0]
      : this.isSupportedLang(queryLang)
        ? queryLang
        : 'it';
    this.applyLanguage(initialLang);
    this.ensureLanguageInPath(initialTree);

    this.router.events.subscribe((event) => {
      if (!(event instanceof NavigationEnd)) {
        return;
      }

      this.ensureLanguageInPath(this.router.parseUrl(this.router.url));
    });
  }

  switchLang(lang: 'it' | 'en' | 'de' | 'fr') {
    if (!this.isSupportedLang(lang)) {
      return;
    }
    this.applyLanguage(lang);

    const currentTree = this.router.parseUrl(this.router.url);
    const segments = this.getPrimarySegments(currentTree);

    let targetSegments: string[];
    if (segments.length === 0) {
      targetSegments = [lang];
    } else if (
      this.isSupportedLang(segments[0]) ||
      this.looksLikeLangToken(segments[0])
    ) {
      targetSegments = [lang, ...segments.slice(1)];
    } else {
      targetSegments = [lang, ...segments];
    }

    this.navigateIfChanged(currentTree, targetSegments);
  }

  selectedLang(): 'it' | 'en' | 'de' | 'fr' {
    const activeLang =
      typeof this.translate.currentLang === 'string'
        ? this.translate.currentLang.toLowerCase()
        : null;
    return this.isSupportedLang(activeLang) ? activeLang : this.currentLang();
  }

  private ensureLanguageInPath(urlTree: UrlTree): void {
    const segments = this.getPrimarySegments(urlTree);

    if (segments.length > 0 && this.isSupportedLang(segments[0])) {
      this.applyLanguage(segments[0]);
      return;
    }

    const queryLang = this.getQueryLang(urlTree);
    const activeLang = this.isSupportedLang(queryLang)
      ? queryLang
      : this.currentLang();
    if (activeLang !== this.currentLang()) {
      this.applyLanguage(activeLang);
    }
    let targetSegments: string[];

    if (segments.length === 0) {
      targetSegments = [activeLang];
    } else if (this.looksLikeLangToken(segments[0])) {
      targetSegments = [activeLang, ...segments.slice(1)];
    } else {
      targetSegments = [activeLang, ...segments];
    }

    this.navigateIfChanged(urlTree, targetSegments);
  }

  private getPrimarySegments(urlTree: UrlTree): string[] {
    const primaryGroup = urlTree.root.children[PRIMARY_OUTLET];
    if (!primaryGroup) {
      return [];
    }
    return primaryGroup.segments.map((segment) => segment.path.toLowerCase());
  }

  private getQueryLang(urlTree: UrlTree): string | null {
    const lang = urlTree.queryParams['lang'];
    return typeof lang === 'string' ? lang.toLowerCase() : null;
  }

  private isSupportedLang(
    lang: string | null | undefined,
  ): lang is 'it' | 'en' | 'de' | 'fr' {
    return (
      typeof lang === 'string' &&
      this.supportedLangs.includes(lang as 'it' | 'en' | 'de' | 'fr')
    );
  }

  private looksLikeLangToken(segment: string | null | undefined): boolean {
    return (
      typeof segment === 'string' && /^[a-z]{2}(?:-[a-z]{2})?$/i.test(segment)
    );
  }

  private applyLanguage(lang: 'it' | 'en' | 'de' | 'fr'): void {
    if (this.currentLang() === lang && this.translate.currentLang === lang) {
      return;
    }
    this.translate.use(lang);
    this.currentLang.set(lang);
  }

  private navigateIfChanged(
    currentTree: UrlTree,
    targetSegments: string[],
  ): void {
    const { lang: _unusedLang, ...queryParams } = currentTree.queryParams;
    const targetTree = this.router.createUrlTree(['/', ...targetSegments], {
      queryParams,
      fragment: currentTree.fragment ?? undefined,
    });

    if (
      this.router.serializeUrl(targetTree) ===
      this.router.serializeUrl(currentTree)
    ) {
      return;
    }

    this.router.navigateByUrl(targetTree, { replaceUrl: true });
  }
}
