import { Component, EventEmitter, inject, Input, Output, OnInit, ElementRef, OnDestroy } from '@angular/core';
import { DynamicFormComponent } from '../dynamic-form/dynamic-form';
import { CommonModule } from '@angular/common';
import { DynamicFormConfig } from '../dynamic-form/dynamic-form-config';
import { FormGroup } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { environment } from '../../../environments/environment';

@Component({
  selector: "app-dynamic-popup",
  templateUrl: "./dynamic-popup.html",
  styleUrls: ['./dynamic-popup.scss'],
  standalone: true,
  imports: [DynamicFormComponent, CommonModule]
})
export class DynamicPopupComponent implements OnInit, OnDestroy {

  @Input() config!: DynamicFormConfig;
  @Input() data: Record<string, unknown> = {};
  form!: FormGroup;

  @Output() saved = new EventEmitter<unknown>();
  readonly http = inject(HttpClient);
  private dialogRef = inject(MatDialogRef, { optional: true }) as unknown as MatDialogRef<DynamicPopupComponent> | null;
  private injectedDialogData = inject(MAT_DIALOG_DATA, { optional: true }) as { config?: DynamicFormConfig; data?: Record<string, unknown> } | undefined;
  private el = inject(ElementRef);
  private focusableElements: HTMLElement[] = [];
  private keydownHandler?: (e: KeyboardEvent) => void;
  titleId = `popup-title-${Math.random().toString(36).slice(2,9)}`;

  ngOnInit(): void {
    if (this.injectedDialogData) {
      if (this.injectedDialogData.config) {
        this.config = this.injectedDialogData.config;
      }
      if (this.injectedDialogData.data) {
        this.data = this.injectedDialogData.data;
      }
    }
    // setup focus trap
    this.keydownHandler = (e: KeyboardEvent) => this.onKeyDown(e);
    this.el.nativeElement.addEventListener('keydown', this.keydownHandler as EventListener);
  }

  onFormBuilt(f: FormGroup) {
    this.form = f;
    setTimeout(() => {
      // collect focusable elements inside this component
      const nodes = this.el.nativeElement.querySelectorAll('button, a, input, textarea, select, [tabindex]:not([tabindex="-1"])') as NodeListOf<HTMLElement>;
      this.focusableElements = Array.from(nodes).filter(n => !n.hasAttribute('disabled'));
      if (this.focusableElements.length) {
        this.focusableElements[0].focus();
      }
    }, 0);
  }

  submit() {
    let payload: unknown;

    if (this.containsFile()) {
      payload = new FormData();
      Object.keys(this.form.value).forEach(k => {
        (payload as FormData).append(k, this.form.value[k]);
      });
    } else {
      payload = this.form.value;
    }

    // If no API configured, just close with form value
    if (!this.config.api?.save) {
      this.saved.emit(payload);
      if (this.dialogRef) {
        this.dialogRef.close(payload);
      } else {
        this.close();
      }
      return;
    }

    const url = this.resolveApiUrl(this.config.api.save as string);

    let apiBody = payload;
    if (this.config.api.bodyKey && payload && typeof payload === 'object' && !(payload instanceof FormData)) {
      apiBody = (payload as Record<string, unknown>)[this.config.api.bodyKey];
    }

    this.http.request(
      this.config.api.method,
      url,
      { body: apiBody }
    ).subscribe(res => {
      this.saved.emit(res);
      if(this.dialogRef){
        this.dialogRef.close(res);
      } else {
        this.close();
      }
    });
  }

  private resolveApiUrl(path: string) {
    if (!path) return path;
    if (/^https?:\/\//i.test(path)) return path;
    const base = (environment.apiUrl || '').replace(/\/$/, '');
    return `${base}/${path.replace(/^\//, '')}`;
  }

  containsFile() {
    return this.config.fields.some(f => f.type === "file");
  }

  close() {
    this.saved.emit(null);
    if(this.dialogRef){
      this.dialogRef.close(null);
    }
  }

  onKeyDown(e: KeyboardEvent){
    if (e.key !== 'Tab') return;
    if (!this.focusableElements.length) return;

    const first = this.focusableElements[0];
    const last = this.focusableElements[this.focusableElements.length - 1];

    if (e.shiftKey) {
      if (document.activeElement === first) {
        e.preventDefault();
        last.focus();
      }
    } else {
      if (document.activeElement === last) {
        e.preventDefault();
        first.focus();
      }
    }
  }

  ngOnDestroy(): void {
    if (this.keydownHandler) {
      this.el.nativeElement.removeEventListener('keydown', this.keydownHandler as EventListener);
    }
  }
}
