import { OnInit, ViewChild, OnDestroy, ChangeDetectorRef, Directive } from "@angular/core";
import { Subscription, Observable } from "rxjs";

import { TitleService } from "../../services/theme/title.service";
import { HeaderActionsService } from "../../services/header-actions.service";
import { TabSystemComponent } from "../tab-system/tab-system.component";
import { TabItem, TabSystemConfig } from "../tab-system/interfaces/tab-system.interface";
import { Logger } from '../../services/logger/logger.service';
import { SideCardConfig } from '../../interfaces/sidecard.config.interface';

/**
 * 🎯 BaseDomainComponent - Componente Base Abstrato para Domínios ERP
 * 
 * Este componente abstrato encapsula todos os padrões comuns dos domínios:
 * - ✅ Sistema de abas integrado
 * - ✅ CRUD operations padronizadas
 * - ✅ Gerenciamento de estado unificado
 * - ✅ Header actions configuráveis
 * - ✅ Paginação server-side
 * - ✅ Prevenção de duplicatas
 * - ✅ Event handling padronizado
 * 
 * ## 🚀 Como usar em novos domínios:
 * 
 * ```typescript
 * @Component({
 *   selector: 'app-clients',
 *   template: `<base-domain [config]="domainConfig"></base-domain>`
 * })
 * export class ClientsComponent extends BaseDomainComponent<Client> {
 *   constructor(
 *     clientsService: ClientsService,
 *     titleService: TitleService,
 *     headerActionsService: HeaderActionsService,
 *     cdr: ChangeDetectorRef
 *   ) {
 *     super(titleService, headerActionsService, cdr, clientsService);
 *   }
 * 
 *   protected getDomainConfig(): DomainConfig {
 *     return {
 *       domain: 'client',
 *       title: 'Clientes',
 *       entityName: 'cliente',
 *       subTabs: ['dados', 'contatos', 'financeiro'],
 *       columns: [...]
 *     };
 *   }
 * }
 * ```
 */

export interface DomainConfig {
  domain: string;                    // ID do domínio (ex: 'driver', 'vehicle', 'client')
  title: string;                     // Título para header (ex: 'Motoristas')
  entityName: string;                // Nome da entidade (ex: 'motorista', 'veículo')
  subTabs: string[];                 // Sub-abas para edição ['dados', 'endereco', 'documentos']
  columns: any[];                    // Configuração das colunas da tabela
  pageSize?: number;                 // Tamanho padrão da página (default: 10)
  maxTabs?: number;                  // Máximo de abas abertas (default: 5)
  allowDuplicates?: boolean;         // Permitir abas duplicadas (default: false)
  customActions?: any[];             // Ações customizadas além do padrão edit/new
  sideCard?: SideCardConfig;         // ✨ Configuração do card lateral
}

export interface DomainService<T> {
  getEntities(page: number, pageSize: number, filters: any): Observable<{
    data: T[];
    totalCount: number;
    pageCount: number;
    currentPage: number;
  }>;
}

@Directive()
export abstract class BaseDomainComponent<T> implements OnInit, OnDestroy {
  @ViewChild('tabSystem') tabSystem!: TabSystemComponent;

  protected logger: Logger;
  protected subscriptions = new Subscription();
  
  // Domain data (generic)
  entities: T[] = [];
  currentPage = 1;
  itemsPerPage = 10;
  totalItems = 0;
  totalPages = 0;
  isLoading = false;
  currentFilters: { [key: string]: string } = {};
  
  // Configuration
  protected domainConfig!: DomainConfig;
  
  // Controle de inicialização para prevenir loops
  private _isInitialized = false;
  private _isLoadingEntities = false;
  private _setupDomainCalled = false;
  private _lastLoadTime = 0;
  
  // Tab system configuration
  tabConfig: TabSystemConfig = {
    maxTabs: 5,
    allowDuplicates: false,
    confirmClose: true
  };

