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 { Subscription } from 'rxjs';

import { Hippodrome } from 'src/app/core/interfaces/hippodrome';
import { Course, CourseStatut, CourseType } from 'src/app/core/interfaces/course';
import { HippodromeService } from 'src/app/core/services/hippodrome';
import { CourseApiResponse, CourseService } from 'src/app/core/services/course';

@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;
    this.hydrateFromValue(v);
  }
  get value(): Course | undefined {
    return this._value;
  }

  form: FormGroup;
  submitted = false;

  hippodromes = signal<Hippodrome[]>([]);
  loadingHippodromes = signal(false);
  searchQuery = signal('');
  selectedHippodromeLabel = signal('');

  private subs = new Subscription();

  constructor(
    private fb: FormBuilder,
    private courseServive: CourseService,
    private hippodromeService: HippodromeService,
    private cdr: ChangeDetectorRef
  ) {
    this.form = this.fb.group({
      hippodromeId: new FormControl<string | null>(null, Validators.required),
      reunionNumero: [null, Validators.required],
      reunionDate: ['', Validators.required],
      nom: ['', Validators.required],
      numero: [null, Validators.required],
      statut: [CourseStatut.BROUILLON, Validators.required],
      heureDepartPrevue: ['', Validators.required],
      discipline: ['', Validators.required],
      distanceMetres: [null, Validators.required],
      nombrePartants: [null, Validators.required],
      annulee: [false],
      categorie: ['', Validators.required],
      reporteeMemeJour: [false],
      reporteeAutreJour: [false],
      incidentTechnique: [false],
      nonPartants: [[]],
      typesParisOuverts: [[], Validators.required],
      createdBy: ['agent-001'],
      validatedBy: [''],
    });

    /* =============================
       FIX 1 — Gestion enable/disable
       (cause principale du select bloqué)
    ============================== */
    effect(() => {
      const loading = this.loadingHippodromes();
      const control = this.form.get('hippodromeId');

      if (loading) {
        control?.disable({ emitEvent: false });
      } else {
        control?.enable({ emitEvent: false });
        this.cdr.markForCheck();
      }

      // Edit mode : appliquer la valeur APRÈS chargement
      if (this.value && this.hippodromes().length) {
        const id = String(this.value.hippodrome?.id ?? '');
        if (id) {
          this.form.patchValue({ hippodromeId: id }, { emitEvent: false });

          const h = this.hippodromes().find(r => String(r.id) === id);
          if (h) {
            this.selectedHippodromeLabel.set(`${h.nom} – (${h.ville})`);
          }
        }
      }
    });

    /* =============================
       FIX 2 — valueChanges propre
    ============================== */
    this.subs.add(
      this.form.get('hippodromeId')!.valueChanges.subscribe((id) => {
        if (!id) {
          this.selectedHippodromeLabel.set('');
          return;
        }

        const h = this.hippodromes().find(r => String(r.id) === String(id));
        if (h) {
          this.selectedHippodromeLabel.set(`${h.nom} – (${h.ville})`);
          this.cdr.markForCheck();
        }
      })
    );
  }

  /* =============================
     FIX 3 — vrai filter
  ============================== */
  filteredHippodromes = computed(() => {
    const q = this.searchQuery().toLowerCase();
    if (!q) return this.hippodromes();

    return this.hippodromes().filter(h =>
      h.nom.toLowerCase().includes(q) ||
      h.ville.toLowerCase().includes(q) ||
      (h as any).pays?.toLowerCase().includes(q)
    );
  });

  ngOnInit() {
    this.loadingHippodromes.set(true);

    this.subs.add(
      this.hippodromeService
        .list({ page: 0, size: 1000 }, true)
        .subscribe({
          next: (res) => {
            this.hippodromes.set(res.content);
            this.loadingHippodromes.set(false);
          },
          error: () => {
            this.loadingHippodromes.set(false);
          },
        })
    );
  }

  ngAfterViewInit() {
    this.cdr.markForCheck();
  }

     getDateCorrectFormat = (date: Date): string => {
      let hour = date.getHours().toString();
      let minutes = date.getMinutes().toString();
      hour = hour.length == 1? `0${hour}`: hour;
      minutes = minutes.length == 1? `0${minutes}`:minutes
      return `${hour}:${minutes}`
    };


  private hydrateFromValue(v?: Course) {
    if (!v) {
      // Reset to defaults
      this.form.reset({
        hippodromeId: '',
        reunionNumero: null,
        reunionDate: '',
        nom: '',
        numero: null,
        statut: CourseStatut.BROUILLON,
        heureDepartPrevue: '',
        discipline: '',
        distanceMetres: null,
        nombrePartants: null,
        annulee: false,
        categorie: '',
        reporteeMemeJour: false,
        reporteeAutreJour: false,
        incidentTechnique: false,
        nonPartants: [],
        typesParisOuverts: [],
      });
      this.selectedHippodromeLabel.set('');
      this.form.markAsPristine();
      this.form.markAsUntouched();
      // Ensure UI updates for cleared form
      this.cdr.markForCheck();
      return;
    }

    const hippodromeId = v.hippodrome?.id ? String(v.hippodrome.id) : '';

 

    this.form.patchValue(
      {
        hippodromeId,
        reunionNumero: v.reunionNumero ?? null,
        reunionDate: v.reunionDate ?? '',
        nom: v.nom ?? '',
        numero: v.numero ?? null,
        statut: v.statut ?? CourseStatut.BROUILLON,
        heureDepartPrevue: v.heureDepartPrevue? this.getDateCorrectFormat(new Date(v.heureDepartPrevue)) :'',
        discipline: v.discipline ?? '',
        distanceMetres: v.distanceMetres ?? null,
        nombrePartants: v.nombrePartants ?? null,
        annulee: v.annulee ?? false,
        categorie: v.categorie ?? '',
        reporteeMemeJour: v.reporteeMemeJour ?? false,
        reporteeAutreJour: v.reporteeAutreJour ?? false,
        incidentTechnique: v.incidentTechnique ?? false,
        nonPartants: v.nonPartants ?? [],
        typesParisOuverts: v.typesParisOuverts,
      },
      { emitEvent: false }
    );

    // Ensure view updates when hydrating values (OnPush component)
    this.cdr.markForCheck();

    // Set hippodrome label if available
    if (hippodromeId && this.hippodromes().length > 0) {
      const h = this.hippodromes().find((r) => String(r.id) === hippodromeId);
      if (h) this.selectedHippodromeLabel.set(`${h.nom} – (${h.ville})`);
      else if (v.hippodrome?.nom) this.selectedHippodromeLabel.set(`${v.hippodrome.nom} – (${v.hippodrome.ville || ''})`);
    } else if (v.hippodrome?.nom) {
      this.selectedHippodromeLabel.set(`${v.hippodrome.nom} – (${v.hippodrome.ville || ''})`);
    }

    this.form.markAsPristine();
    this.form.markAsUntouched();
  }

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

  onToggleType(event: Event) {
  const input = event.target as HTMLInputElement;
  const value = input.value;
  const current = this.form.value.typesParisOuverts ?? [];

  this.form.patchValue({
    typesParisOuverts: input.checked
      ? [...current, value]
      : current.filter((v: string) => v !== value)
  });

    // Trigger change detection so checkbox states update in OnPush mode
    this.cdr.markForCheck();
}


