import { CommonModule } from '@angular/common';
import {
  ChangeDetectionStrategy,
  Component,
  ViewChild,
  effect,
  signal,
  untracked,
  OnInit,
} from '@angular/core';
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 { ZardButtonComponent } from '@shared/components/button/button.component';
import { ZardMenuModule } from '@shared/components/menu/menu.module';
import { ZardTooltipModule } from '@shared/components/tooltip/tooltip';
import { SortDir } from '@shared/paging/paging';
import { TpeDevice, TpeStatus } from 'src/app/core/interfaces/tpe';
import { TpeService } from 'src/app/core/services/tpe';
import { TpeForm } from '@shared/forms/tpe-form/tpe-form';
import { Agent } from 'src/app/core/interfaces/agent';
import { AgentService } from 'src/app/core/services/agent';
import { ZardSelectComponent } from '@shared/components/select/select.component';
import { ZardSelectItemComponent } from '@shared/components/select/select-item.component';
import { ZardFormModule } from '@shared/components/form/form.module';
import { forkJoin, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';

@Component({
  standalone: true,
  selector: 'app-tpe-list',
  templateUrl: './tpe.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    CommonModule,
    DataTable,
    Paginator,
    SearchBar,
    Modal,
    ZardButtonComponent,
    TpeForm,
    ZardMenuModule,
    ZardTooltipModule,
    ZardSelectComponent,
    ZardSelectItemComponent,
    ZardFormModule,
  ],
})
export class TpePage implements OnInit {
  rows = signal<TpeDevice[]>([]);
  total = signal(0);
  loading = signal(false);

  page = signal(1);
  perPage = signal(10);
  search = signal('');
  sort = signal<SortState>({ key: 'imei', dir: 'asc' });
  selectedStatut = signal<TpeStatus | null>(null);

  modalOpen = signal(false);
  modalTitle = signal('Nouvel équipement');
  editingItem = signal<TpeDevice | null>(null);

  // Agent assignment modal
  assignModalOpen = signal(false);
  assigningTpe = signal<TpeDevice | null>(null);
  agents = signal<Agent[]>([]);
  selectedAgentId = signal<string>('');
  agentsLoading = signal(false);

  // Stats
  statsByStatut = signal<Record<string, number>>({});
  assignmentStats = signal({ total: 0, assignes: 0, disponibles: 0 });
  statsLoading = signal(false);

  // Live search
  private searchSubject = new Subject<string>();

  @ViewChild(TpeForm) formComp?: TpeForm;

  formatStatut(statut: string): string {
    const statutMap: Record<string, string> = {
      VALIDE: 'Valide',
      INVALIDE: 'Invalide',
      EN_PANNE: 'En panne',
      BLOQUE: 'Bloqué',
      DISPONIBLE: 'Disponible',
      AFFECTE: 'Affecté',
      EN_MAINTENANCE: 'En maintenance',
      HORS_SERVICE: 'Hors service',
      VOLE: 'Volé',
    };
    return statutMap[statut] || statut;
  }

  cols: TableColumn<TpeDevice>[] = [
    { key: 'imei', label: 'IMEI', sortable: true },
    { key: 'serial', label: 'N° de Série', sortable: true },
    { key: 'type', label: 'Type', sortable: true },
    { key: 'marque', label: 'Marque', sortable: true },
    { key: 'modele', label: 'Modèle', sortable: true },
    { key: 'statut', label: 'Statut', sortable: true, cell: (d) => this.formatStatut(d.statut) },
    {
      key: 'assigne',
      label: 'Assigné à',
      cell: (d) => {
        if (!d.assigne || !d.agent) {
          return '<span class="text-muted-foreground text-sm">Non assigné</span>';
        }
        const agent = d.agent;
        const code = agent.code
          ? `<span class="inline-flex items-center px-2 py-1 rounded bg-primary/10 text-primary text-xs font-medium">${agent.code}</span>`
          : '';
        const name =
          agent.nom && agent.prenom
            ? `<div class="font-medium text-sm">${agent.nom} ${agent.prenom}</div>`
            : agent.nom || agent.prenom
            ? `<div class="font-medium text-sm">${agent.nom || agent.prenom}</div>`
            : '';
        const phone = agent.phone
          ? `<div class="text-xs text-muted-foreground">${agent.phone}</div>`
          : '';
        const zone = agent.zone
          ? `<div class="text-xs text-muted-foreground">Zone: ${agent.zone}</div>`
          : '';

        const parts = [code, name, phone, zone].filter(Boolean);
        if (parts.length === 0) {
          return '<span class="text-muted-foreground text-sm">Agent assigné</span>';
        }
        return `<div class="flex flex-col gap-1">${parts.join('')}</div>`;
      },
    },
  ];