  tabEvents = {
    onMaxTabsReached: () => {
      console.warn('Limite máximo de abas atingido!');
    },
    onUnsavedChanges: (tabs: TabItem[]) => {
      console.warn('Existem mudanças não salvas:', tabs);
    }
  };

  // Table configuration (will be set by domain config)
  tableConfig: any = {};

  constructor(
    protected titleService: TitleService,
    protected headerActionsService: HeaderActionsService,
    protected cdr: ChangeDetectorRef,
    protected entityService: DomainService<T>
  ) {
    this.logger = new Logger(this.constructor.name);
  }

  ngOnInit() {
    if (this._isInitialized) {
      console.warn('[BaseDomainComponent] Tentativa de re-inicialização bloqueada');
      return;
    }
    
    this.domainConfig = this.getDomainConfig();
    this.setupDomain();
    this._isInitialized = true;
  }



  ngOnDestroy() {
    this.subscriptions.unsubscribe();
    try {
      this.headerActionsService.clearConfig();
    } catch (error) {
      console.error('Erro ao limpar header:', error);
    }
  }

  // ========================================
  // 🎯 MÉTODOS ABSTRATOS (implementar nos domínios)
  // ========================================

  /**
   * Deve retornar a configuração específica do domínio
   */
  protected abstract getDomainConfig(): DomainConfig;

  /**
   * Pode ser sobrescrito para customizar criação de nova entidade
   */
  protected getNewEntityData(): Partial<T> {
    return {};
  }

  // ========================================
  // 🏗️ SETUP E CONFIGURAÇÃO
  // ========================================

  private setupDomain(): void {
    if (this._setupDomainCalled) {
      console.warn('[BaseDomainComponent] setupDomain já foi executado, evitando duplicação');
      return;
    }
    
    this._setupDomainCalled = true;
    
    // Setup título
    this.titleService.setTitle(this.domainConfig.title);
    
    // Setup configurações
    this.itemsPerPage = this.domainConfig.pageSize || 10;
    this.tabConfig.maxTabs = this.domainConfig.maxTabs || 5;
    this.tabConfig.allowDuplicates = this.domainConfig.allowDuplicates || false;
    
    // Setup tabela
    this.setupTableConfig();
    
    // Setup header actions
    this.configureHeaderActions();
    
    // Carregar dados
    this.loadEntities();
  }

  private setupTableConfig(): void {
    this.tableConfig = {
      columns: this.domainConfig.columns,
      pageSize: this.itemsPerPage,
      pageSizeOptions: [5, 10, 25, 50],
      showFirstLastButtons: true,
      actions: [
        {
          icon: "fas fa-edit",
          label: "Editar",
          action: "edit"
        },
        ...(this.domainConfig.customActions || [])
      ]
    };
  }

  // ========================================
  // 🔄 CRUD OPERATIONS (GENÉRICAS)
  // ========================================

  loadEntities(currentPage = this.currentPage, itemsPerPage = this.itemsPerPage) {
    const now = Date.now();
    
    // 🛡️ PROTEÇÃO CONTRA LOOP: Não carregar se já está carregando ou se a última chamada foi muito recente
    if (this.isLoading || this._isLoadingEntities) {
      console.warn('[BaseDomainComponent] Tentativa de carregamento rejeitada - já está carregando');
      return;
    }
    
    // Proteção contra chamadas muito frequentes (75ms - tempo moderado entre responsividade e proteção)
    if (now - this._lastLoadTime < 75) {
      console.warn('[BaseDomainComponent] Tentativa de carregamento rejeitada - chamada muito frequente (tempo desde última:', now - this._lastLoadTime, 'ms)');
      return;
    }
    
    this._lastLoadTime = now;
    this.isLoading = true;
    this._isLoadingEntities = true;
    
    this.entityService
      .getEntities(currentPage, itemsPerPage, this.currentFilters)
      .subscribe({
        next: (response) => {
          this.entities = response.data;
          this.totalItems = response.totalCount;
          this.totalPages = response.pageCount;
          this.currentPage = response.currentPage;
          this.isLoading = false;
          this._isLoadingEntities = false;

          this.headerActionsService.updateRecordCount(this.totalItems);
          
          // 🔧 OTIMIZAÇÃO: Criar aba apenas UMA VEZ, não em loop
          if (this.tabSystem && this.tabSystem.getTabs().length === 0) {
            this.createListTab();
          } else if (this.tabSystem) {
            this.updateListTabData();
          }
          
          // Forçar detecção de mudanças de forma controlada
          this.cdr.detectChanges();
        },
        error: (error) => {
          console.error("Erro ao carregar entidades:", error);
          this.isLoading = false;
          this._isLoadingEntities = false;
        },
      });
  }

