import { Component, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core';
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
import { FilterService } from '../../common-filter/filter.service';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-to-do-chart',
  templateUrl: './to-do-chart.component.html',
  styleUrls: ['./to-do-chart.component.scss']
})
export class ToDoChartComponent implements OnInit, OnChanges {
  @Input() xAxis: string;
  @Input() yAxis: string | string[];
  @Input() table: string;
  @Input() datastore: string;
  @Input() charttitle: string;
  @Input() chartlegend: boolean = true;
  @Input() showlabel: boolean = true;
  @Input() chartcolor: boolean;
  @Input() slices: boolean;
  @Input() donut: boolean;
  @Input() charturl: string;
  @Input() chartparameter: string;
  @Input() datasource: string;
  @Input() fieldName: string;
  @Input() connection: number; // Add connection input
  // Drilldown configuration inputs
  @Input() drilldownEnabled: boolean = false;
  @Input() drilldownApiUrl: string;
  @Input() drilldownXAxis: string;
  @Input() drilldownYAxis: string;
  @Input() drilldownParameter: string; // Add drilldown parameter input
  @Input() baseFilters: any[] = []; // Add base filters input
  @Input() drilldownFilters: any[] = []; // Add drilldown filters input
  // Multi-layer drilldown configuration inputs
  @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
  
  // Multi-layer drilldown state tracking
  drilldownStack: any[] = []; // Stack to track drilldown navigation history
  currentDrilldownLevel: number = 0; // Current drilldown level (0 = base level)
  originalTodoList: string[] = [];

  constructor(
    private dashboardService: Dashboard3Service,
    private filterService: FilterService
  ) { }
  
  ngOnInit(): void {
    // Subscribe to filter changes
    this.subscriptions.push(
      this.filterService.filterState$.subscribe(filters => {
        // When filters change, refresh the chart data
        this.fetchToDoData();
      })
    );
    
    // Initialize with default data
    this.fetchToDoData();
  }
  
