import {
  Component,
  Input,
  Output,
  EventEmitter,
  OnInit,
  OnDestroy,
  forwardRef,
  ViewChild,
  ElementRef,
  HostListener,
  ChangeDetectorRef
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

import {
  Subject,
  Observable,
  of,
  EMPTY,
  BehaviorSubject,
  combineLatest
} from 'rxjs';
import {
  debounceTime,
  distinctUntilChanged,
  switchMap,
  map,
  catchError,
  tap,
  takeUntil,
  filter
} from 'rxjs/operators';

import {
  RemoteSelectConfig,
  RemoteSelectItem,
  RemoteSelectEvent,
  RemoteSelectState
} from './interfaces/remote-select.interface';

/**
 * 🎯 RemoteSelectComponent - Componente de busca dinâmica universal
 * 
 * ✨ Funcionalidades:
 * - 🔍 Autocomplete com debounce
 * - ⌨️ F2 para modal de seleção - TODO: Implementar modal de seleção 
 * - 📱 Responsivo e acessível
 * - 🔄 Integração com Reactive Forms
 * - 🎨 Customizável via configuração
 * 
 * 🚀 Uso em qualquer domínio via getEntities()
 */
@Component({
  selector: 'app-remote-select',
  standalone: true,
  imports: [
    CommonModule
  ],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => RemoteSelectComponent),
      multi: true
    }
  ],
  templateUrl: './remote-select.component.html',
  styleUrl: './remote-select.component.scss'
})
export class RemoteSelectComponent implements OnInit, OnDestroy, ControlValueAccessor {
  
  // ========================================
  // 🎛️ INPUTS E CONFIGURAÇÕES
  // ========================================
  
  private _config!: RemoteSelectConfig;
  
    @Input()
  set config(value: RemoteSelectConfig) {
    // 🚨 PROTEÇÃO: Se já temos um valor e o novo config não tem initialValue, preservar estado
    if (this._config && this.state?.searchTerm && value && !value.initialValue) {
      // Manter o initialValue do config anterior se disponível
      if (this._config.initialValue && this.value === this._config.initialValue.id) {
        value.initialValue = this._config.initialValue;
      }
    }
    
    this._config = value;
  }
  
  get config(): RemoteSelectConfig {
    return this._config;
  }
  @Input() label: string = '';
  @Input() disabled: boolean = false;
  @Input() required: boolean = false;
  @Input() hideLabel: boolean = false;
  
  // ========================================
  // 📤 OUTPUTS E EVENTOS
  // ========================================
  
  @Output() selectionChange = new EventEmitter<RemoteSelectEvent>();
  @Output() searchQuery = new EventEmitter<string>();
  @Output() modalToggle = new EventEmitter<boolean>();
  
  // ========================================
  // 🎯 REFERÊNCIAS E ELEMENTOS
  // ========================================
  
  @ViewChild('searchInput') searchInput!: ElementRef<HTMLInputElement>;
  @ViewChild('dropdown') dropdown!: ElementRef<HTMLElement>;
  
  // ========================================
  // 🏗️ ESTADO DO COMPONENTE
  // ========================================
  
  // 🔍 STATE SIMPLES - seguindo padrão dos componentes funcionais
  state: RemoteSelectState = {
    loading: false,
    dropdownOpen: false,
    modalOpen: false,
    searchTerm: '',
    items: [],
    selectedItems: [],
    error: undefined
  };
  
  // ✅ NOVO: Controle de foco para dropdown
  private inputFocused: boolean = false;

  private setSearchTerm(newTerm: string, source: string = 'unknown') {
    const oldTerm = this.state.searchTerm;
    this.state.searchTerm = newTerm;
  }
  
  // ========================================
  // 🔧 CONTROLES INTERNOS
  // ========================================
  
  private destroy$ = new Subject<void>();
  private searchSubject = new BehaviorSubject<string>('');
  selectedIndex = -1;
  private cache = new Map<string, RemoteSelectItem[]>();