  async createNew(): Promise<void> {
    await this.tabSystem.tabSystemService.openCreateTab(
      this.domainConfig.domain, 
      this.getNewEntityData()
    );
  }

  async editEntity(entityData: any): Promise<void> {
    const success = await this.tabSystem.tabSystemService.openTabWithSubTabs(
      this.domainConfig.domain, 
      entityData, 
      this.domainConfig.subTabs,
      undefined, // customTitle
      this.domainConfig.sideCard // ✨ Passar configuração do side card
    );
    
    if (!success) {
      console.error('Falha ao abrir aba de edição');
    }
  }

  // ========================================
  // 📊 TABLE EVENTS (GENÉRICOS)
  // ========================================

  onSort(event: { field: string; direction: "asc" | "desc" }) {
    const { field, direction } = event;
    this.entities = [...this.entities].sort((a: any, b: any) => {
      const isAsc = direction === "asc";
      return this.compare(a[field], b[field], isAsc);
    });
  }

  onPage(event: { page: number; pageSize: number }) {
    const maxPage = Math.ceil(this.totalItems / event.pageSize);
    const validPage = Math.min(event.page, maxPage);
    
    // Condições mais claras para debugging
    const pageChanged = this.currentPage !== validPage;
    const pageSizeChanged = this.itemsPerPage !== event.pageSize;
    const shouldLoad = pageChanged || pageSizeChanged;

    if (shouldLoad) {
      // Atualizar o estado antes de carregar para evitar condições de corrida
      this.currentPage = validPage;
      this.itemsPerPage = event.pageSize;
      
      this.loadEntities(validPage, event.pageSize);
    }
  }

  onFilter(filters: { [key: string]: string }) {
    // Verificar se realmente houve mudança nos filtros
    const filtersChanged = JSON.stringify(this.currentFilters) !== JSON.stringify(filters);
    
    this.currentFilters = filters;
    
    // ✅ Só resetar para página 1 se realmente houve mudança de filtros
    if (filtersChanged) {
      this.currentPage = 1;
    }
    
    this.loadEntities();
  }

  onColumnsChange(columns: any[]) {
    this.tableConfig = { ...this.tableConfig, columns };
  }

  onActionClick(event: { action: string; data: any }) {
    switch (event.action) {
      case "new":
        this.createNew();
        break;
      case "edit":
        this.editEntity(event.data);
        break;
      default:
        this.handleCustomAction(event.action, event.data);
        break;
    }
  }

  onTableEvent(eventData: { event: string, data: any }): void {
    const { event, data } = eventData;
    
    switch (event) {
      case 'sort':
        this.onSort(data);
        break;
      case 'page':
        this.onPage(data);
        break;
      case 'filter':
        this.onFilter(data);
        break;
      case 'columnsChange':
        this.onColumnsChange(data);
        break;
      case 'actionClick':
        this.onActionClick(data);
        break;
      case 'formSubmit':
        this.onFormSubmit(data);
        break;
    }
  }

  // ========================================
  // 🎯 TAB SYSTEM EVENTS (GENÉRICOS)
  // ========================================

  onTabSelected(tab: TabItem): void {
    console.log('Aba selecionada:', tab?.title);
  }

  onTabClosed(tab: TabItem): void {
    console.log('Aba fechada:', tab?.title);
  }

  onTabAdded(tab: TabItem): void {
    console.log('Aba adicionada:', tab?.title);
  }

