import { Injectable, inject } from '@angular/core';
import { Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { firstValueFrom } from 'rxjs';
import { selectCurrentUser } from '../../../../store/users/users.selectors';
import { ServerDirectoryFacade } from '../../../server-directory';
import { AUTH_MODE_AUTHORIZE, buildLoginReturnQueryParams } from '../../domain/logic/auth-navigation.rules';
import { SignalServerAuthService } from './signal-server-auth.service';

@Injectable({ providedIn: 'root' })
export class SignalServerAuthorizeService {
  private readonly router = inject(Router);
  private readonly store = inject(Store);
  private readonly serverDirectory = inject(ServerDirectoryFacade);
  private readonly signalServerAuth = inject(SignalServerAuthService);

  async ensureCredentialForServerUrl(serverUrl: string): Promise<boolean> {
    if (this.signalServerAuth.hasValidCredential(serverUrl)) {
      return true;
    }

    const currentUser = await firstValueFrom(this.store.select(selectCurrentUser));

    if (!currentUser) {
      return false;
    }

    const result = await this.signalServerAuth.ensureProvisioned(serverUrl, currentUser);

    if (result.kind === 'existing' || result.kind === 'provisioned') {
      return true;
    }

    if (result.kind === 'collision') {
      await this.navigateToAuthorize(serverUrl, this.router.url);
      return false;
    }

    if (result.kind === 'skipped' && result.reason === 'no-provision-secret') {
      await this.navigateToAuthorize(serverUrl, this.router.url);
      return false;
    }

    return false;
  }

  async navigateToAuthorize(serverUrl: string, returnUrl: string): Promise<void> {
    const endpoint = this.serverDirectory.ensureServerEndpoint({
      name: this.buildEndpointName(serverUrl),
      url: serverUrl
    });

    await this.router.navigate(['/login'], {
      queryParams: buildLoginReturnQueryParams(returnUrl, undefined, {
        mode: AUTH_MODE_AUTHORIZE,
        serverId: endpoint.id
      })
    });
  }

  private buildEndpointName(serverUrl: string): string {
    try {
      return new URL(serverUrl).hostname;
    } catch {
      return serverUrl;
    }
  }
}
