import { CommonModule } from "@angular/common";
import { ChangeDetectionStrategy, Component, computed, inject, signal } from "@angular/core";
import { toSignal } from "@angular/core/rxjs-interop";

import { JslibModule } from "@bitwarden/angular/jslib.module";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { UriMatchStrategy } from "@bitwarden/common/models/domain/domain-service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
import { UnionOfValues } from "@bitwarden/common/vault/types/union-of-values";
import {
  DIALOG_DATA,
  DialogConfig,
  DialogRef,
  DialogService,
  BadgeComponent,
  ButtonModule,
  DialogModule,
  TypographyModule,
  CalloutComponent,
  LinkModule,
  TooltipDirective,
} from "@bitwarden/components";

export interface AutofillConfirmationDialogParams {
  savedUris: LoginUriView[];
  currentUrl: string;
  viewOnly?: boolean;
}

export const AutofillConfirmationDialogResult = Object.freeze({
  AutofillAndUrlAdded: "added",
  AutofilledOnly: "autofilled",
  Canceled: "canceled",
} as const);

export type AutofillConfirmationDialogResultType = UnionOfValues<
  typeof AutofillConfirmationDialogResult
>;

/** Match strategies that force showing full URLs */
const FULL_URI_MATCH_STRATEGIES = [
  UriMatchStrategy.StartsWith,
  UriMatchStrategy.RegularExpression,
  UriMatchStrategy.Exact,
];

@Component({
  templateUrl: "./autofill-confirmation-dialog.component.html",
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    BadgeComponent,
    ButtonModule,
    CalloutComponent,
    CommonModule,
    DialogModule,
    LinkModule,
    TypographyModule,
    JslibModule,
    TooltipDirective,
  ],
})
export class AutofillConfirmationDialogComponent {
  private readonly params = inject<AutofillConfirmationDialogParams>(DIALOG_DATA);
  private readonly dialogRef = inject(DialogRef<AutofillConfirmationDialogResultType>);
  private readonly domainSettingsService = inject(DomainSettingsService);
  private readonly i18nService = inject(I18nService);

  private readonly uriMatchSetting = toSignal(
    this.domainSettingsService.resolvedDefaultUriMatchStrategy$,
  );

  readonly savedUrls = signal<LoginUriView[]>(this.params.savedUris ?? []);

  readonly currentUrl = signal<string>(this.params.currentUrl);

  /**
   * When any of the saved URIs contain a `FULL_URI_MATCH_STRATEGIES` setting,
   * show the full URLs in the dialog.
   */
  readonly showFullUrls = computed<boolean>(() => {
    const uriMatchSetting = this.uriMatchSetting();

    return (
      (uriMatchSetting && (FULL_URI_MATCH_STRATEGIES as number[]).includes(uriMatchSetting)) ||
      this.savedUrls().some(
        (u) => u.match != null && (FULL_URI_MATCH_STRATEGIES as number[]).includes(u.match),
      )
    );
  });

  readonly formattedSavedUrls = computed(() => {
    const savedUrls = this.savedUrls();

    return this.showFullUrls()
      ? savedUrls.map((u) => u.uri)
      : savedUrls.map((u) => Utils.getHostname(u.uri ?? "")).filter(Boolean);
  });

  readonly formattedCurrentUrl = computed(() => {
    return this.showFullUrls() ? this.currentUrl() : Utils.getHostname(this.currentUrl());
  });

  readonly viewOnly = signal<boolean>(this.params.viewOnly ?? false);
  readonly savedUrlsExpanded = signal<boolean>(false);

  readonly currentUrlMatchesNeverUri = computed<boolean>(() => {
    const currentHostname = Utils.getHostname(this.currentUrl());
    if (!currentHostname) {
      return false;
    }
    const uriMatchSetting = this.uriMatchSetting();
    return this.savedUrls().some((u) => {
      const effectiveMatch = u.match ?? uriMatchSetting;
      return (
        effectiveMatch === UriMatchStrategy.Never &&
        Utils.getHostname(u.uri ?? "") === currentHostname
      );
    });
  });

  readonly dialogTitle = computed(() => {
    if (this.currentUrlMatchesNeverUri()) {
      return this.i18nService.t("loginNeverMatchTitle");
    }
    return this.savedUrls().length === 0
      ? this.i18nService.t("loginHasNoSiteSaved")
      : this.i18nService.t("siteDoesntMatch");
  });

  readonly dialogBody = computed(() => {
    const count = this.savedUrls().length;
    if (count === 0) {
      return this.i18nService.t("loginNoSiteDesc");
    }
    if (this.currentUrlMatchesNeverUri()) {
      return this.i18nService.t("loginNeverMatchDesc");
    }
    if (count === 1) {
      return this.i18nService.t("loginSingleSiteDesc");
    }
    return this.i18nService.t("loginMultipleSitesDesc");
  });

  readonly savedUrlsListClass = computed(() =>
    this.savedUrlsExpanded()
      ? ""
      : `tw-relative tw-max-h-24 tw-overflow-hidden after:tw-pointer-events-none
         after:tw-content-[''] after:tw-absolute after:tw-inset-x-0 after:tw-bottom-0
         after:tw-h-8 after:tw-bg-gradient-to-t after:tw-from-background after:tw-to-transparent`,
  );

  toggleSavedUrlExpandedState() {
    this.savedUrlsExpanded.update((v) => !v);
  }

  close() {
    void this.dialogRef.close(AutofillConfirmationDialogResult.Canceled);
  }

  autofillAndAddUrl() {
    void this.dialogRef.close(AutofillConfirmationDialogResult.AutofillAndUrlAdded);
  }

  autofillOnly() {
    void this.dialogRef.close(AutofillConfirmationDialogResult.AutofilledOnly);
  }

  static open(
    dialogService: DialogService,
    config: DialogConfig<AutofillConfirmationDialogParams>,
  ) {
    return dialogService.open<AutofillConfirmationDialogResultType>(
      AutofillConfirmationDialogComponent,
      { ...config },
    );
  }
}
