import { Injectable } from '@angular/core';
import { DefaultUrlSerializer, UrlSerializer, UrlTree } from '@angular/router';

import { TenantService } from './tenant.service';

@Injectable()
export class TenantUrlSerializer extends UrlSerializer {
  private readonly defaultSerializer = new DefaultUrlSerializer();

  constructor(private readonly tenantService: TenantService) {
    super();
  }

  override parse(url: string): UrlTree {
    return this.defaultSerializer.parse(this.removeBasePath(url));
  }

  override serialize(tree: UrlTree): string {
    const url = this.defaultSerializer.serialize(tree);
    const basePath = this.basePath();

    if (basePath === '/') {
      return url;
    }

    return url === '/' ? basePath : `${basePath}${url}`;
  }

  private removeBasePath(url: string): string {
    const basePath = this.basePath();

    if (basePath === '/' || !this.startsWithCompletePathSegment(url, basePath)) {
      return url;
    }

    const remainder = url.slice(basePath.length);

    if (remainder === '') {
      return '/';
    }

    return remainder.startsWith('?') || remainder.startsWith('#')
      ? `/${remainder}`
      : remainder;
  }

  private basePath(): string {
    const configuredPath = this.tenantService.getTenant()?.base_path?.trim() ?? '/';

    if (configuredPath === '' || configuredPath === '/') {
      return '/';
    }

    return `/${configuredPath.replace(/^\/+|\/+$/g, '')}`;
  }

  private startsWithCompletePathSegment(url: string, basePath: string): boolean {
    if (!url.startsWith(basePath)) {
      return false;
    }

    const boundary = url.charAt(basePath.length);

    return boundary === '' || boundary === '/' || boundary === '?' || boundary === '#';
  }
}