  ngOnChanges(changes: SimpleChanges): void {
    console.log('ToDoChartComponent input changes:', changes);
    
    // Initialize filter values if they haven't been initialized yet
    if (!this.filtersInitialized && (changes.baseFilters || changes.drilldownFilters || changes.drilldownLayers)) {
      this.initializeFilterValues();
      this.filtersInitialized = true;
    }
    
    // Check if any of the key properties have changed
    const xAxisChanged = changes.xAxis && !changes.xAxis.firstChange;
    const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange;
    const tableChanged = changes.table && !changes.table.firstChange;
    const connectionChanged = changes.connection && !changes.connection.firstChange; // Add connection change detection
    
    // Respond to input changes
    if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged) {
      console.log('X or Y axis or table or connection changed, fetching new data');
      // Only fetch data if xAxis, yAxis, table, or connection has changed (and it's not the first change)
      this.fetchToDoData();
    }
  }
  
  data: any;
  todo: string;
  todoList: string[] = [];
  
  // Add properties for filter functionality
  private openMultiselects: Map<string, string> = new Map(); // Map of filterId -> context
  private documentClickHandler: ((event: MouseEvent) => void) | null = null;
  private filtersInitialized: boolean = false;
  
  // Subscriptions to unsubscribe on destroy
  private subscriptions: Subscription[] = [];
  
  fetchToDoData(): void {
    // If we have the necessary data, fetch to-do data from the service
    if (this.table && this.xAxis) {
      console.log('Fetching to-do data for:', { table: this.table, xAxis: this.xAxis, connection: this.connection });
      
      // Convert baseFilters to filter parameters
      let filterParams = '';
      if (this.baseFilters && this.baseFilters.length > 0) {
        const filterObj = {};
        this.baseFilters.forEach(filter => {
          if (filter.field && filter.value) {
            filterObj[filter.field] = filter.value;
          }
        });
        if (Object.keys(filterObj).length > 0) {
          filterParams = JSON.stringify(filterObj);
        }
      }
      
      // Add common filters to filter parameters
      const commonFilters = this.filterService.getFilterValues();
      console.log('Common filters from service:', commonFilters);
      
      if (Object.keys(commonFilters).length > 0) {
        // Merge common filters with base filters
        const mergedFilterObj = {};
        
        // Add base filters first
        if (filterParams) {
          try {
            const baseFilterObj = JSON.parse(filterParams);
            Object.assign(mergedFilterObj, baseFilterObj);
          } catch (e) {
            console.warn('Failed to parse base filter parameters:', e);
          }
        }
        
        // Add common filters using the field name as the key, not the filter id
        Object.keys(commonFilters).forEach(filterId => {
          const filterValue = commonFilters[filterId];
          // Find the filter definition to get the field name
          const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
          if (filterDef && filterDef.field) {
            const fieldName = filterDef.field;
            if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
              mergedFilterObj[fieldName] = filterValue;
            }
          } else {
            // Fallback to using filterId as field name if no field is defined
            if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
              mergedFilterObj[filterId] = filterValue;
            }
          }
        });
        
        if (Object.keys(mergedFilterObj).length > 0) {
          filterParams = JSON.stringify(mergedFilterObj);
        }
      }
      
      console.log('Final filter parameters:', filterParams);
      
      // Fetch data from the dashboard service
      this.dashboardService.getChartData(this.table, 'todo', this.xAxis, '', this.connection, '', '', filterParams).subscribe(
        (data: any) => {
          console.log('Received to-do chart data:', data);
          if (data === null) {
            console.warn('To-do chart API returned null data. Check if the API endpoint is working correctly.');
            this.todoList = [];
            return;
          }
          
          // Handle the actual data structure returned by the API
          if (data && data.chartLabels) {
            // Use chartLabels as the todo items
            this.todoList = data.chartLabels;
          } else if (data && data.labels) {
            // Fallback to labels if chartLabels is not available
            this.todoList = data.labels;
          } else {
            console.warn('To-do chart received data does not have expected structure', data);
            this.todoList = [];
          }
        },
        (error) => {
          console.error('Error fetching to-do chart data:', error);
          this.todoList = [];
        }
      );
    } else {
      console.log('Missing required data for to-do chart:', { table: this.table, xAxis: this.xAxis });
      // Initialize with default data if no table is specified
      if (this.todoList.length === 0) {
        this.todoList = ['Sample Task 1', 'Sample Task 2', 'Sample Task 3'];
      }
    }
  }

  public addTodo(todo: string) {
    if (todo && todo.trim() !== '') {
      this.todoList.push(todo.trim());
      this.todo = ''; // Clear the input field
    }
  }

  public removeTodo(todoIx: number) {
    if (this.todoList.length) {
        this.todoList.splice(todoIx, 1);
    }
  }
  
  // Navigate back to previous drilldown level
  navigateBack(): void {
    console.log('Navigating back, current stack:', this.drilldownStack);
    console.log('Current level:', this.currentDrilldownLevel);
    
    if (this.drilldownStack.length > 0) {
      // Remove the last entry from the stack
      const removedEntry = this.drilldownStack.pop();
      console.log('Removed entry from stack:', removedEntry);
      
      // Update the current drilldown level
      this.currentDrilldownLevel = this.drilldownStack.length;
      console.log('New level after pop:', this.currentDrilldownLevel);
      console.log('Stack after pop:', this.drilldownStack);
      
      if (this.drilldownStack.length > 0) {
        // Fetch data for the previous level
        console.log('Fetching data for previous level');
        this.fetchToDoData();
      } else {
        // Back to base level
        console.log('Back to base level, resetting to original data');
        this.todoList = [...this.originalTodoList];
      }
    } else {
      // Already at base level, reset to original data
      console.log('Already at base level, resetting to original data');
      this.todoList = [...this.originalTodoList];
    }
  }
  
  // Initialize filter values with proper default values based on type
  private initializeFilterValues(): void {
    console.log('Initializing filter values');
    
    // Initialize base filters
    if (this.baseFilters) {
      this.baseFilters.forEach(filter => {
        if (filter.value === undefined || filter.value === null) {
          switch (filter.type) {
            case 'multiselect':
              filter.value = [];
              break;
            case 'date-range':
              filter.value = { start: null, end: null };
              break;
            case 'toggle':
              filter.value = false;
              break;
            default:
              filter.value = '';
          }
        }
      });
    }
    
    // Initialize drilldown filters
    if (this.drilldownFilters) {
      this.drilldownFilters.forEach(filter => {
        if (filter.value === undefined || filter.value === null) {
          switch (filter.type) {
            case 'multiselect':
              filter.value = [];
              break;
            case 'date-range':
              filter.value = { start: null, end: null };
              break;
            case 'toggle':
              filter.value = false;
              break;
            default:
              filter.value = '';
          }
        }
      });
    }
    
    // Initialize layer filters
    if (this.drilldownLayers) {
      this.drilldownLayers.forEach(layer => {
        if (layer.filters) {
          layer.filters.forEach((filter: any) => {
            if (filter.value === undefined || filter.value === null) {
              switch (filter.type) {
                case 'multiselect':
                  filter.value = [];
                  break;
                case 'date-range':
                  filter.value = { start: null, end: null };
                  break;
                case 'toggle':
                  filter.value = false;
                  break;
                default:
                  filter.value = '';
              }
            }
          });
        }
      });
    }
    
    console.log('Filter values initialized:', {
      baseFilters: this.baseFilters,
      drilldownFilters: this.drilldownFilters,
      drilldownLayers: this.drilldownLayers
    });
  }

  // Check if there are active filters
  hasActiveFilters(): boolean {
    return (this.baseFilters && this.baseFilters.length > 0) || 
           (this.drilldownFilters && this.drilldownFilters.length > 0) || 
           this.hasActiveLayerFilters();
  }

  // Check if there are active layer filters for current drilldown level
  hasActiveLayerFilters(): boolean {
    if (this.currentDrilldownLevel > 1 && this.drilldownLayers && this.drilldownLayers.length > 0) {
      const layerIndex = this.currentDrilldownLevel - 2; // -2 because level 1 is base drilldown
      return layerIndex < this.drilldownLayers.length && 
             this.drilldownLayers[layerIndex].filters && 
             this.drilldownLayers[layerIndex].filters.length > 0;
    }
    return false;
  }

  // Get active layer filters for current drilldown level
  getActiveLayerFilters(): any[] {
    if (this.currentDrilldownLevel > 1 && this.drilldownLayers && this.drilldownLayers.length > 0) {
      const layerIndex = this.currentDrilldownLevel - 2; // -2 because level 1 is base drilldown
      if (layerIndex < this.drilldownLayers.length && 
          this.drilldownLayers[layerIndex].filters) {
        return this.drilldownLayers[layerIndex].filters;
      }
    }
    return [];
  }

  // Get filter options for dropdown/multiselect filters
  getFilterOptions(filter: any): string[] {
    if (filter.options) {
      if (Array.isArray(filter.options)) {
        return filter.options;
      } else if (typeof filter.options === 'string') {
        return filter.options.split(',').map(opt => opt.trim()).filter(opt => opt);
      }
    }
    return [];
  }

  // Check if an option is selected for multiselect filters
  isOptionSelected(filter: any, option: string): boolean {
    if (!filter.value) {
      return false;
    }
    
    if (Array.isArray(filter.value)) {
      return filter.value.includes(option);
    }
    
    return filter.value === option;
  }

  // Handle base filter changes
  onBaseFilterChange(filter: any): void {
    console.log('Base filter changed:', filter);
    // Refresh data when filter changes
    this.fetchToDoData();
  }

  // Handle drilldown filter changes
  onDrilldownFilterChange(filter: any): void {
    console.log('Drilldown filter changed:', filter);
    // Refresh data when filter changes
    this.fetchToDoData();
  }

  // Handle layer filter changes
  onLayerFilterChange(filter: any): void {
    console.log('Layer filter changed:', filter);
    // Refresh data when filter changes
    this.fetchToDoData();
  }

  // Handle multiselect changes
  onMultiSelectChange(filter: any, option: string, event: any): void {
    const checked = event.target.checked;
    
    // Initialize filter.value as array if it's not already
    if (!Array.isArray(filter.value)) {
      filter.value = [];
    }
    
    if (checked) {
      // Add option to array if not already present
      if (!filter.value.includes(option)) {
        filter.value.push(option);
      }
    } else {
      // Remove option from array
      filter.value = filter.value.filter((item: string) => item !== option);
    }
    
    // Refresh data when filter changes
    this.fetchToDoData();
  }

  // Handle date range changes
  onDateRangeChange(filter: any, dateRange: { start: string | null, end: string | null }): void {
    filter.value = dateRange;
    // Refresh data when filter changes
    this.fetchToDoData();
  }

  // Handle toggle changes
  onToggleChange(filter: any, checked: boolean): void {
    filter.value = checked;
    // Refresh data when filter changes
    this.fetchToDoData();
  }

  // Toggle multiselect dropdown visibility
  toggleMultiselect(filter: any, context: string): void {
    const filterId = `${context}-${filter.field}`;
    if (this.isMultiselectOpen(filter, context)) {
      this.openMultiselects.delete(filterId);
    } else {
      // Close all other multiselects first
      this.openMultiselects.clear();
      this.openMultiselects.set(filterId, context);
      
      // Add document click handler to close dropdown when clicking outside
      this.addDocumentClickHandler();
    }
  }

  // Add document click handler to close dropdowns when clicking outside
  private addDocumentClickHandler(): void {
    if (!this.documentClickHandler) {
      this.documentClickHandler = (event: MouseEvent) => {
        const target = event.target as HTMLElement;
        // Check if click is outside any multiselect dropdown
        if (!target.closest('.multiselect-container')) {
          this.openMultiselects.clear();
          this.removeDocumentClickHandler();
        }
      };
      
      // Use setTimeout to ensure the click event that opened the dropdown doesn't immediately close it
      setTimeout(() => {
        document.addEventListener('click', this.documentClickHandler!);
      }, 0);
    }
  }

  // Remove document click handler
  private removeDocumentClickHandler(): void {
    if (this.documentClickHandler) {
      document.removeEventListener('click', this.documentClickHandler);
      this.documentClickHandler = null;
    }
  }

  // Check if multiselect dropdown is open
  isMultiselectOpen(filter: any, context: string): boolean {
    const filterId = `${context}-${filter.field}`;
    return this.openMultiselects.has(filterId);
  }

  // Get count of selected options for a multiselect filter
  getSelectedOptionsCount(filter: any): number {
    if (!filter.value) {
      return 0;
    }
    
    if (Array.isArray(filter.value)) {
      return filter.value.length;
    }
    
    return 0;
  }

  // Clear all filters
  clearAllFilters(): void {
    // Clear base filters
    if (this.baseFilters) {
      this.baseFilters.forEach(filter => {
        if (filter.type === 'multiselect') {
          filter.value = [];
        } else if (filter.type === 'date-range') {
          filter.value = { start: null, end: null };
        } else if (filter.type === 'toggle') {
          filter.value = false;
        } else {
          filter.value = '';
        }
      });
    }
    
    // Clear drilldown filters
    if (this.drilldownFilters) {
      this.drilldownFilters.forEach(filter => {
        if (filter.type === 'multiselect') {
          filter.value = [];
        } else if (filter.type === 'date-range') {
          filter.value = { start: null, end: null };
        } else if (filter.type === 'toggle') {
          filter.value = false;
        } else {
          filter.value = '';
        }
      });
    }
    
    // Clear layer filters
    if (this.drilldownLayers) {
      this.drilldownLayers.forEach(layer => {
        if (layer.filters) {
          layer.filters.forEach((filter: any) => {
            if (filter.type === 'multiselect') {
              filter.value = [];
            } else if (filter.type === 'date-range') {
              filter.value = { start: null, end: null };
            } else if (filter.type === 'toggle') {
              filter.value = false;
            } else {
              filter.value = '';
            }
          });
        }
      });
    }
    
    // Close all multiselect dropdowns
    this.openMultiselects.clear();
    
    // Refresh data
    this.fetchToDoData();
  }
  
  ngOnDestroy(): void {
    // Unsubscribe from all subscriptions to prevent memory leaks
    this.subscriptions.forEach(subscription => subscription.unsubscribe());
    
    // Remove document click handler if it exists
    this.removeDocumentClickHandler();
  }
}