import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { FormArray, FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { ZardFormModule } from '@shared/components/form/form.module';
import { ZardInputDirective } from '@shared/components/input/input.directive';
import { ZardSelectComponent } from '@shared/components/select/select.component';
import { ZardSelectItemComponent } from '@shared/components/select/select-item.component';
import { ZardButtonComponent } from '@shared/components/button/button.component';
import { ZardCardComponent } from '@shared/components/card/card.component';
import { DataTable, SortState, TableColumn } from '@shared/components/data-table/data-table';
import { Paginator } from '@shared/components/paginator/paginator';
import { SearchBar } from '@shared/components/search-bar/search-bar';
import { Modal } from '@shared/components/modal/modal';
import { Agent, AgentFamilyMember } from 'src/app/core/interfaces/agent';
import { AgentLimit } from 'src/app/core/interfaces/agent-limit';
import { AgentLimitService } from 'src/app/core/services/agent-limit';
import { AgentFamilyMemberService } from 'src/app/core/services/agent-family-member';
import { TpeDevice } from 'src/app/core/interfaces/tpe';
import { TpeService } from 'src/app/core/services/tpe';

@Component({
  selector: 'app-agent-full-form',
  standalone: true,
  templateUrl: './agent-full-form.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    CommonModule,
    ReactiveFormsModule,
    ZardFormModule,
    ZardInputDirective,
    ZardSelectComponent,
    ZardSelectItemComponent,
    ZardButtonComponent,
    ZardCardComponent,
    DataTable,
    Paginator,
    SearchBar,
    Modal,
  ],
})
export class AgentFullForm {
  @Output() save = new EventEmitter<Agent>();
  @Output() cancel = new EventEmitter<void>();

  limits: AgentLimit[] = [];
  selectedLimit: AgentLimit | null = null;
  tpes: TpeDevice[] = [];
  // TPE picker state
  assignModalOpen = false;
  tpeRows: TpeDevice[] = [];
  tpeTotal = 0;
  tpePage = 1;
  tpePerPage = 10;
  tpeSearch = '';
  tpeCols: TableColumn<TpeDevice>[] = [
    { key: 'imei', label: 'IMEI', sortable: true },
    { key: 'serial', label: 'N° Série', sortable: true },
    { key: 'marque', label: 'Marque', sortable: true },
    { key: 'modele', label: 'Modèle', sortable: true },
    { key: 'type', label: 'Type', sortable: true },
    { key: 'statut', label: 'Statut', sortable: true },
  ];

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

  form: FormGroup;
  submitted = false;

  constructor(
    private fb: FormBuilder,
    private limitService: AgentLimitService,
    private tpeService: TpeService,
    private familyMemberService: AgentFamilyMemberService
  ) {
    this.form = this.fb.group({
      // Emploi
      code: ['', Validators.required], profile: ['', Validators.required], principalCode: [''], caisseProfile: [''], statut: ['ACTIF', Validators.required], zone: [''], kiosk: [''], fonction: [''], dateEmbauche: [''],
      // Perso
      nom: ['', Validators.required], prenom: ['', Validators.required], autresNoms: [''], dateNaissance: [''], lieuNaissance: [''], adresse: [''], ville: [''], autoriserAides: [false], maxPeripheriques: [0, [Validators.min(0)]],
      // Connexion & limites
      phone: ['', Validators.required], pin: [''], limiteInferieure: [0], limiteSuperieure: [0], limiteParTransaction: [0], limiteMinAirtime: [0], limiteMaxAirtime: [0], limitId: ['', Validators.required],
      // Légales
      nationalite: [''], cni: [''], cniDelivreeLe: [''], cniDelivreeA: [''], residence: [''], autreAdresse1: [''], statutMarital: [''], epoux: [''], autreTelephone: [''],
      // Famille
      famille: this.fb.array([]),
      // TPE (stored as IDs in form, converted to full objects on submit)
      tpeIds: this.fb.array<string>([]),
    });

    this.limitService.list({ page: 1, perPage: 100, search: '', sortKey: 'nom', sortDir: 'asc' } as any).subscribe((res) => {
      this.limits = res.content;
      
      // Find default limit
      const defaultLimit = this.limits.find((l) => l.isDefault);
      
      // Watch for limitId changes to update selectedLimit
      this.form.get('limitId')?.valueChanges.subscribe((limitId) => {
        if (limitId) {
          this.selectedLimit = this.limits.find((l) => l.id === limitId) || null;
        } else {
          this.selectedLimit = null;
        }
      });
      
      // Set initial selectedLimit if form already has a value
      const currentLimitId = this.form.get('limitId')?.value;
      if (currentLimitId) {
        this.selectedLimit = this.limits.find((l) => l.id === currentLimitId) || null;
      } else if (defaultLimit && !this.value?.id) {
        // If no limit is set and we're creating a new agent, assign the default limit
        this.form.patchValue({ limitId: defaultLimit.id });
        this.selectedLimit = defaultLimit;
      }
    });
    // initial fetch page for TPE modal
    this.fetchTpes();
  }

