import { Component, ElementRef, computed, input, output, signal, viewChild } from '@angular/core';

let nextId = 0;

/** Friendly labels for the MIME types the backend sends in `acceptedTypes`. */
const TYPE_LABELS: Record<string, string> = {
  'application/pdf': 'PDF',
  'image/jpeg': 'JPG',
  'image/jpg': 'JPG',
  'image/png': 'PNG',
  'application/msword': 'Word',
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'Word',
};

/** Atom: the CIBG Huisstijl **Bestand-upload** control
    (designsystem.cibg.nl/componenten/bestand-upload) — a `.file-picker-drop-area`
    with an always-visible instruction (allowed types + max size), a real
    `.btn-upload` button, and a visually-hidden native `<input type="file">`. Supports
    click-to-pick and drag-and-drop; resets its value after each change so re-picking
    the same file re-fires. The instruction is linked to the input via
    `aria-describedby` (pattern requirement). Pure UI — no validation, no upload. */
@Component({
  selector: 'app-file-input',
  styles: [
    `
      :host {
        display: block;
      }
      .file-picker-drop-area {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        gap: var(--rhc-space-max-sm);
      }
      /* Default (not subtle) foreground: subtle grey on the grey drop-area fails WCAG AA contrast. */
      .upload-instructions {
        margin: 0;
        color: var(--rhc-color-foreground-default);
        font-size: var(--rhc-text-font-size-sm);
      }
      /* Solid CIBG-blue button; the .btn-upload ::before folder glyph is the icon, so
       drop its redundant centred background-image folder. */
      .btn-upload {
        cursor: pointer;
        background-image: none;
      }
      .btn-upload.disabled {
        cursor: not-allowed;
      }
      /* The input is visually hidden but still focusable; surface its focus on the button. */
      input:focus-visible + .btn-upload {
        outline: var(--rhc-border-width-md) solid var(--rhc-color-foreground-link);
        outline-offset: 2px;
      }
    `,
  ],
  template: `
    <div
      class="file-picker-drop-area"
      [class.drag-over]="dragging()"
      (dragover)="onDragOver($event)"
      (dragleave)="onDragLeave($event)"
      (drop)="onDrop($event)"
    >
      @if (instructions()) {
        <p class="upload-instructions" [id]="instructionsId">{{ instructions() }}</p>
      }
      <input
        #fileInput
        class="visually-hidden"
        type="file"
        [id]="inputId()"
        [attr.aria-label]="label()"
        [attr.aria-describedby]="instructions() ? instructionsId : null"
        [accept]="accept().join(',')"
        [multiple]="multiple()"
        [disabled]="disabled()"
        (change)="onChange($event)"
      />
      <label
        class="btn btn-primary btn-upload"
        [class.disabled]="disabled()"
        [attr.for]="inputId()"
      >
        {{ buttonText() }}
      </label>
    </div>
  `,
})
export class FileInputComponent {
  accept = input<string[]>([]);
  multiple = input(false);
  disabled = input(false);
  maxSizeMb = input(0);
  inputId = input.required<string>();
  /** Accessible name for the input; the domain caller supplies a per-category label. */
  label = input($localize`:@@upload.fileInput.label:Bestand kiezen`);

  filesSelected = output<File[]>();

  protected readonly instructionsId = `upload-instructions-${nextId++}`;
  protected readonly dragging = signal(false);

  private fileInput = viewChild.required<ElementRef<HTMLInputElement>>('fileInput');

  protected buttonText = computed(() =>
    this.multiple()
      ? $localize`:@@upload.fileInput.addMany:Bestanden toevoegen`
      : $localize`:@@upload.fileInput.addOne:Bestand toevoegen`,
  );

  /** Always-visible instruction: allowed file types + max size (CIBG pattern). */
  protected instructions = computed(() => {
    const types = this.accept()
      .map((m) => TYPE_LABELS[m] ?? m.split('/').pop()?.toUpperCase() ?? m)
      .join(', ');
    const size = this.maxSizeMb();
    if (types && size > 0)
      return $localize`:@@upload.fileInput.instrBoth:Toegestaan: ${types}:types: · max ${size}:size: MB`;
    if (types) return $localize`:@@upload.fileInput.instrTypes:Toegestaan: ${types}:types:`;
    if (size > 0) return $localize`:@@upload.fileInput.instrSize:Max ${size}:size: MB`;
    return '';
  });

  onChange(event: Event) {
    const input = event.target as HTMLInputElement;
    this.filesSelected.emit(Array.from(input.files ?? []));
    this.fileInput().nativeElement.value = '';
  }

  onDragOver(event: DragEvent) {
    if (this.disabled()) return;
    event.preventDefault(); // allow drop
    this.dragging.set(true);
  }
  onDragLeave(event: DragEvent) {
    event.preventDefault();
    this.dragging.set(false);
  }
  onDrop(event: DragEvent) {
    event.preventDefault();
    this.dragging.set(false);
    if (this.disabled()) return;
    const files = Array.from(event.dataTransfer?.files ?? []);
    if (files.length) this.filesSelected.emit(files);
  }
}