  // ========================================
  // 🏗️ HELPER METHODS (GENÉRICOS)
  // ========================================

  private async createListTab(): Promise<void> {
    const listType = `${this.domainConfig.domain}s-list`;
    const listTitle = `Lista de ${this.domainConfig.title}`;
    
    const tabData = {
      items: this.entities,
      [this.domainConfig.domain + 's']: this.entities, // Backward compatibility
      totalItems: this.totalItems,
      currentPage: this.currentPage,
      totalPages: this.totalPages,
      tableConfig: this.tableConfig,
      isLoading: this.isLoading
    };

    const listTab: TabItem = {
      id: listType,
      title: listTitle,
      type: listType,
      data: tabData,
      isLoading: false,
      isModified: false
    };
    
    await this.tabSystem.addTab(listTab);
  }

  private updateListTabData(): void {
    if (!this.tabSystem) return;

    const listType = `${this.domainConfig.domain}s-list`;
    const listTabIndex = this.tabSystem.getTabs().findIndex(tab => tab.type === listType);
    
    if (listTabIndex >= 0) {
      const updatedData = {
        items: this.entities,
        [this.domainConfig.domain + 's']: this.entities,
        totalItems: this.totalItems,
        currentPage: this.currentPage,
        totalPages: this.totalPages,
        tableConfig: this.tableConfig,
        isLoading: this.isLoading
      };
      
      this.tabSystem.tabSystemService.updateTab(listTabIndex, updatedData);
      
      // Forçar detecção de mudanças
      this.cdr.detectChanges();
    }
  }

  private configureHeaderActions(): void {
    this.headerActionsService.setDomainConfig({
      domain: this.domainConfig.domain,
      title: this.domainConfig.title,
      recordCount: this.totalItems,
      actions: [
        {
          id: `new-${this.domainConfig.domain}`,
          label: `Novo ${this.domainConfig.entityName}`,
          icon: 'add',
          type: 'primary',
          action: () => this.createNew(),
          visible: true,
          tooltip: `Criar novo ${this.domainConfig.entityName}`
        }
      ]
    });
  }

  /**
   * 🚀 GENÉRICO: Lidar com salvamento de formulários
   */
  protected onFormSubmit(data: any): void {
    const { tab, formData, isNewItem, onSuccess, onError } = data;
    
    console.log(`${isNewItem ? 'Criando' : 'Atualizando'} ${this.domainConfig.entityName}...`);
    
    // Determinar qual método do service usar
    const saveOperation = isNewItem 
      ? this.createEntity(formData)
      : this.updateEntity(tab.data.id, formData);
    
    if (saveOperation) {
      saveOperation.subscribe({
        next: (response: any) => {
          console.log(`✅ ${this.domainConfig.entityName} salvo com sucesso:`, response);
          
          // 🎯 NOVO: Atualizar lista automaticamente após salvar
          this.updateListAfterSave(response, isNewItem);
          
          onSuccess(response);
        },
        error: (error: any) => {
          console.error(`❌ Erro ao salvar ${this.domainConfig.entityName}:`, error);
          onError(error);
        }
      });
    } else {
      // Fallback se não há service específico
      this.simulateSave(formData, isNewItem, tab, onSuccess, onError);
    }
  }