  get famille(): FormArray { return this.form.get('famille') as FormArray; }
  get tpeArray(): FormArray { return this.form.get('tpeIds') as FormArray; }

  addFamily() {
    this.famille.push(
      this.fb.group({
        id: [''], // Will be set when saved
        agentId: [this.value?.id || ''],
        nom: ['', Validators.required],
        statut: [''],
        dateNaissance: [''],
        sexe: [''],
      })
    );
  }
  removeFamily(i: number) {
    const familyGroup = this.famille.at(i);
    const familyId = familyGroup?.get('id')?.value;
    // If it has an ID, it means it's already saved - we'll delete it when saving the agent
    // For now, just remove from form
    this.famille.removeAt(i);
  }

  private hydrate(v?: Agent) {
    this.famille.clear();
    this.tpeArray.clear();
    this.selectedLimit = null;
    
    if (!v) {
      // Find default limit to assign it automatically
      const defaultLimit = this.limits.find((l) => l.isDefault);
      const defaultLimitId = defaultLimit?.id || '';
      
      this.form.reset({
        code: '',
        profile: '',
        principalCode: '',
        caisseProfile: '',
        statut: 'ACTIF',
        zone: '',
        kiosk: '',
        fonction: '',
        dateEmbauche: '',
        nom: '',
        prenom: '',
        autresNoms: '',
        dateNaissance: '',
        lieuNaissance: '',
        adresse: '',
        ville: '',
        autoriserAides: false,
        maxPeripheriques: 0,
        phone: '',
        pin: '',
        limiteInferieure: 0,
        limiteSuperieure: 0,
        limiteParTransaction: 0,
        limiteMinAirtime: 0,
        limiteMaxAirtime: 0,
        limitId: defaultLimitId,
        nationalite: '',
        cni: '',
        cniDelivreeLe: '',
        cniDelivreeA: '',
        residence: '',
        autreAdresse1: '',
        statutMarital: '',
        epoux: '',
        autreTelephone: '',
      });
      
      // Set selectedLimit if default limit exists
      if (defaultLimit) {
        this.selectedLimit = defaultLimit;
      }
      return;
    }
    
    this.form.patchValue(v);
    
    // Set selected limit if limitId exists
    if (v.limitId) {
      this.selectedLimit = this.limits.find((l) => l.id === v.limitId) || null;
    }
    
    // Load family members separately via AgentFamilyMemberService
    if (v.id) {
      this.familyMemberService.getByAgentId(v.id).subscribe({
        next: (members) => {
          members.forEach((m) => {
            this.famille.push(
              this.fb.group({
                id: [m.id || ''],
                agentId: [m.agentId || v.id],
                nom: [m.nom, Validators.required],
                statut: [m.statut || ''],
                dateNaissance: [m.dateNaissance || ''],
                sexe: [m.sexe || ''],
              })
            );
          });
        },
        error: () => {
          // If error, just continue without family members
        },
      });
    }
    
    // Load assigned TPE IDs from tpes array
    (v.tpes ?? []).forEach((tpe) => this.tpeArray.push(this.fb.control(tpe.id)));
  }

  onToggleTpe(id: string, checked: boolean) {
    const idx = this.tpeArray.value.indexOf(id);
    if (checked && idx === -1) this.tpeArray.push(this.fb.control(id));
    if (!checked && idx !== -1) this.tpeArray.removeAt(idx);
  }

  openAssignTpe() {
    this.assignModalOpen = true;
    this.fetchTpes();
  }
  closeAssignTpe() {
    this.assignModalOpen = false;
    // Refresh TPE list to show current assignments
    this.fetchTpes();
  }
  onTpeSearch(q: string) { this.tpeSearch = q; this.tpePage = 1; this.fetchTpes(); }
  onTpePageChange(p: number) { this.tpePage = p; this.fetchTpes(); }
  onTpePerPageChange(pp: number) { this.tpePerPage = pp; this.fetchTpes(); }
  isSelectedTpe(id: string) { return (this.tpeArray.value as string[]).includes(id); }

