import { CommonModule } from '@angular/common';
import {
  AfterViewInit,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  EventEmitter,
  Input,
  Output,
  computed,
  signal,
  OnInit,
  OnDestroy,
  effect,
} from '@angular/core';
import {
  FormBuilder,
  FormControl,
  FormGroup,
  ReactiveFormsModule,
  Validators,
} from '@angular/forms';
import { ZardFormModule } from '@shared/components/form/form.module';
import { ZardInputDirective } from '@shared/components/input/input.directive';
import { ZardSelectItemComponent } from '@shared/components/select/select-item.component';
import { ZardSelectComponent } from '@shared/components/select/select.component';
import { Course, CourseStatut, CourseType } from 'src/app/core/interfaces/course';
import { Reunion } from 'src/app/core/interfaces/reunion';
import { ReunionService } from 'src/app/core/services/reunion';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-course-form',
  standalone: true,
  templateUrl: './course-form.html',
  styleUrls: ['./course-form.css'],
  imports: [
    CommonModule,
    ReactiveFormsModule,
    ZardFormModule,
    ZardInputDirective,
    ZardSelectComponent,
    ZardSelectItemComponent,
  ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CourseForm implements OnInit, AfterViewInit, OnDestroy {
  @Output() save = new EventEmitter<Course>();
  @Output() cancel = new EventEmitter<void>();

  private _value?: Course;
  @Input() set value(v: Course | undefined) {
    this._value = v;
  }
  get value(): Course | undefined {
    return this._value;
  }

  form: FormGroup;
  submitted = false;

  reunions = signal<Reunion[]>([]);
  loadingReunions = signal(false);
  searchQuery = signal<string>('');
  selectedReunionLabel = signal<string>('');
  initializing = signal(false);
  private subs = new Subscription();

  constructor(
    private fb: FormBuilder,
    private reunionService: ReunionService,
    private cdr: ChangeDetectorRef
  ) {
    this.form = this.fb.group({
      type: ['', Validators.required],
      numero: [null, [Validators.required, Validators.min(1)]],
      nom: ['', [Validators.required, Validators.minLength(3)]],
      dateDepartCourse: ['', Validators.required],
      dateDebutParis: ['', Validators.required],
      dateFinParis: ['', Validators.required],
      reunionId: new FormControl<string | null>(null, Validators.required),
      reunionCourse: [1],
      particularite: [''],
      partants: [null, [Validators.required, Validators.min(1)]],
      distance: [''],
      condition: [''],
      statut: [CourseStatut.PROGRAMMEE, Validators.required],
      createdBy: ['agent-001'],
      validatedBy: [''],
    });

    // Watch for reunionId changes to update the label
    // This handles BOTH create and edit modes when user selects a reunion
    this.subs.add(
      this.form.get('reunionId')?.valueChanges.subscribe((reunionId) => {
        // Skip if we're initializing (to avoid interfering with form initialization)
        if (this.initializing()) {
          return;
        }

        // Handle empty/null values
        if (!reunionId || reunionId === '') {
          this.selectedReunionLabel.set('');
          return;
        }

        // Update label when user selects a reunion (both create and edit)
        if (this.reunions().length > 0) {
          // Try both string and direct comparison since form control might convert types
          const matchingReunion = this.reunions().find(
            (r) => String(r.id) === String(reunionId) || r.id === reunionId
          );
          if (matchingReunion) {
            const reunionLabel = `${matchingReunion.nom} – ${matchingReunion.hippodrome.nom} (${matchingReunion.hippodrome.ville})`;
            this.selectedReunionLabel.set(reunionLabel);
            // Force change detection to ensure the label is displayed immediately
            this.cdr.markForCheck();
          } else {
            this.selectedReunionLabel.set('');
          }
        } else {
          this.selectedReunionLabel.set('');
        }
      }) || new Subscription()
    );

    // Effect to handle form initialization when value or reunions change
    effect(() => {
      const v = this.value;
      const reunionsList = this.reunions();
      const isLoading = this.loadingReunions();

      // CRITICAL: Enable/disable reunion control based on loading state
      // This is the most important part for create mode to work
      const reunionControl = this.form.get('reunionId');
      if (isLoading) {
        reunionControl?.disable({ emitEvent: false });
      } else {
        reunionControl?.enable({ emitEvent: false });
        // Force change detection after enabling to ensure the select is clickable
        this.cdr.markForCheck();
      }

      // Handle edit mode (value is defined) - populate form with course data
      if (v !== null && v !== undefined) {
        this.initializing.set(true);

        let reunionId: string | null = null;
        let reunionLabel: string = '';
        if (v.reunion?.id) {
          reunionId = String(v.reunion.id);
          if (reunionsList.length > 0) {
            const matchingReunion = reunionsList.find((r) => String(r.id) === reunionId);
            if (matchingReunion) {
              reunionLabel = `${matchingReunion.nom} – ${matchingReunion.hippodrome.nom} (${matchingReunion.hippodrome.ville})`;
              this.selectedReunionLabel.set(reunionLabel);
            } else {
              reunionId = null;
              this.selectedReunionLabel.set('');
            }
          } else {
            if (v.reunion.nom) {
              reunionLabel = `${v.reunion.nom} – ${v.reunion.hippodrome?.nom || ''} (${
                v.reunion.hippodrome?.ville || ''
              })`;
              this.selectedReunionLabel.set(reunionLabel);
            }
            reunionId = null;
          }
        } else {
          this.selectedReunionLabel.set('');
        }

        this.form.patchValue(
          {
            type: v.type ?? '',
            numero: v.numero ?? null,
            nom: v.nom ?? '',
            dateDepartCourse: v.dateDepartCourse ?? '',
            dateDebutParis: v.dateDebutParis ?? v.dateDepartCourse ?? '',
            dateFinParis: v.dateFinParis ?? v.dateDepartCourse ?? '',
            reunionId,
            reunionCourse: (v as any).reunionCourse ?? v.numero ?? 1,
            particularite: (v as any).particularite ?? '',
            partants: (v as any).partants ?? null,
            distance: (v as any).distance ?? null,
            condition: (v as any).condition ?? '',
            statut: v.statut ?? CourseStatut.PROGRAMMEE,
            createdBy: (v as any).createdBy ?? 'agent-001',
            validatedBy: (v as any).validatedBy ?? '',
          },
          { emitEvent: false }
        );

        this.form.markAsPristine();
        this.form.markAsUntouched();
        queueMicrotask(() => this.initializing.set(false));
      }
      // Create mode (v === null or undefined) - DO NOTHING except ensure control is enabled
      // The form already has default values, just let the user fill it
      // The valueChanges subscription will handle label updates when user selects

      // When reunions finish loading - re-apply value if we have one (for edit mode)
      else if (reunionsList.length > 0 && !isLoading) {
        // Reunions just finished loading - re-apply value if we have one
        const currentValue = this.value;
        if (currentValue?.reunion?.id) {
          const reunionId = String(currentValue.reunion.id);
          const matchingReunion = reunionsList.find((r) => String(r.id) === reunionId);
          if (matchingReunion) {
            // Set the label manually
            const reunionLabel = `${matchingReunion.nom} – ${matchingReunion.hippodrome.nom} (${matchingReunion.hippodrome.ville})`;
            this.selectedReunionLabel.set(reunionLabel);
            // Wait for Angular to render the select items
            setTimeout(() => {
              this.form.patchValue({ reunionId }, { emitEvent: false });
              this.cdr.detectChanges();
            }, 50);
          }
        }
      }
    });
  }

  private hydrateFromValue(v?: Course) {
    if (v) {
      const patch = {
        type: v.type ?? '',
        numero: v.numero ?? null,
        nom: v.nom ?? '',
        dateDepartCourse: v.dateDepartCourse ?? '',
        dateDebutParis: v.dateDebutParis ?? v.dateDepartCourse ?? '',
        dateFinParis: v.dateFinParis ?? v.dateDepartCourse ?? '',
        reunionId: (v as any).reunionId ?? v.reunion?.id ?? '',
        reunionCourse: (v as any).reunionCourse ?? v.numero ?? 1,
        particularite: (v as any).particularite ?? '',
        partants: (v as any).partants ?? null,
        distance: (v as any).distance ?? null,
        condition: (v as any).condition ?? '',
        statut: v.statut ?? CourseStatut.PROGRAMMEE,
        createdBy: (v as any).createdBy ?? 'agent-001',
        validatedBy: (v as any).validatedBy ?? '',
      };
      this.form.reset(patch);
      this.form.markAsPristine();
      this.form.markAsUntouched();
    } else {
      this.form.reset({
        type: '',
        numero: null,
        nom: '',
        dateDepartCourse: '',
        dateDebutParis: '',
        dateFinParis: '',
        reunionId: '',
        reunionCourse: 1,
        particularite: '',
        partants: null,
        distance: null,
        condition: '',
        statut: CourseStatut.PROGRAMMEE,
        createdBy: 'agent-001',
        validatedBy: '',
      });
      this.form.markAsPristine();
      this.form.markAsUntouched();
    }
  }

  isInvalid(control: string): boolean {
    const ctrl = this.form.get(control);
    return !!(ctrl && ctrl.invalid && (ctrl.touched || this.submitted));
  }

  errorMessage(control: string): string | null {
    const c = this.form.get(control);
    if (!c || !c.errors) return null;
    if (c.errors['required']) return 'Ce champ est obligatoire';
    if (c.errors['minlength']) return `Minimum ${c.errors['minlength'].requiredLength} caractères`;
    if (c.errors['min']) return `Valeur minimale : ${c.errors['min'].min}`;
    return null;
  }

  getDatePart(control: string): string {
    const val = this.form.get(control)?.value;
    return val ? new Date(val).toISOString().slice(0, 10) : '';
  }

  getTimePart(control: string): string {
    const val = this.form.get(control)?.value;
    if (!val) return '';
    const d = new Date(val);
    return d.toISOString().slice(11, 16);
  }

  setDatePart(control: string, date: string) {
    const current = new Date(this.form.get(control)?.value || new Date());
    const [h, m] = [current.getHours(), current.getMinutes()];
    const newDate = new Date(
      `${date}T${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:00Z`
    );
    this.form.patchValue({ [control]: newDate.toISOString() });
  }

  setTimePart(control: string, time: string) {
    const current = new Date(this.form.get(control)?.value || new Date());
    const [h, m] = time.split(':').map(Number);
    current.setHours(h, m);
    this.form.patchValue({ [control]: current.toISOString() });
  }

  onSubmit() {
    this.submitted = true;
    if (!this.form.valid) {
      this.form.markAllAsTouched();
      return;
    }

    const raw = this.form.getRawValue() as any;

    // Find the reunion object from the reunions list
    const reunionId = raw.reunionId;
    const reunion = this.reunions().find((r) => String(r.id) === String(reunionId));

    if (!reunion) {
      console.error('Reunion not found:', reunionId);
      return;
    }

    const payload: Partial<Course> = {
      ...(this.value ?? {}),
      type: raw.type,
      numero: +raw.numero,
      nom: raw.nom,
      dateDepartCourse: raw.dateDepartCourse,
      dateDebutParis: raw.dateDebutParis,
      dateFinParis: raw.dateFinParis,
      reunion: reunion!, // Will be set if reunion is found
      reunionCourse: +raw.reunionCourse,
      particularite: raw.particularite ?? '',
      partants: +raw.partants,
      distance: +raw.distance,
      condition: raw.condition ?? '',
      statut: raw.statut,
      createdBy: raw.createdBy,
      validatedBy: raw.validatedBy || null,
    };

    // Ensure reunion is found
    if (!reunion) {
      console.error('Reunion not found:', reunionId);
      return;
    }

    this.save.emit(payload as Course);
  }

  // === Filter Reunions ===
  filteredReunions = computed(() => {
    const q = this.searchQuery().toLowerCase();
    return this.reunions().filter(
      (r) =>
        r.nom.toLowerCase().includes(q) ||
        r.hippodrome.nom.toLowerCase().includes(q) ||
        r.hippodrome.ville.toLowerCase().includes(q)
    );
  });

  courseTypes = [
    { label: 'Tiercé', value: CourseType.TIERCE },
    { label: 'Quarté + Tiercé', value: CourseType.QUARTE },
    { label: 'Quinté + Tiercé', value: CourseType.QUINTE },
  ];

  courseStatus = [
    { label: 'Programmée', value: CourseStatut.PROGRAMMEE },
    { label: 'Créée', value: CourseStatut.CREATED },
    { label: 'Validée', value: CourseStatut.VALIDATED },
    { label: 'En cours', value: CourseStatut.RUNNING },
    { label: 'Clôturée', value: CourseStatut.CLOSED },
    { label: 'Annulée', value: CourseStatut.CANCELED },
  ];

  ngOnInit() {
    // Fetch reunions from API
    this.loadingReunions.set(true);
    this.subs.add(
      this.reunionService.list({ page: 1, perPage: 1000 }, false).subscribe({
        next: (result) => {
          this.reunions.set(result.data);
          this.loadingReunions.set(false);
          // Force enable the control after loading
          setTimeout(() => {
            const reunionControl = this.form.get('reunionId');
            reunionControl?.enable({ emitEvent: false });
            this.cdr.markForCheck();
          }, 100);
        },
        error: (err) => {
          console.error('Error loading reunions:', err);
          this.loadingReunions.set(false);
        },
      })
    );
  }

  ngAfterViewInit() {
    // After view is initialized, ensure the reunion value and label are set correctly
    const currentValue = this.value;
    if (currentValue?.reunion?.id && this.reunions().length > 0) {
      const reunionId = String(currentValue.reunion.id);
      const matchingReunion = this.reunions().find((r) => String(r.id) === reunionId);
      if (matchingReunion) {
        // Set the label manually
        const reunionLabel = `${matchingReunion.nom} – ${matchingReunion.hippodrome.nom} (${matchingReunion.hippodrome.ville})`;
        this.selectedReunionLabel.set(reunionLabel);
        // Wait a bit for the select items to be fully rendered
        setTimeout(() => {
          const currentFormValue = this.form.get('reunionId')?.value;
          if (String(currentFormValue) !== reunionId) {
            this.form.patchValue({ reunionId }, { emitEvent: false });
            this.cdr.detectChanges();
          }
        }, 100);
      }
    }
  }

  onReunionSelectionChange(value: string) {
    // Immediately update the label when user selects a reunion
    if (value && this.reunions().length > 0) {
      const matchingReunion = this.reunions().find(
        (r) => String(r.id) === String(value) || r.id === value
      );
      if (matchingReunion) {
        const reunionLabel = `${matchingReunion.nom} – ${matchingReunion.hippodrome.nom} (${matchingReunion.hippodrome.ville})`;
        this.selectedReunionLabel.set(reunionLabel);
        this.cdr.markForCheck();
      } else {
      }
    }
  }

  ngOnDestroy() {
    this.subs.unsubscribe();
  }
}
