
import {
  Component,
  computed,
  inject,
  OnInit,
  signal
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { Actions } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideLogIn } from '@ng-icons/lucide';
import {
  filter,
  firstValueFrom,
  take
} from 'rxjs';

import { AuthenticationService } from '../../application/services/authentication.service';
import { ServerDirectoryFacade } from '../../../server-directory';
import {
  AUTH_MODE_AUTHORIZE,
  buildLoginReturnQueryParams,
  isAuthorizeAuthMode,
  resolveSafeReturnUrl,
  waitForAuthenticationOutcome
} from '../../domain/logic/auth-navigation.rules';
import { UsersActions } from '../../../../store/users/users.actions';
import { User } from '../../../../shared-kernel';
import { AppI18nService, APP_TRANSLATE_IMPORTS } from '../../../../core/i18n';
import { AutoFocusDirective, SelectOnFocusDirective } from '../../../../shared/directives';
import { selectCurrentUser } from '../../../../store/users/users.selectors';

@Component({
  selector: 'app-login',
  standalone: true,
  imports: [
    CommonModule,
    FormsModule,
    NgIcon,
    AutoFocusDirective,
    SelectOnFocusDirective,
    ...APP_TRANSLATE_IMPORTS
  ],
  viewProviders: [provideIcons({ lucideLogIn })],
  templateUrl: './login.component.html'
})
/**
 * Login form allowing existing users to authenticate against a selected server.
 */
export class LoginComponent implements OnInit {
  serversSvc = inject(ServerDirectoryFacade);

  servers = this.serversSvc.servers;
  username = '';
  password = '';
  serverId: string | undefined = this.serversSvc.activeServer()?.id;
  error = signal<string | null>(null);
  readonly isAuthorizeMode = signal(false);
  readonly authorizeServerName = computed(() => {
    const sid = this.serverId || this.serversSvc.activeServer()?.id;
    const endpoint = this.servers().find((server) => server.id === sid);

    return endpoint?.name ?? this.appI18n.instant('auth.authorize.defaultServerName');
  });

  private readonly appI18n = inject(AppI18nService);
  private auth = inject(AuthenticationService);
  private actions$ = inject(Actions);
  private store = inject(Store);
  private route = inject(ActivatedRoute);
  private router = inject(Router);

  /** TrackBy function for server list rendering. */
  trackById(_index: number, item: { id: string }) { return item.id; }

  ngOnInit(): void {
    const mode = this.route.snapshot.queryParamMap.get('mode');
    const requestedServerId = this.route.snapshot.queryParamMap.get('serverId')?.trim();

    this.isAuthorizeMode.set(isAuthorizeAuthMode(mode));

    if (requestedServerId) {
      this.serverId = requestedServerId;
    }

    if (this.isAuthorizeMode()) {
      return;
    }

    this.store.select(selectCurrentUser).pipe(
      filter(Boolean),
      take(1)
    )
      .subscribe(() => {
        const returnUrl = resolveSafeReturnUrl(this.route.snapshot.queryParamMap.get('returnUrl'));

        void this.router.navigateByUrl(returnUrl);
      });
  }

  /** Validate and submit the login form, then navigate to search on success. */
  submit() {
    this.error.set(null);
    const sid = this.serverId || this.serversSvc.activeServer()?.id;

    this.auth.login({ username: this.username.trim(),
      password: this.password,
      serverId: sid }).subscribe({
      next: async (resp) => {
        const serverUrl = this.auth.resolveServerUrlFor(sid);

        if (this.isAuthorizeMode()) {
          this.store.dispatch(UsersActions.authorizeSignalServer({
            serverUrl,
            response: resp,
            provisioned: false
          }));

          const returnUrl = resolveSafeReturnUrl(this.route.snapshot.queryParamMap.get('returnUrl'));

          await this.router.navigateByUrl(returnUrl);
          return;
        }

        if (sid) {
          this.serversSvc.setActiveServer(sid);
        }

        const homeSignalServerUrl = this.serversSvc.servers().find((server) => server.id === sid)?.url
          ?? this.serversSvc.activeServer()?.url;
        const user: User = {
          id: resp.id,
          oderId: resp.id,
          username: resp.username,
          displayName: resp.displayName,
          status: 'online',
          role: 'member',
          joinedAt: Date.now(),
          homeSignalServerUrl
        };

        this.store.dispatch(UsersActions.authenticateUser({ user, loginResponse: resp }));

        const outcome = await firstValueFrom(waitForAuthenticationOutcome(this.actions$));

        if (outcome.kind === 'failure') {
          this.error.set(outcome.error);
          return;
        }

        const returnUrl = resolveSafeReturnUrl(this.route.snapshot.queryParamMap.get('returnUrl'));

        await this.router.navigateByUrl(returnUrl);
      },
      error: (err) => {
        this.error.set(err?.error?.error || this.appI18n.instant('auth.login.failed'));
      }
    });
  }

  /** Navigate to the registration page. */
  goRegister() {
    this.router.navigate(['/register'], {
      queryParams: buildLoginReturnQueryParams(this.router.url, undefined, {
        mode: this.isAuthorizeMode() ? AUTH_MODE_AUTHORIZE : undefined,
        serverId: this.serverId
      })
    });
  }
}