onSubmit() {
  this.submitted = true;

  if (this.form.invalid) {
    this.form.markAllAsTouched();
    return;
  }

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

  // 1️⃣ Résoudre l'hippodrome sélectionné
  const hippodromeId = raw.hippodromeId;
  const foundHippodrome = this.hippodromes().find(h => String(h.id) === String(hippodromeId));
  const hippodromeObj = foundHippodrome ?? (hippodromeId ? { id: +hippodromeId } : undefined);

  // 2️⃣ Transformer typesParisOuverts CSV → tablea

  // 3️⃣ Construire payload
  const payload: Partial<CourseApiResponse> = {
    ...this.value, // inclut les champs existants si édition
    hippodromeId: raw.hippodromeId,
    reunionNumero: raw.reunionNumero ? +raw.reunionNumero : undefined,
    reunionDate: raw.reunionDate,
    nom: raw.nom,
    numero: raw.numero ? +raw.numero : undefined,
    statut: raw.statut,
    discipline: raw.discipline,
    heureDepartPrevue: new Date(`${raw.reunionDate}T${raw.heureDepartPrevue}:00`).toISOString(),
    distanceMetres: raw.distanceMetres ? +raw.distanceMetres : undefined,
    nombrePartants: raw.nombrePartants ? +raw.nombrePartants : undefined,
    typesParisOuverts: raw.typesParisOuverts,
    annulee: raw.annulee ?? false,
    reporteeMemeJour: raw.reporteeMemeJour ?? false,
    reporteeAutreJour: raw.reporteeAutreJour ?? false,
    incidentTechnique: raw.incidentTechnique ?? false,
    nonPartants: raw.nonPartants ?? [],
    categorie: raw.categorie,
  };




  // Persist: create or update via CourseService, then emit the saved Course
  if (this.value && this.value.id) {
    this.courseServive.update(this.value.id, payload).subscribe({
      next: (updated) => {
        if (updated) this.save.emit(updated);
        else console.error('Update returned empty result');
      },
      error: (err) => {
        console.error('Error updating course:', err)},
    });
  } else {
    this.courseServive.create(payload).subscribe({
      next: (created) => this.save.emit(created),
      error: (err) => console.error('Error creating course:', err),
    });
  }
}



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;
}


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

  courseTypes = [
    { label: 'Gagnant', value: CourseType.GAGNANT },
    { label: 'Placé', value: CourseType.PLACE },
    { label: 'Jumélé gagnant', value: CourseType.JUMELE_GAGNANT},
    { label: 'Jumélé placé', value: CourseType.JUMELE_PLACE},
    { label: 'Jumélé ordre', value: CourseType.JUMELE_ORDRE},
    { label: 'Trio', value: CourseType.TRIO},
    { label: 'Trio ordre', value: CourseType.TRIO_ORDRE},
    { label: 'Triplet', value: CourseType.TRIPLET},
    { label: 'Quatro', value: CourseType.QUATRO},
    { label: 'Quinte', value: CourseType.QUINTE},
  ];


  courseStatus = [
    { label: 'Brouillon', value: CourseStatut.BROUILLON },
    { label: 'Validé', value: CourseStatut.VALIDE },
    { label: 'Fremé', value: CourseStatut.FERME },
    {label: 'Ouvert', value: CourseStatut.OUVERT},
    { label: 'Resultat Provisoire', value: CourseStatut.RESULTAT_PROVISOIRE },
    { label: 'Resultat officiel', value: CourseStatut.RESULTAT_OFFICIEL },
    { label: 'Reglée', value: CourseStatut.REGLEE },
    { label: 'Annulée', value: CourseStatut.ANNULEE },
  ];
}