  /**
   * 🎯 NOVO: Atualiza a lista automaticamente após salvar
   * - Para CRIAÇÃO: Adiciona o novo item à lista
   * - Para EDIÇÃO: Atualiza o item existente na lista
   * - Atualiza contadores e interface
   */
  private updateListAfterSave(savedEntity: any, isNewItem: boolean): void {
    console.log('🎯 updateListAfterSave chamado:', { savedEntity, isNewItem });
    
    if (isNewItem) {
      // ✅ CRIAÇÃO: Adicionar novo item à lista (no início para melhor UX)
      this.entities = [savedEntity, ...this.entities];
      this.totalItems += 1;
      
      // Recalcular páginas se necessário
      this.totalPages = Math.ceil(this.totalItems / this.itemsPerPage);
      
      console.log(`✅ Novo ${this.domainConfig.entityName} adicionado à lista:`, savedEntity);
      
    } else {
      // ✅ EDIÇÃO: Atualizar item existente na lista
      // Extrair ID da resposta (pode estar em savedEntity.id ou savedEntity.data.id)
      const savedEntityId = savedEntity?.id || savedEntity?.data?.id;
      
      console.log('🔍 Procurando item na lista com ID:', savedEntityId);
      
      const index = this.entities.findIndex((entity: any) => entity.id === savedEntityId);
      
      if (index >= 0) {
        // Manter dados existentes e sobrescrever com os novos
        // Se savedEntity tem uma estrutura aninhada (.data), usar essa estrutura
        const updatedData = savedEntity?.data || savedEntity;
        this.entities[index] = { ...this.entities[index], ...updatedData };
        
        console.log(`✅ ${this.domainConfig.entityName} atualizado na lista:`, {
          index,
          oldData: this.entities[index],
          newData: updatedData
        });
      } else {
        console.warn(`⚠️ Item com ID ${savedEntityId} não encontrado na lista para atualização`);
        console.log('📋 IDs disponíveis na lista:', this.entities.map((e: any) => e.id));
        
        // Fallback: adicionar à lista mesmo sendo edição (pode ter sido criado em outra sessão)
        const entityToAdd = savedEntity?.data || savedEntity;
        this.entities = [entityToAdd, ...this.entities];
        this.totalItems += 1;
        this.totalPages = Math.ceil(this.totalItems / this.itemsPerPage);
      }
    }
    
    // 🔄 Atualizar interface automaticamente
    this.updateListTabData();
    this.headerActionsService.updateRecordCount(this.totalItems);
    this.cdr.detectChanges();
    
    console.log('✅ Lista atualizada com sucesso');
  }

  /**
   * Método para criar entidade - deve ser sobrescrito nos domínios se necessário
   */
  protected createEntity(data: any): Observable<any> | null {
    // Por padrão, tentar chamar um método genérico se existir
    const service = this.entityService as any;
    if (service.create) {
      return service.create(data);
    }
    return null;
  }

  /**
   * Método para atualizar entidade - deve ser sobrescrito nos domínios se necessário
   */
  protected updateEntity(id: any, data: any): Observable<any> | null {
    // Por padrão, tentar chamar um método genérico se existir
    const service = this.entityService as any;
    if (service.update) {
      return service.update(id, data);
    }
    return null;
  }

  /**
   * Simular salvamento quando não há service específico
   */
  private simulateSave(formData: any, isNewItem: boolean, tab: any, onSuccess: Function, onError: Function): void {
    console.warn(`${this.domainConfig.entityName}Service não disponível, simulando salvamento...`);
    
    setTimeout(() => {
      try {
        // 🎯 MELHORADO: Criar resposta mais completa para atualização do formulário
        const response = {
          success: true,
          ...formData, // Incluir todos os dados do formulário
          id: isNewItem ? Math.random().toString(36).substr(2, 9) : tab.data.id,
          updated_at: new Date().toISOString(),
          // Adicionar campos que podem ter sido processados pelo backend
          created_at: isNewItem ? new Date().toISOString() : tab.data.created_at
        };

        console.log(`✅ ${this.domainConfig.entityName} salvo com sucesso (simulado):`, response);
        
        // 🎯 USAR A MESMA LÓGICA: Atualizar lista automaticamente
        this.updateListAfterSave(response, isNewItem);
        
        onSuccess(response);
        
      } catch (error) {
        console.error(`❌ Erro ao salvar ${this.domainConfig.entityName}:`, error);
        onError(error);
      }
    }, 1500);
  }

  /**
   * Método para ações customizadas - pode ser sobrescrito nos domínios
   */
  protected handleCustomAction(action: string, data: any): void {
    console.warn(`Ação customizada não implementada: ${action}`, data);
  }

  private compare(a: number | string, b: number | string, isAsc: boolean) {
    return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
  }
} 