import { CommonModule } from '@angular/common';
import { Component, OnInit, Input, Output, EventEmitter, inject } from '@angular/core';
import { ReactiveFormsModule, FormGroup, FormControl, Validators, FormArray, AbstractControl } from '@angular/forms';
import { DynamicFormConfig } from './dynamic-form-config';
import { DynamicField } from './dynamic-field';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { provideNativeDateAdapter } from '@angular/material/core';
import { ConfirmDialogComponent } from '../confirm-dialog/confirm-dialog';

@Component({
  selector: "app-dynamic-form",
  templateUrl: "./dynamic-form.html",
  standalone: true,
  styleUrls: ['./dynamic-form.scss'],
  providers: [provideNativeDateAdapter()],
  imports: [ReactiveFormsModule, CommonModule, MatFormFieldModule, MatInputModule, MatSelectModule, MatButtonModule, MatIconModule, MatDatepickerModule, MatDialogModule]
})
export class DynamicFormComponent implements OnInit {
  @Input() config!: DynamicFormConfig;
  @Input() initialData: Record<string, unknown> = {};

  @Output() formBuilt = new EventEmitter<FormGroup>();

  private dialog = inject(MatDialog);

  form!: FormGroup;

  ngOnInit() {
    const group: Record<string, AbstractControl> = {};

      this.config.fields.forEach(f => {
    if (f.type === "array") {
      group[f.name] = new FormArray(
        this.initialData[f.name] && Array.isArray(this.initialData[f.name])
          ? (this.initialData[f.name] as unknown[]).map((item: unknown) =>
              this.buildArrayItem(f.itemConfig!, item)
            )
          : [this.buildArrayItem(f.itemConfig!, {})]
      );
    } else {
      group[f.name] = new FormControl(
        this.initialData[f.name] || "",
        f.required ? Validators.required : null
      );
    }
  });

    this.form = new FormGroup(group);
    this.formBuilt.emit(this.form);
  }

  buildArrayItem(config: DynamicField[], item: unknown) {
  const group: Record<string, FormControl> = {};

  config.forEach(f => {
    group[f.name] = new FormControl(
      (item as Record<string, unknown>)[f.name] || "",
      f.required ? Validators.required : null
    );
  });

  return new FormGroup(group);
}

addArrayItem(field: DynamicField) {
  const array = this.form.get(field.name) as FormArray;
  array.push(this.buildArrayItem(field.itemConfig!, {}));
}

removeArrayItem(field: DynamicField, index: number) {
  const array = this.form.get(field.name) as FormArray;

  this.dialog.open(ConfirmDialogComponent, {
    data: {
      title: 'Remove Item',
      message: `Are you sure you want to remove this ${field.label?.toLowerCase() ?? 'item'}?`,
      confirmLabel: 'Remove',
      confirmColor: 'warn'
    },
    panelClass: 'dark-popup-panel',
    width: '400px'
  }).afterClosed().subscribe((confirmed: boolean) => {
    if (confirmed) {
      array.removeAt(index);
    }
  });
}

  getArrayControls(name: string): AbstractControl[] {
    return (this.form.get(name) as FormArray).controls;
  }

  onFileChange(e: Event, field: string) {
    const target = e.target as HTMLInputElement;
    if (target?.files?.length) {
      const file = target.files[0];
      this.form.patchValue({ [field]: file });
    }
  }

  private yearOptionsCache = new Map<string, (number | string)[]>();

  getYearOptions(field: DynamicField): (number | string)[] {
    const asString = field.yearRange?.valueType === 'string';
    const key = `${field.name}_${field.yearRange?.start}_${field.yearRange?.end}_${asString}`;
    if (this.yearOptionsCache.has(key)) return this.yearOptionsCache.get(key)!;

    const currentYear = new Date().getFullYear();
    const start = field.yearRange?.start ?? (currentYear - 50);
    const end = field.yearRange?.end ?? (currentYear + 5);
    const years: (number | string)[] = [];
    for (let y = end; y >= start; y--) {
      years.push(asString ? y.toString() : y);
    }
    this.yearOptionsCache.set(key, years);
    return years;
  }

  compareYearValues = (a: unknown, b: unknown): boolean => {
    if (a == null && b == null) return true;
    if (a == null || b == null) return false;
    return a.toString() === b.toString();
  };
}