  allStatuses: TpeStatus[] = [
    'VALIDE',
    'INVALIDE',
    'EN_PANNE',
    'BLOQUE',
    'DISPONIBLE',
    'AFFECTE',
    'EN_MAINTENANCE',
    'HORS_SERVICE',
    'VOLE',
  ];

  constructor(private api: TpeService, private agentService: AgentService) {
    effect(() => {
      // Only trigger fetch when page, perPage, or sort changes (not search - handled by searchSubject)
      const searchValue = this.search();
      const params = {
        page: this.page(),
        size: this.perPage(),
        search: searchValue,
        sortKey: this.sort().key,
        sortDir: this.sort().dir as SortDir,
      };
      // Only fetch if search is empty (search is handled by searchSubject)
      if (!searchValue.trim()) {
        untracked(() => this.fetch(params));
      }
    });

    // Setup live search with debounce
    this.searchSubject
      .pipe(
        debounceTime(300),
        distinctUntilChanged(),
        switchMap((query) => {
          if (query.trim()) {
            return this.api.search(query);
          } else {
            // If empty, use normal list
            return this.api.list({
              page: this.page(),
              size: this.perPage(),
              search: '',
              sortKey: this.sort().key,
              sortDir: this.sort().dir as SortDir,
            });
          }
        })
      )
      .subscribe({
        next: (res) => {
          if (Array.isArray(res)) {
            // Search API returns array
            this.rows.set(res);
            this.total.set(res.length);
          } else {
            // List returns PagedResult
            this.rows.set(res.content);
            this.total.set(res.pageable.total);
          }
          this.loading.set(false);
        },
        error: (err) => {
          console.error('Search error:', err);
          this.rows.set([]);
          this.total.set(0);
          this.loading.set(false);
        },
      });
  }

  ngOnInit() {
    this.loadStats();
    // Initial fetch if no search query
    if (!this.search().trim()) {
      this.fetch({
        page: this.page(),
        size: this.perPage(),
        search: '',
        sortKey: this.sort().key,
        sortDir: this.sort().dir as SortDir,
      });
    }
  }

  loadStats() {
    this.statsLoading.set(true);
    forkJoin({
      byStatut: this.api.getCountByStatut(),
      assignes: this.api.getAssignesStats(),
    }).subscribe({
      next: ({ byStatut, assignes }) => {
        this.statsByStatut.set(byStatut || {});
        // Calculate total from statsByStatut
        const total = Object.values(byStatut || {}).reduce((sum, count) => sum + count, 0);
        // Calculate disponibles (total - assignes)
        const disponibles = Math.max(0, total - (assignes || 0));
        this.assignmentStats.set({
          total: total,
          assignes: assignes || 0,
          disponibles: disponibles,
        });
        this.statsLoading.set(false);
      },
      error: (err) => {
        console.error('Error loading stats:', err);
        this.statsByStatut.set({});
        this.assignmentStats.set({ total: 0, assignes: 0, disponibles: 0 });
        this.statsLoading.set(false);
      },
    });
  }

  private fetch(params: {
    page: number;
    size: number;
    search: string;
    sortKey: string;
    sortDir: SortDir;
  }) {
    // Don't fetch if there's a search query - it's handled by searchSubject
    const searchQuery = params.search.trim();
    if (searchQuery) {
      return; // Search is handled by searchSubject subscription
    }

    this.loading.set(true);
    const statut = this.selectedStatut();

    if (statut) {
      // Filter by statut - returns array
      this.api.getByStatut(statut).subscribe({
        next: (res: TpeDevice[]) => {
          this.rows.set(res);
          this.total.set(res.length);
          this.loading.set(false);
        },
        error: () => {
          this.rows.set([]);
          this.total.set(0);
          this.loading.set(false);
        },
      });
    } else {
      // Normal list with pagination
      this.api.list(params).subscribe({
        next: (res) => {
          this.rows.set(res.content);
          this.total.set(res.pageable.total);
          this.loading.set(false);
        },
        error: () => {
          this.rows.set([]);
          this.total.set(0);
          this.loading.set(false);
        },
      });
    }
  }

  onSearch(q: string) {
    this.search.set(q);
    this.page.set(1);
    // Trigger search via subject for live search
    if (q.trim()) {
      this.loading.set(true);
      this.searchSubject.next(q);
    } else {
      // If empty, fetch normally
      this.fetch({
        page: this.page(),
        size: this.perPage(),
        search: '',
        sortKey: this.sort().key,
        sortDir: this.sort().dir as SortDir,
      });
    }
  }

