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

@Component({
  selector: 'app-grid-view',
  templateUrl: './grid-view.component.html',
  styleUrls: ['./grid-view.component.scss']
})
export class GridViewComponent implements OnInit, OnChanges, OnDestroy {
  @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

  loading = false;
  givendata: any[] = [];
  orders;
  error: string;
  modalAdd = false;
  modaledit = false;
  modaldelete = false;
  rowSelected: any = {};
  mcreate;
  medit;
  showdata;
  submitted = false;
  dynamicHeaders: any[] = [];

  // Multi-layer drilldown state tracking
  drilldownStack: any[] = []; // Stack to track drilldown navigation history
  currentDrilldownLevel: number = 0; // Current drilldown level (0 = base level)
  originalGridData: any[] = [];

  // No data state
  noDataAvailable: boolean = false;

  // Flag to prevent infinite loops
  private isFetchingData: boolean = false;

  // Add subscriptions to unsubscribe on destroy
  private subscriptions: Subscription[] = [];

  // Add a flag to track if filters have been initialized
  private filtersInitialized: boolean = false;

  // Add properties to track open multiselect dropdowns
  private openMultiselects: Map<string, string> = new Map(); // Map of filterId -> context

  // Add property to track document click handler
  private documentClickHandler: ((event: MouseEvent) => void) | null = null;

  constructor(
    private mainservice: UsergrpmaintainceService,
    private dashboardService: Dashboard3Service,
    // Add FilterService to constructor
    private filterService: FilterService
  ) { }

  ngOnInit(): void {
    // Subscribe to filter changes
    this.subscriptions.push(
      this.filterService.filterState$.subscribe(filters => {
        // When filters change, refresh the grid data
        console.log('GridView: Filter state changed:', filters);
        this.fetchGridData();
      })
    );

    this.fetchGridData();
  }

