import {
  Component,
  computed,
  ElementRef,
  HostBinding,
  HostListener,
  inject,
  input,
} from "@angular/core";

import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";

type CharacterType = "letter" | "emoji" | "special" | "number";

/**
 * The color password is used primarily in the Generator pages and in the Login type form. It includes
 * the logic for displaying letters as `text-main`, numbers as `primary`, and special symbols as
 * `danger`.
 */
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
  selector: "bit-color-password",
  template: `@for (character of passwordCharArray(); track $index; let i = $index) {
    <span [class]="getCharacterClass(character)" class="tw-font-mono" data-password-character>
      <span>{{ character }}</span>
      @if (showCount()) {
        <span class="tw-whitespace-nowrap tw-text-xs tw-leading-5 tw-text-main">{{ i + 1 }}</span>
      }
    </span>
  }`,
})
export class ColorPasswordComponent {
  readonly password = input<string>("");
  readonly showCount = input<boolean>(false);

  // Convert to an array to handle cases that strings have special characters, i.e.: emoji.
  readonly passwordCharArray = computed(() => {
    return Array.from(this.password() ?? "");
  });

  private platformUtilsService = inject(PlatformUtilsService);
  private elementRef = inject(ElementRef);

  characterStyles: Record<CharacterType, string[]> = {
    emoji: [],
    letter: ["tw-text-main"],
    special: ["tw-text-danger"],
    number: ["tw-text-primary-600"],
  };

  @HostBinding("class")
  get classList() {
    return ["tw-min-w-0", "tw-whitespace-pre-wrap", "tw-break-words"];
  }

  getCharacterClass(character: string) {
    const charType = this.getCharacterType(character);
    const charClass = this.characterStyles[charType];

    if (this.showCount()) {
      return charClass.concat([
        "tw-inline-flex",
        "tw-flex-col",
        "tw-items-center",
        "tw-w-7",
        "tw-py-1",
        "odd:tw-bg-secondary-100",
        "even:tw-bg-background",
      ]);
    }

    return charClass;
  }

  private getCharacterType(character: string): CharacterType {
    if (character.match(Utils.regexpEmojiPresentation)) {
      return "emoji";
    }

    if (character.match(/\d/)) {
      return "number";
    }

    const specials = ["&", "<", ">", " "];
    if (specials.includes(character) || character.match(/[^\w ]/)) {
      return "special";
    }

    return "letter";
  }

  @HostListener("copy", ["$event"])
  onCopy(event: ClipboardEvent) {
    event.preventDefault();
    const selection = window.getSelection();
    if (!selection || selection.rangeCount === 0) {
      return;
    }

    const spanElements = this.elementRef.nativeElement.querySelectorAll(
      "span[data-password-character]",
    );
    let copiedText = "";

    spanElements.forEach((span: HTMLElement, index: number) => {
      if (selection.containsNode(span, true)) {
        copiedText += this.passwordCharArray()[index];
      }
    });

    if (copiedText) {
      this.platformUtilsService.copyToClipboard(copiedText);
    }
  }
}