  onStatutFilter(statut: TpeStatus | null) {
    this.selectedStatut.set(statut);
    this.page.set(1);
    this.fetch({
      page: this.page(),
      size: this.perPage(),
      search: this.search(),
      sortKey: this.sort().key,
      sortDir: this.sort().dir as SortDir,
    });
  }

  onUpdateStatut(row: TpeDevice, newStatut: TpeStatus) {
    if (!confirm(`Changer le statut de ${row.imei} vers ${this.formatStatut(newStatut)} ?`)) return;
    this.api.updateStatut(row.id, newStatut).subscribe({
      next: () => {
        this.fetch({
          page: this.page(),
          size: this.perPage(),
          search: this.search(),
          sortKey: this.sort().key,
          sortDir: this.sort().dir as SortDir,
        });
        this.loadStats();
      },
    });
  }

  onLiberer(row: TpeDevice) {
    if (!confirm(`Libérer le TPE ${row.imei} ?`)) return;
    this.api.liberer(row.id).subscribe({
      next: () => {
        this.fetch({
          page: this.page(),
          size: this.perPage(),
          search: this.search(),
          sortKey: this.sort().key,
          sortDir: this.sort().dir as SortDir,
        });
        this.loadStats();
      },
    });
  }

  onAssigner(row: TpeDevice) {
    this.assigningTpe.set(row);
    this.selectedAgentId.set('');
    this.loadAgents();
    this.assignModalOpen.set(true);
  }

  loadAgents() {
    this.agentsLoading.set(true);
    // Load active agents only
    this.agentService.getByStatut('ACTIF').subscribe({
      next: (agents) => {
        this.agents.set(agents);
        this.agentsLoading.set(false);
      },
      error: () => {
        this.agents.set([]);
        this.agentsLoading.set(false);
      },
    });
  }

  confirmAssign() {
    const tpe = this.assigningTpe();
    const agentId = this.selectedAgentId();
    if (!tpe || !agentId) {
      alert('Veuillez sélectionner un agent');
      return;
    }
    this.api.assigner(tpe.id, agentId).subscribe({
      next: () => {
        this.assignModalOpen.set(false);
        this.assigningTpe.set(null);
        this.selectedAgentId.set('');
        this.fetch({
          page: this.page(),
          size: this.perPage(),
          search: this.search(),
          sortKey: this.sort().key,
          sortDir: this.sort().dir as SortDir,
        });
        this.loadStats();
      },
      error: () => {
        alert("Erreur lors de l'assignation du TPE");
      },
    });
  }

  closeAssignModal() {
    this.assignModalOpen.set(false);
    this.assigningTpe.set(null);
    this.selectedAgentId.set('');
  }
  openCreate() {
    this.modalTitle.set('Nouvel équipement');
    this.editingItem.set(null);
    queueMicrotask(() => this.modalOpen.set(true));
  }
  openEdit(row: TpeDevice) {
    this.modalTitle.set("Modifier l'équipement");
    this.editingItem.set(row);
    queueMicrotask(() => this.modalOpen.set(true));
  }
  closeModal() {
    this.modalOpen.set(false);
    setTimeout(() => {
      this.editingItem.set(null);
    }, 0);
  }

  submitChildForm() {
    this.formComp?.onSubmit();
  }

  onFormSave(payload: Partial<TpeDevice>) {
    const current = this.editingItem();
    const isCreating = !current?.id;
    const req$ = current?.id
      ? this.api.update(current.id, payload)
      : this.api.create(payload as Omit<TpeDevice, 'id'>);
    req$.subscribe({
      next: (result) => {
        // For update, check if result is valid (update can return undefined on error)
        if (current?.id && !result) {
          console.error('Update failed - result is undefined');
          // Don't close modal, let user retry
          return;
        }
        // Success - close modal first
        this.modalOpen.set(false);
        // Then reset form and clear editing item after a short delay
        setTimeout(() => {
          this.editingItem.set(null);
          this.formComp?.resetForm();
        }, 100);
        // Refresh data
        this.fetch({
          page: this.page(),
          size: this.perPage(),
          search: this.search(),
          sortKey: this.sort().key,
          sortDir: this.sort().dir as SortDir,
        });
        this.loadStats();
      },
      error: (err) => {
        console.error('Error saving TPE:', err);
        // Don't close modal on error, let user fix and retry
        // Form stays filled so user can correct and resubmit
      },
    });
  }

  remove(row: TpeDevice) {
    if (!confirm(`Supprimer l\'équipement IMEI ${row.imei} ?`)) return;
    this.api.delete(row.id).subscribe(() => {
      this.fetch({
        page: this.page(),
        size: this.perPage(),
        search: this.search(),
        sortKey: this.sort().key,
        sortDir: this.sort().dir as SortDir,
      });
      this.loadStats();
    });
  }
}
