/* eslint-disable @typescript-eslint/member-ordering */
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { type ServerEndpoint, ServerDirectoryFacade } from '../../../server-directory';
import type { LoginResponse } from '../../domain/models/authentication.model';

/**
 * Handles user authentication (login and registration) against a
 * configurable back-end server.
 *
 * The target server is resolved via {@link ServerDirectoryFacade}: the
 * caller may pass an explicit `serverId`, otherwise the currently active
 * server endpoint is used.
 */
@Injectable({ providedIn: 'root' })
export class AuthenticationService {
  private readonly http = inject(HttpClient);
  private readonly serverDirectory = inject(ServerDirectoryFacade);

  /**
   * Resolve the API base URL for the given server.
   *
   * @param serverId - Optional server ID to look up. When omitted the
   *   currently active endpoint is used.
   * @returns Fully-qualified API base URL (e.g. `http://host:3001/api`).
   */
  private endpointFor(serverId?: string): string {
    let endpoint: ServerEndpoint | undefined;

    if (serverId) {
      endpoint = this.serverDirectory.servers().find(
        (server) => server.id === serverId
      );
    }

    const activeEndpoint = endpoint ?? this.serverDirectory.activeServer();

    return activeEndpoint
      ? `${activeEndpoint.url}/api`
      : this.serverDirectory.getApiBaseUrl();
  }

  /**
   * Register a new user account on the target server.
   *
   * @param params - Registration parameters.
   * @param params.username  - Desired login username.
   * @param params.password  - Account password.
   * @param params.displayName - Optional display name (defaults to username on the server).
   * @param params.serverId  - Optional server ID to register against.
   * @returns Observable emitting the {@link LoginResponse} on success.
   */
  register(params: {
    username: string;
    password: string;
    displayName?: string;
    serverId?: string;
  }): Observable<LoginResponse> {
    const url = `${this.endpointFor(params.serverId)}/users/register`;

    return this.http.post<LoginResponse>(url, {
      username: params.username,
      password: params.password,
      displayName: params.displayName
    });
  }

  /**
   * Log in to an existing user account on the target server.
   *
   * @param params - Login parameters.
   * @param params.username - Login username.
   * @param params.password - Account password.
   * @param params.serverId - Optional server ID to authenticate against.
   * @returns Observable emitting the {@link LoginResponse} on success.
   */
  login(params: {
    username: string;
    password: string;
    serverId?: string;
  }): Observable<LoginResponse> {
    const url = `${this.endpointFor(params.serverId)}/users/login`;

    return this.http.post<LoginResponse>(url, {
      username: params.username,
      password: params.password
    });
  }
}