  // ControlValueAccessor
  private value: any = null;
  private onChange = (value: any) => {};
  private onTouched = () => {};
  
  // ========================================
  // 🎯 CONFIGURAÇÕES PADRÃO
  // ========================================
  
  private get defaultConfig(): Partial<RemoteSelectConfig> {
    return {
      minLength: 3,
      debounceTime: 300,
      multiple: false,
      maxResults: 10,
      placeholder: 'Digite para buscar...'
    };
  }
  
  get mergedConfig(): RemoteSelectConfig {
    return { ...this.defaultConfig, ...this.config };
  }
  
  // ========================================
  // 🚀 LIFECYCLE HOOKS
  // ========================================
  
  constructor(private cdr: ChangeDetectorRef) {}
  
  ngOnInit() {
    this.validateConfig();
    this.setupSearchStream();
  }
  
  ngOnDestroy() {
    this.destroy$.next();
    this.destroy$.complete();
  }
  
  // ========================================
  // 🔧 CONFIGURAÇÃO E VALIDAÇÃO
  // ========================================
  
  private validateConfig() {
    if (!this.config) {
      throw new Error('RemoteSelect: config é obrigatório');
    }
    
    const required = ['service', 'searchField', 'displayField', 'valueField'];
    for (const field of required) {
      if (!this.config[field as keyof RemoteSelectConfig]) {
        throw new Error(`RemoteSelect: config.${field} é obrigatório`);
      }
    }
  }
  
  private setupSearchStream() {
    this.searchSubject.pipe(
      debounceTime(this.mergedConfig.debounceTime!),
      distinctUntilChanged(),
      filter(term => {        
        if (this.config.initialValue && this.config.initialValue.label) {
          if(term.length === 0 && this.config.initialValue.label.length > 0) {
            return false;
          }else{
            return true;
          }
        }
        return term.length >= this.mergedConfig.minLength! || term.length === 0;
      }),
      tap(term => {
        this.state.searchTerm = term;
        this.searchQuery.emit(term);
        
        if (term.length === 0) {
          this.clearResults();
          return;
        }
        
        this.state.loading = true;
        this.state.error = undefined;
      }),
      switchMap(term => {
        return this.searchItems(term).pipe(
          map(items => {
            // Salvar no cache - TODO: Implementar cache
            this.cache.set(term, items);
            return items;
          }),
          catchError(error => {
            this.state.error = 'Erro ao buscar dados. Tente novamente.';
            return of([]);
          })
        );
      }),
      takeUntil(this.destroy$)
      
    ).subscribe(items => {
      this.state.items = items;
      this.state.loading = false;
      // ✅ NOVO: Só abrir dropdown se input estiver focado E tiver itens
      this.state.dropdownOpen = items.length > 0 && this.inputFocused;
      this.selectedIndex = -1;

      if (items.length > 0) {
        this.cdr.detectChanges();
      }
    });
  }
  
  // ========================================
  // 🔍 BUSCA DE DADOS
  // ========================================
  
  private searchItems(query: string): Observable<RemoteSelectItem[]> {
    const filters = this.buildSearchFilters(query);
    
    return this.mergedConfig.service.getEntities(1, this.mergedConfig.maxResults!, filters).pipe(
      map((response: any) => this.mapResponseToItems(response.data)),
      tap(() => console.log(`RemoteSelect: Busca por "${query}" executada`))
    );
  }
  
  private buildSearchFilters(query: string): any {
    const filters: any = {
      [this.mergedConfig.searchField]: query
    };
    
    // Adicionar campos extras se configurados
    if (this.mergedConfig.additionalFields?.length) {
      this.mergedConfig.additionalFields.forEach(field => {
        filters[field] = query;
      });
    }
    
    // 🎯 NOVO: Adicionar filtros da configuração
    if (this.mergedConfig.filters) {
      Object.keys(this.mergedConfig.filters).forEach(key => {
        filters[key] = this.mergedConfig.filters![key];
      });
    }
    
    return filters;
  }
  