  ngOnChanges(changes: SimpleChanges): void {
    console.log('GridViewComponent input changes:', changes);

    // 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;
    const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange;
    // Drilldown configuration changes
    const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange;
    const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange;
    const drilldownXAxisChanged = changes.drilldownXAxis && !changes.drilldownXAxis.firstChange;
    const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange;
    const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange;

    // Initialize filter values if they haven't been initialized yet
    if (!this.filtersInitialized && (changes.baseFilters || changes.drilldownFilters || changes.drilldownLayers)) {
      this.initializeFilterValues();
      this.filtersInitialized = true;
    }

    // Respond to input changes
    if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged ||
      drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
      drilldownLayersChanged)) {
      console.log('X or Y axis or table or connection or base filters or drilldown config changed, fetching new data');
      // Only fetch data if xAxis, yAxis, table, connection, baseFilters or drilldown config has changed (and it's not the first change)
      this.fetchGridData();
    }
  }

  // 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
    });
  }

  // Dynamic headers for the grid

  fetchGridData(): void {
    // Set flag to prevent recursive calls
    this.isFetchingData = true;

    // If we're in drilldown mode, fetch the appropriate drilldown data
    if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
      this.fetchDrilldownData();
      // Reset flag after fetching
      this.isFetchingData = false;
      return;
    }

    // If we have the necessary data, fetch grid data from the service
    // if (this.table && this.xAxis) {
    if (this.table) {

      console.log('=== GRID VIEW DEBUG INFO ===');
      console.log('Table:', this.table);
      console.log('X-Axis:', this.xAxis);
      console.log('Y-Axis:', this.yAxis);
      console.log('Connection:', this.connection);

      // Convert yAxis to string if it's an array
      const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;

      // Get the parameter value from the drilldown stack for base level (should be empty)
      let parameterValue = '';

      // Log the URL that will be called
      let url = `chart/getdashjson/grid?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`;
      console.log('Grid data URL:', url);

      // Get filter parameters from base filters
      const filterObj = {};

      // Add base filters
      if (this.baseFilters && this.baseFilters.length > 0) {
        this.baseFilters.forEach(filter => {
          if (filter.field && filter.value) {
            filterObj[filter.field] = filter.value;
          }
        });
      }

      // Add common filters directly as key-value pairs
      const commonFilters = this.filterService.getFilterValues();
      const filterDefinitions = this.filterService.getFilters();

      // Add common filters using the field name as the key
      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 !== '') {
            filterObj[fieldName] = filterValue;
          }
        }
      });

      // Convert to JSON string for API call
      let filterParams = '';
      if (Object.keys(filterObj).length > 0) {
        filterParams = JSON.stringify(filterObj);
      }

      console.log('GridView: Final filter object to send to API:', filterObj);

      // Fetch data from the dashboard service, similar to other chart components
      this.dashboardService.getChartData(this.table, 'grid', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
        (data: any) => {
          console.log('=== GRID VIEW DATA RESPONSE ===');
          console.log('Received grid data:', data);
          if (data === null) {
            console.warn('Grid API returned null data. Check if the API endpoint is working correctly.');
            this.error = "No data Available";
            this.noDataAvailable = true;
            // Reset flag after fetching
            this.isFetchingData = false;
            return;
          }

          // Handle the actual data structure returned by the API
          if (data && data.chartData) {
            this.givendata = data.chartData;
            this.extractDynamicHeaders(data.chartData);
            this.error = this.givendata.length === 0 ? "No data Available" : undefined;
            this.noDataAvailable = this.givendata.length === 0;
            console.log('Updated grid with data:', this.givendata);
          } else if (data && data.data) {
            // Handle the original expected format as fallback
            this.givendata = data.data;
            this.extractDynamicHeaders(data.data);
            this.error = this.givendata.length === 0 ? "No data Available" : undefined;
            this.noDataAvailable = this.givendata.length === 0;
            console.log('Updated grid with legacy data format:', this.givendata);
          } else if (Array.isArray(data)) {
            // Handle case where data is directly an array
            this.givendata = data;
            this.extractDynamicHeaders(data);
            this.error = this.givendata.length === 0 ? "No data Available" : undefined;
            this.noDataAvailable = this.givendata.length === 0;
            console.log('Updated grid with array data:', this.givendata);
          } else {
            console.warn('Grid received data does not have expected structure', data);
            this.error = "No valid data received";
            this.givendata = [];
            this.noDataAvailable = true;
          }
          // Reset flag after fetching
          this.isFetchingData = false;
        }, (error) => {
          console.log('Error fetching grid data:', error);
          this.error = "Server Error";
          this.noDataAvailable = true;
          // Reset flag after fetching
          this.isFetchingData = false;
        });
    } else if (this.table) {
      console.log('Missing xAxis, falling back to default data fetching');
      // Fallback to default data fetching when only table is provided
      // Convert yAxis to string if it's an array
      const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;

      // Fetch data from the dashboard service, similar to other chart components
      this.dashboardService.getChartData(this.table, 'grid', this.xAxis, yAxisString, this.connection).subscribe(
        (data: any) => {
          // this.mainservice.getAll().subscribe((data: any) => {
          console.log('recv data ', data);
          this.givendata = Array.isArray(data) ? data : [];
          this.extractDynamicHeaders(data);
          this.error = this.givendata && this.givendata.length === 0 ? "No data Available" : undefined;
          this.noDataAvailable = this.givendata && this.givendata.length === 0;
          // Reset flag after fetching
          this.isFetchingData = false;
        }, (error) => {
          console.log(error);
          this.error = "Server Error";
          this.noDataAvailable = true;
          // Reset flag after fetching
          this.isFetchingData = false;
        });
    } else {
      console.log('Missing required data for grid:', { table: this.table });
      this.error = "Table name is required";
      this.noDataAvailable = true;
      // Reset flag after fetching
      this.isFetchingData = false;
    }
  }

  // Fetch drilldown data based on current drilldown level
  fetchDrilldownData(): void {
    console.log('Fetching drilldown data, current level:', this.currentDrilldownLevel);
    console.log('Drilldown stack:', this.drilldownStack);

    // Get the current drilldown configuration based on the current level
    let drilldownConfig;
    if (this.currentDrilldownLevel === 1) {
      // Base drilldown level
      drilldownConfig = {
        apiUrl: this.drilldownApiUrl,
        xAxis: this.drilldownXAxis,
        yAxis: this.drilldownYAxis,
        parameter: this.drilldownParameter
      };
    } else {
      // Multi-layer drilldown level
      const layerIndex = this.currentDrilldownLevel - 2; // -2 because level 1 is base drilldown
      if (layerIndex >= 0 && layerIndex < this.drilldownLayers.length) {
        drilldownConfig = this.drilldownLayers[layerIndex];
      } else {
        console.warn('Invalid drilldown layer index:', layerIndex);
        this.error = "Invalid drilldown configuration";
        this.givendata = [];
        this.noDataAvailable = true;
        return;
      }
    }

    console.log('Drilldown config for level', this.currentDrilldownLevel, ':', drilldownConfig);

    // Check if we have valid drilldown configuration
    if (!drilldownConfig || !drilldownConfig.apiUrl || !drilldownConfig.xAxis || !drilldownConfig.yAxis) {
      console.warn('Missing drilldown configuration for level:', this.currentDrilldownLevel);
      this.error = "Missing drilldown configuration";
      this.givendata = [];
      this.noDataAvailable = true;
      return;
    }

    // Get the parameter value from the drilldown stack
    let parameterValue = '';
    if (this.drilldownStack.length > 0) {
      const lastEntry = this.drilldownStack[this.drilldownStack.length - 1];
      parameterValue = lastEntry.clickedValue || '';
      console.log('Parameter value from last click:', parameterValue);
    }

    // Get the parameter field from drilldown config
    const parameterField = drilldownConfig.parameter || '';
    console.log('Parameter field:', parameterField);

    console.log('Fetching drilldown data for level:', this.currentDrilldownLevel, {
      apiUrl: drilldownConfig.apiUrl,
      xAxis: drilldownConfig.xAxis,
      yAxis: drilldownConfig.yAxis,
      parameterField: parameterField,
      parameterValue: parameterValue,
      connection: this.connection
    });

    // Build the actual API URL with parameter replacement
    let actualApiUrl = drilldownConfig.apiUrl;
    console.log('Original API URL:', actualApiUrl);
    console.log('Parameter value to use:', parameterValue);
    console.log('Parameter field:', parameterField);

    // Check if the URL contains angle brackets for parameter replacement
    const hasAngleBrackets = /<[^>]+>/.test(actualApiUrl);

    if (hasAngleBrackets && parameterValue) {
      // Replace angle brackets placeholder with actual value
      console.log('Replacing angle brackets with parameter value');
      const encodedValue = encodeURIComponent(parameterValue);
      actualApiUrl = actualApiUrl.replace(/<[^>]+>/g, encodedValue);
      console.log('URL after angle bracket replacement:', actualApiUrl);
    }

    // Log the URL that will be called
    let url = `chart/getdashjson/grid?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
    if (parameterField && parameterValue) {
      url += `&parameter=${encodeURIComponent(parameterField)}&parameterValue=${encodeURIComponent(parameterValue)}`;
    }
    console.log('Drilldown data URL:', url);

    // Convert drilldown layer filters to filter parameters (if applicable)
    const filterObj = {};

    // Add drilldown layer filters
    if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
      drilldownConfig.filters.forEach((filter: any) => {
        if (filter.field && filter.value) {
          filterObj[filter.field] = filter.value;
        }
      });
    }

    // Add drilldownFilters
    if (this.drilldownFilters && this.drilldownFilters.length > 0) {
      this.drilldownFilters.forEach(filter => {
        if (filter.field && filter.value) {
          filterObj[filter.field] = filter.value;
        }
      });
    }

    // Add common filters
    const commonFilters = this.filterService.getFilterValues();
    const filterDefinitions = this.filterService.getFilters();
    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 !== '') {
          filterObj[fieldName] = filterValue;
        }
      }
    });

    // Convert to JSON string for API call
    let drilldownFilterParams = '';
    if (Object.keys(filterObj).length > 0) {
      drilldownFilterParams = JSON.stringify(filterObj);
    }

    console.log('Drilldown filter parameters:', drilldownFilterParams);

    // For drilldown level, we pass the parameter value from the drilldown stack and drilldown filters
    this.dashboardService.getChartData(
      drilldownConfig.apiUrl, 'grid',
      drilldownConfig.xAxis, drilldownConfig.yAxis,
      this.connection,
      parameterField, parameterValue,
      drilldownFilterParams
    ).subscribe(
      (data: any) => {
        console.log('Received drilldown data:', data);
        if (data === null) {
          console.warn('Drilldown API returned null data. Check if the API endpoint is working correctly.');
          this.error = "No data Available";
          this.givendata = [];
          this.noDataAvailable = true;
          return;
        }

        // Handle the actual data structure returned by the API
        if (data && data.chartData) {
          this.givendata = data.chartData;
          this.extractDynamicHeaders(data.chartData);
          this.error = this.givendata.length === 0 ? "No data Available" : undefined;
          this.noDataAvailable = this.givendata.length === 0;
          console.log('Updated grid with drilldown data:', this.givendata);
        } else if (data && data.data) {
          // Handle the original expected format as fallback
          this.givendata = data.data;
          this.extractDynamicHeaders(data.data);
          this.error = this.givendata.length === 0 ? "No data Available" : undefined;
          this.noDataAvailable = this.givendata.length === 0;
          console.log('Updated grid with drilldown legacy data format:', this.givendata);
        } else if (Array.isArray(data)) {
          // Handle case where data is directly an array
          this.givendata = data;
          this.extractDynamicHeaders(data);
          this.error = this.givendata.length === 0 ? "No data Available" : undefined;
          this.noDataAvailable = this.givendata.length === 0;
          console.log('Updated grid with drilldown array data:', this.givendata);
        } else {
          console.warn('Drilldown received data does not have expected structure', data);
          this.error = "No valid data received";
          this.givendata = [];
          this.noDataAvailable = true;
        }
      },
      (error) => {
        console.error('Error fetching drilldown data:', error);
        this.error = "Server Error";
        this.givendata = [];
        this.noDataAvailable = true;
      }
    );
  }

  // Reset to original data (go back to base level)
  resetToOriginalData(): void {
    console.log('Resetting to original data');
    console.log('Current stack before reset:', this.drilldownStack);
    console.log('Current level before reset:', this.currentDrilldownLevel);

    this.currentDrilldownLevel = 0;
    this.drilldownStack = [];

    if (this.originalGridData.length > 0) {
      // Create a deep copy to avoid reference issues
      this.givendata = JSON.parse(JSON.stringify(this.originalGridData));
      this.extractDynamicHeaders(this.givendata);
      console.log('Restored original data');
    }

    console.log('After reset - data:', this.givendata);

    // Re-fetch original data
    this.fetchGridData();
  }

  // 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.fetchDrilldownData();
      } else {
        // Back to base level
        console.log('Back to base level, resetting to original data');
        this.resetToOriginalData();
      }
    } else {
      // Already at base level, reset to original data
      console.log('Already at base level, resetting to original data');
      this.resetToOriginalData();
    }
  }

  // Method to handle grid row clicks for drilldown
  onRowClick(item: any, key: string): void {
    console.log('Grid row clicked:', { item, key });

    // If drilldown is enabled
    if (this.drilldownEnabled) {
      // Get the value for the clicked key
      const clickedValue = item[key];

      console.log('Clicked on row value:', { key, value: clickedValue });

      // If we're not at the base level, store original data
      if (this.currentDrilldownLevel === 0) {
        // Store original data before entering drilldown mode
        // Create a deep copy to avoid reference issues
        this.originalGridData = JSON.parse(JSON.stringify(this.givendata));
        console.log('Stored original data for drilldown');
      }

      // Determine the next drilldown level
      const nextDrilldownLevel = this.currentDrilldownLevel + 1;

      console.log('Next drilldown level will be:', nextDrilldownLevel);

      // Check if there's a drilldown configuration for this level
      let hasDrilldownConfig = false;
      let drilldownConfig;

      if (nextDrilldownLevel === 1) {
        // Base drilldown level
        drilldownConfig = {
          apiUrl: this.drilldownApiUrl,
          xAxis: this.drilldownXAxis,
          yAxis: this.drilldownYAxis,
          parameter: this.drilldownParameter
        };
        hasDrilldownConfig = !!this.drilldownApiUrl && !!this.drilldownXAxis && !!this.drilldownYAxis;
      } else {
        // Multi-layer drilldown level
        const layerIndex = nextDrilldownLevel - 2; // -2 because level 1 is base drilldown
        if (layerIndex < this.drilldownLayers.length) {
          drilldownConfig = this.drilldownLayers[layerIndex];
          hasDrilldownConfig = drilldownConfig.enabled &&
            !!drilldownConfig.apiUrl &&
            !!drilldownConfig.xAxis &&
            !!drilldownConfig.yAxis;
        }
      }

      console.log('Drilldown config for next level:', drilldownConfig);
      console.log('Has drilldown config:', hasDrilldownConfig);

      // If there's a drilldown configuration for the next level, proceed
      if (hasDrilldownConfig) {
        // Add this click to the drilldown stack
        const stackEntry = {
          level: nextDrilldownLevel,
          clickedKey: key,
          clickedValue: clickedValue
        };

        this.drilldownStack.push(stackEntry);

        console.log('Added to drilldown stack:', stackEntry);
        console.log('Current drilldown stack:', this.drilldownStack);

        // Update the current drilldown level
        this.currentDrilldownLevel = nextDrilldownLevel;

        console.log('Entering drilldown level:', this.currentDrilldownLevel);

        // Fetch drilldown data for the new level
        this.fetchDrilldownData();
      } else {
        console.log('No drilldown configuration for level:', nextDrilldownLevel);
      }
    } else {
      console.log('Drilldown not enabled');
    }
  }

  /**
   * Extract dynamic headers from the data
   * @param data Array of data objects
   */
  private extractDynamicHeaders(data: any): void {
    // Ensure data is an array
    const dataArray = Array.isArray(data) ? data : [];

    if (dataArray && dataArray.length > 0) {
      // Get all unique keys from the data objects
      const allKeys = new Set<string>();
      dataArray.forEach(item => {
        if (item && typeof item === 'object') {
          Object.keys(item).forEach(key => allKeys.add(key));
        }
      });

      // Convert to array of header objects with key and display name
      this.dynamicHeaders = Array.from(allKeys).map(key => ({
        key: key,
        displayName: this.formatHeader(key)
      }));

      console.log('Dynamic headers extracted:', this.dynamicHeaders);
    } else {
      this.dynamicHeaders = [];
    }
  }

  /**
   * Format header name for better display
   * @param key The key to format
   */
  private formatHeader(key: string): string {
    // Convert camelCase to Title Case
    return key
      .replace(/([A-Z])/g, ' $1')
      .replace(/^./, str => str.toUpperCase());
  }

  // 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.fetchGridData();
  }

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

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

  // 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.fetchGridData();
  }

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

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

  // 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.fetchGridData();
  }

  ngOnDestroy() {
    // Unsubscribe from all subscriptions to prevent memory leaks
    console.log('GridViewComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions');
    this.subscriptions.forEach(subscription => {
      if (subscription && !subscription.closed) {
        subscription.unsubscribe();
      }
    });
    this.subscriptions = [];

    // Clear data to help with garbage collection
    this.givendata = [];
    this.dynamicHeaders = [];
    this.drilldownStack = [];
    this.originalGridData = [];

    // Clear multiselect tracking
    this.openMultiselects.clear();
    
    // Remove document click handler
    this.removeDocumentClickHandler();
    
    console.log('GridViewComponent destroyed and cleaned up');
  }
}