import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';

export interface HlmPasswordStrengthRules {
  minLength?: number;
  digit?: boolean;
  specialCharacter?: boolean;
  lowerCase?: boolean;
  upperCase?: boolean;
}

interface RuleEvaluation {
  key: keyof HlmPasswordStrengthRules;
  label: string;
  passed: boolean;
}

const RULE_LABELS: Record<keyof HlmPasswordStrengthRules, string> = {
  minLength: 'Min length',
  digit: 'Digit',
  specialCharacter: 'Special character',
  lowerCase: 'Lowercase',
  upperCase: 'Uppercase',
};

const SPECIAL_CHAR_REGEX = /[!@#$%^&*()+_\-=}{[\]|:;"/?.><,`~]/;

/**
 * Visual indicator of how many password rules a candidate satisfies.
 *
 * Renders a horizontally-segmented bar (one segment per active rule, filled
 * when the rule passes) and a checklist below. Color of the bar transitions
 * red → yellow → green as the ratio of satisfied rules increases.
 *
 * Pure presentation: the host is responsible for validation/business logic.
 *
 * @example
 * <au-hlm-password-strength
 *   [password]="form.controls.password.value"
 *   [rules]="{ minLength: 8, digit: true, specialCharacter: true, lowerCase: true, upperCase: true }"
 * />
 */
@Component({
  selector: 'au-hlm-password-strength',
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: { class: 'block w-full' },
  template: `
    @let total = totalActiveRules();
    @let passed = passedRules().length;
    <div
      role="progressbar"
      class="grid w-full grid-flow-col gap-1"
      [attr.aria-valuenow]="passed"
      [attr.aria-valuemin]="0"
      [attr.aria-valuemax]="total"
    >
      @for (segment of segments(); track segment.index) {
        <div
          class="h-1 rounded-full transition-colors"
          [class]="segment.passed ? barColorClass() : 'bg-muted'"
        ></div>
      }
    </div>

    <ul class="mt-2 space-y-0.5 text-xs">
      @for (rule of evaluations(); track rule.key) {
        <li class="flex items-center gap-2">
          <span
            aria-hidden="true"
            class="inline-flex h-3 w-3 items-center justify-center rounded-full text-[0.6rem] font-bold"
            [class]="rule.passed ? 'bg-green-500 text-white' : 'bg-muted text-muted-foreground'"
          >
            {{ rule.passed ? '✓' : '✗' }}
          </span>
          <span [class]="rule.passed ? 'text-foreground' : 'text-muted-foreground'">
            {{ rule.label }}
          </span>
        </li>
      }
    </ul>
  `,
})
export class HlmPasswordStrength {
  readonly password = input<string>('');
  readonly rules = input<HlmPasswordStrengthRules>({});

  protected readonly evaluations = computed<RuleEvaluation[]>(() => {
    const value = this.password() ?? '';
    const rules = this.rules();
    const items: RuleEvaluation[] = [];

    if (rules.minLength != null) {
      items.push({
        key: 'minLength',
        label: `${RULE_LABELS.minLength} (${rules.minLength})`,
        passed: value.length >= rules.minLength,
      });
    }
    if (rules.digit) {
      items.push({ key: 'digit', label: RULE_LABELS.digit, passed: /[0-9]/.test(value) });
    }
    if (rules.specialCharacter) {
      items.push({
        key: 'specialCharacter',
        label: RULE_LABELS.specialCharacter,
        passed: SPECIAL_CHAR_REGEX.test(value),
      });
    }
    if (rules.lowerCase) {
      items.push({ key: 'lowerCase', label: RULE_LABELS.lowerCase, passed: /[a-z]/.test(value) });
    }
    if (rules.upperCase) {
      items.push({ key: 'upperCase', label: RULE_LABELS.upperCase, passed: /[A-Z]/.test(value) });
    }

    return items;
  });

  protected readonly totalActiveRules = computed(() => this.evaluations().length);

  protected readonly passedRules = computed(() => this.evaluations().filter((rule) => rule.passed));

  protected readonly segments = computed(() => {
    const evals = this.evaluations();
    return evals.map((evaluation, index) => ({
      index,
      passed: evaluation.passed,
    }));
  });

  protected readonly barColorClass = computed(() => {
    const total = this.totalActiveRules();
    const passed = this.passedRules().length;
    if (total === 0) return 'bg-muted';
    const ratio = passed / total;
    if (ratio < 0.5) return 'bg-red-500';
    if (ratio < 1) return 'bg-yellow-500';
    return 'bg-green-500';
  });
}

export const HlmPasswordStrengthImports = [HlmPasswordStrength] as const;