  private mapResponseToItems(data: any[]): RemoteSelectItem[] {
    return data.map(item => ({
      id: item[this.mergedConfig.valueField],
      label: item[this.mergedConfig.displayField],
      data: item,
      selected: false
    }));
  }
  
  // ========================================
  // 🎯 CONTROLE DE PESQUISA
  // ========================================
  
  onSearchInput(event: Event) {
    const target = event.target as HTMLInputElement;
    const value = target.value;
    
    this.searchSubject.next(value);
    this.onTouched();
  }
  
  private clearResults() {
    this.state.items = [];
    this.state.dropdownOpen = false;
    this.state.loading = false;
    this.selectedIndex = -1;
  }
  
  // ========================================
  // 🎯 SELEÇÃO DE ITENS
  // ========================================
  
  selectItem(item: RemoteSelectItem) {
    if (this.mergedConfig.multiple) {
      // ✅ SELEÇÃO MÚLTIPLA: Adicionar/remover do array
      const existingIndex = this.state.selectedItems.findIndex(i => i.id === item.id);
      
      if (existingIndex >= 0) {
        // Item já selecionado - remover
        this.state.selectedItems.splice(existingIndex, 1);
      } else {
        // Item não selecionado - adicionar
        this.state.selectedItems.push(item);
      }
      
      // Atualizar valor como array de IDs
      const values = this.state.selectedItems.map(i => i.id);
      this.setValue(values.length > 0 ? values : null);
      
      // Manter dropdown aberto para múltipla seleção
      // this.state.dropdownOpen = true; // Manter aberto
      
      // Limpar campo de busca para nova pesquisa
      this.setSearchTerm('', 'selectItem');
      
      const event: RemoteSelectEvent = {
        value: values,
        item: this.state.selectedItems,
        source: 'dropdown'
      };
      
      this.selectionChange.emit(event);
    } else {
      // ✅ SELEÇÃO ÚNICA: Comportamento original
      this.setValue(item.id);
      this.state.selectedItems = [item];
      this.state.dropdownOpen = false;
      this.setSearchTerm(item.label, 'selectItem');
      
      const event: RemoteSelectEvent = {
        value: item.id,
        item: item,
        source: 'dropdown'
      };
      
      this.selectionChange.emit(event);
    }
  }
  
  clearSelection() {
    this.setValue(null);
    this.state.selectedItems = [];
    this.state.searchTerm = '';
    this.clearResults();
    
    if (this.searchInput) {
      this.searchInput.nativeElement.focus();
    }
    
    const event: RemoteSelectEvent = {
      value: null,
      item: [],
      source: 'clear'
    };
    
    this.selectionChange.emit(event);
  }
  
  // ========================================
  // ⌨️ NAVEGAÇÃO POR TECLADO
  // ========================================
  
  @HostListener('keydown', ['$event'])
  onKeyDown(event: KeyboardEvent) {
    if (!this.state.dropdownOpen && event.key !== 'F2') return;
    
    switch (event.key) {
      case 'ArrowDown':
        event.preventDefault();
        this.navigateDown();
        break;
        
      case 'ArrowUp':
        event.preventDefault();
        this.navigateUp();
        break;
        
      case 'Enter':
        event.preventDefault();
        this.selectCurrentItem();
        break;
        
      case 'Escape':
        event.preventDefault();
        this.closeDropdown();
        break;
        
      case 'F2':
        event.preventDefault();
        this.openModal();
        break;
    }
  }
  
  private navigateDown() {
    if (this.selectedIndex < this.state.items.length - 1) {
      this.selectedIndex++;
    }
  }
  
  private navigateUp() {
    if (this.selectedIndex > 0) {
      this.selectedIndex--;
    }
  }
  
  private selectCurrentItem() {
    if (this.selectedIndex >= 0 && this.selectedIndex < this.state.items.length) {
      this.selectItem(this.state.items[this.selectedIndex]);
    }
  }
  
  private closeDropdown() {
    this.state.dropdownOpen = false;
    this.selectedIndex = -1;
  }
  
  // ========================================
  // 🎨 MODAL F2
  // ========================================
  