  fetchTpes() {
    this.tpeService
      .list({ page: this.tpePage, perPage: this.tpePerPage, search: this.tpeSearch, sortKey: 'imei', sortDir: 'asc' } as any)
      .subscribe((res) => {
        // Only show VALIDE TPEs that are either not assigned or assigned to this agent
        const currentAgentId = this.value?.id;
        this.tpeRows = res.content.filter((t) => {
          if (t.statut !== 'VALIDE') return false;
          // If TPE is assigned but to this agent, show it
          if (t.assigne && currentAgentId) {
            // We need to check if this TPE is assigned to this agent
            // For now, show all VALIDE TPEs - the backend should handle assignment logic
            return true;
          }
          // Show unassigned TPEs
          return !t.assigne;
        });
        this.tpeTotal = this.tpeRows.length;
      });
  }

  tpeLabel(id: string): string {
    const list = [...(this.tpeRows ?? []), ...(this.tpes ?? [])];
    const found = list.find((t) => t.id === id);
    if (found) {
      return `${found.imei} (${found.marque} ${found.modele})`;
    }
    // Try to load from service if not in current list
    return id;
  }

  // === Validation helpers ===
  error(control: string): string {
    // Handle nested paths like "famille.0.nom"
    const parts = control.split('.');
    let c: any = this.form;
    for (const part of parts) {
      if (c.get) {
        c = c.get(part);
      } else if (c.controls && c.controls[part]) {
        c = c.controls[part];
      } else {
        return '';
      }
      if (!c) return '';
    }
    
    const invalid = c.invalid && (c.touched || this.submitted);
    if (!invalid) return '';
    const e = c.errors || {};
    if (e['required']) return 'Ce champ est obligatoire';
    if (e['min']) return `Valeur minimale: ${e['min'].min}`;
    if (e['minlength']) return `Minimum ${e['minlength'].requiredLength} caractères`;
    return 'Valeur invalide';
  }

  onSubmit() {
    this.submitted = true;
    if (this.form.invalid) {
      this.form.markAllAsTouched();
      return;
    }
    const raw = this.form.getRawValue() as any;
    
    // Convert TPE IDs to full TPE objects
    const tpeIds = [...this.tpeArray.value] as string[];
    const tpes: TpeDevice[] = tpeIds
      .map((id) => {
        // Try to find in tpeRows first (current modal list)
        const found = this.tpeRows.find((t) => t.id === id);
        if (found) return found;
        // Try to find in existing tpes (from value)
        const existing = this.value?.tpes?.find((t) => t.id === id);
        if (existing) return existing;
        // If not found, create a minimal TPE object (backend will fill in details)
        // This shouldn't happen in normal flow, but handle gracefully
        return null;
      })
      .filter((t): t is TpeDevice => t !== null);
    
    // Prepare agent payload (without famille - family members are handled separately)
    const payload: Agent = {
      ...(this.value ?? {}),
      id: this.value?.id || '',
      ...raw,
      tpes: tpes,
    } as Agent;
    
    // Remove tpeIds from payload (it's not part of Agent interface)
    delete (payload as any).tpeIds;
    
    // Emit the agent payload first
    // Family members will be saved separately in the parent component
    this.save.emit(payload);
  }

  // Get family members data for saving
  getFamilyMembersData(): Array<{ id?: string; agentId: string; nom: string; statut?: string; dateNaissance?: string; sexe?: string }> {
    return this.famille.value.map((fm: any) => ({
      id: fm.id || undefined,
      agentId: fm.agentId || this.value?.id || '',
      nom: fm.nom,
      statut: fm.statut || undefined,
      dateNaissance: fm.dateNaissance || undefined,
      sexe: fm.sexe || undefined,
    }));
  }

  resetForm() {
    this._value = undefined;
    this.selectedLimit = null;
    this.famille.clear();
    this.tpeArray.clear();
    
    // Find default limit to assign it automatically
    const defaultLimit = this.limits.find((l) => l.isDefault);
    const defaultLimitId = defaultLimit?.id || '';
    
    this.form.reset({
      code: '',
      profile: '',
      principalCode: '',
      caisseProfile: '',
      statut: 'ACTIF',
      zone: '',
      kiosk: '',
      fonction: '',
      dateEmbauche: '',
      nom: '',
      prenom: '',
      autresNoms: '',
      dateNaissance: '',
      lieuNaissance: '',
      adresse: '',
      ville: '',
      autoriserAides: false,
      maxPeripheriques: 0,
      phone: '',
      pin: '',
      limiteInferieure: 0,
      limiteSuperieure: 0,
      limiteParTransaction: 0,
      limiteMinAirtime: 0,
      limiteMaxAirtime: 0,
      limitId: defaultLimitId,
      nationalite: '',
      cni: '',
      cniDelivreeLe: '',
      cniDelivreeA: '',
      residence: '',
      autreAdresse1: '',
      statutMarital: '',
      epoux: '',
      autreTelephone: '',
    });
    
    // Set selectedLimit if default limit exists
    if (defaultLimit) {
      this.selectedLimit = defaultLimit;
    }
    this.submitted = false;
  }
}