  openModal() {
    this.state.modalOpen = true;
    this.modalToggle.emit(true);
    
    // TODO: Implementar modal de seleção
    console.log('🎯 Modal F2 aberto para:', this.mergedConfig.modalTitle);
  }
  
  closeModal() {
    this.state.modalOpen = false;
    this.modalToggle.emit(false);
  }
  
  // ========================================
  // 🔄 CONTROL VALUE ACCESSOR
  // ========================================
  
  writeValue(value: any): void {
    this.value = value;

    // ✅ NOVO: Tratar valores nulos/vazios
    if (!value || (Array.isArray(value) && value.length === 0)) {
      this.state.selectedItems = [];
      this.state.searchTerm = '';
      this.persistedDisplayValue = '';
      this.persistedValueId = null;
      this.cdr.detectChanges();
      return;
    }

    // Se temos um valor inicial na configuração
    if (this.config?.initialValue) {
      const initialItem: RemoteSelectItem = {
        id: this.config.initialValue.id,
        label: this.config.initialValue.label || '',
        data: this.config.initialValue,
        selected: true
      };
      
      this.state.selectedItems = [initialItem];
      this.state.searchTerm = this.mergedConfig.multiple ? '' : initialItem.label;
      this.value = initialItem.id;
      
      // Não precisamos carregar do backend pois já temos os dados
      this.persistedDisplayValue = initialItem.label;
      this.persistedValueId = initialItem.id;
      
      this.cdr.detectChanges();
      return;
    }

    // Se não temos valor inicial, carrega do backend
    if (value) {
      this.loadSelectedItem(value);
    } else {
      this.state.selectedItems = [];
      this.state.searchTerm = '';
      this.persistedDisplayValue = '';
      this.persistedValueId = null;
    }
  }
  
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
  
  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }
  
  private setValue(value: any) {
    this.value = value;
    this.onChange(value);
  }
  
  // 🎯 PROTEÇÃO: Cache do valor exibido para evitar perda durante re-renders
  private persistedDisplayValue: string = '';
  private persistedValueId: any = null;

  private loadSelectedItem(id: any) {
    console.log(`📡 [RemoteSelect-DEEP] loadSelectedItem iniciado para ID: ${id}`);
    
    if (!id || !this.mergedConfig.service?.getById) {
      console.log(`⚠️ [RemoteSelect-DEEP] loadSelectedItem cancelado - sem ID ou service`);
      return;
    }

    // 🎯 OTIMIZAÇÃO: Se já carregamos este ID, não recarregar
    if (this.persistedValueId === id && this.persistedDisplayValue) {
      console.log(`✅ [RemoteSelect-DEEP] Usando cache para ID ${id}: ${this.persistedDisplayValue}`);
      this.setSearchTerm(this.persistedDisplayValue, 'persistedValue-loadSelectedItem');
      return;
    }

    console.log(`🌐 [RemoteSelect-DEEP] Fazendo requisição HTTP para ID: ${id}`);
    this.mergedConfig.service.getById(id).subscribe({
      next: (item: any) => {
        console.log(`📥 [RemoteSelect-DEEP] Resposta HTTP recebida para ID ${id}:`, item);
        // 🚀 CORREÇÃO: A resposta é o objeto direto, não tem .data
        if (item) {
          const displayValue = item[this.mergedConfig.displayField!];
          
          if (displayValue) {
            // 🎯 PERSISTIR: Salvar valor para proteger contra re-renders
            this.persistedDisplayValue = displayValue;
            this.persistedValueId = id;
            console.log(`💾 [RemoteSelect-DEEP] Valor persistido: ${displayValue}`);
            this.setSearchTerm(displayValue, 'loadSelectedItem-success');
          } else {
            console.warn(`⚠️ [RemoteSelect-DEEP] Campo ${this.mergedConfig.displayField} não encontrado no item:`, item);
          }
        }
      },
      error: (error: any) => {
        console.error(`❌ [RemoteSelect-DEEP] Erro HTTP para ID ${id}:`, error);
        // 🎯 FALLBACK: Tentar usar valor persistido em caso de erro
        if (this.persistedValueId === id && this.persistedDisplayValue) {
          console.log(`🔄 [RemoteSelect-DEEP] Usando fallback para ID ${id}: ${this.persistedDisplayValue}`);
          this.setSearchTerm(this.persistedDisplayValue, 'loadSelectedItem-error');
        }
      }
    });
  }
  
  // ========================================
  // 🎯 HELPERS E GETTERS
  // ========================================
  
  /**
   * 🔍 HELPER: Extrai informações do caller do stack trace
   */
  private extractCallerInfo(stack?: string): {file: string, function: string, line: string} {
    if (!stack) return {file: 'unknown', function: 'unknown', line: 'unknown'};
    
    const lines = stack.split('\n');
    // Pular as primeiras linhas (Error e writeValue) para pegar o verdadeiro caller
    for (let i = 2; i < Math.min(lines.length, 6); i++) {
      const line = lines[i];
      if (line && !line.includes('writeValue') && !line.includes('extractCallerInfo')) {
        // Extrair informações do formato: "at function (file:line:col)"
        const match = line.match(/at\s+(.+?)\s+\((.+):(\d+):\d+\)/);
        if (match) {
          return {
            function: match[1] || 'anonymous',
            file: match[2]?.split('/').pop() || 'unknown',
            line: match[3] || 'unknown'
          };
        }
        
        // Formato alternativo: "at file:line:col"
        const altMatch = line.match(/at\s+(.+):(\d+):\d+/);
        if (altMatch) {
          return {
            function: 'anonymous',
            file: altMatch[1]?.split('/').pop() || 'unknown',
            line: altMatch[2] || 'unknown'
          };
        }
      }
    }
    
    return {file: 'unknown', function: 'unknown', line: 'unknown'};
  }
  
  get hasValue(): boolean {
    return this.value !== null && this.value !== undefined && this.value !== '';
  }
  
  get placeholder(): string {
    return this.mergedConfig.placeholder || 'Digite para buscar...';
  }
  
  get isLoading(): boolean {
    return this.state.loading;
  }
  
  get hasError(): boolean {
    return !!this.state.error;
  }
  
  get errorMessage(): string {
    return this.state.error || '';
  }
  
  get canClear(): boolean {
    return this.hasValue && !this.disabled;
  }
  
  isItemSelected(index: number): boolean {
    // ✅ Para navegação por teclado (highlight)
    return index === this.selectedIndex;
  }
  
  isItemActuallySelected(item: RemoteSelectItem): boolean {
    // ✅ Para verificar se item está realmente selecionado
    return this.state.selectedItems.some(selected => selected.id === item.id);
  }
  
  // ========================================
  // 🎯 EVENTOS DE FOCUS/BLUR
  // ========================================
  
  onFocus() {
    // ✅ NOVO: Marcar input como focado
    this.inputFocused = true;
    
    // ✅ NOVO: Se já temos itens, mostrar dropdown
    if (this.state.items.length > 0) {
      this.state.dropdownOpen = true;
    }
    
    this.onTouched();
  }
  
  onBlur() {
    // ✅ NOVO: Marcar input como não focado
    this.inputFocused = false;
    
    // Delay para permitir clique nos itens do dropdown
    setTimeout(() => {
      this.closeDropdown();
    }, 200);
  }
  
  // ========================================
  // 🎯 MÉTODOS AUXILIARES PARA TEMPLATE
  // ========================================
  
  trackByFn(index: number, item: RemoteSelectItem): any {
    return item.id || index;
  }
  
  removeSelection(item: RemoteSelectItem): void {
    this.state.selectedItems = this.state.selectedItems.filter(i => i.id !== item.id);
    
    if (this.state.selectedItems.length === 0) {
      this.setValue(null);
    } else {
      const values = this.state.selectedItems.map(i => i.id);
      this.setValue(this.mergedConfig.multiple ? values : values[0]);
    }
  }
}