import { Component, OnInit, Input, OnChanges, SimpleChanges, AfterViewChecked } from '@angular/core';
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';

@Component({
  selector: 'app-pie-chart',
  templateUrl: './pie-chart.component.html',
  styleUrls: ['./pie-chart.component.scss']
})
export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked {
  @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
  // Multi-layer drilldown configuration inputs
  @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations

  public pieChartLabels: string[] = ['Category A', 'Category B', 'Category C'];
  public pieChartData: number[] = [30, 50, 20];
  public pieChartType: string = 'pie';
  public pieChartOptions: any = {
    responsive: true,
    maintainAspectRatio: false,
    plugins: {
      legend: {
        display: false // We'll create our own legend
      },
      tooltip: {
        enabled: true,
        mode: 'index',
        intersect: false,
        backgroundColor: 'rgba(0, 0, 0, 0.8)',
        titleFont: {
          size: 16,
          color: '#fff'
        },
        bodyFont: {
          size: 14,
          color: '#fff'
        },
        cornerRadius: 4,
        displayColors: false
      }
    },
    animation: {
      animateRotate: true,
      animateScale: false
    },
    elements: {
      arc: {
        borderWidth: 2,
        borderColor: '#fff'
      }
    }
  };
  
  // Chart colors for consistent styling
  private chartColors: string[] = [
    '#FF6384',
    '#36A2EB',
    '#FFCE56',
    '#4BC0C0',
    '#9966FF',
    '#FF9F40',
    '#FF6384',
    '#C9CBCF'
  ];
  
  // Multi-layer drilldown state tracking
  drilldownStack: any[] = []; // Stack to track drilldown navigation history
  currentDrilldownLevel: number = 0; // Current drilldown level (0 = base level)
  originalPieChartLabels: string[] = [];
  originalPieChartData: number[] = [];
  
  // No data state
  noDataAvailable: boolean = false;

  constructor(private dashboardService: Dashboard3Service) { }

  /**
   * Force chart redraw
   */
  public redrawChart(): void {
    // This method can be called to force a chart redraw if needed
    console.log('Redrawing pie chart');
    this.pieChartData = [...this.pieChartData];
  }
  
  ngOnInit(): void {
    console.log('PieChartComponent initialized with default data:', { labels: this.pieChartLabels, data: this.pieChartData });
    // Validate initial data
    this.validateChartData();
    this.fetchChartData();
  }

  ngOnChanges(changes: SimpleChanges): void {
    console.log('PieChartComponent 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;
    // 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;
    
    // Respond to input changes
    if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || 
        drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
        drilldownLayersChanged) {
      console.log('X or Y axis or table or connection or drilldown config changed, fetching new data');
      // Only fetch data if xAxis, yAxis, table, connection, or drilldown config has changed (and it's not the first change)
      this.fetchChartData();
    }
  }

  fetchChartData(): void {
    // If we're in drilldown mode, fetch the appropriate drilldown data
    if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
      this.fetchDrilldownData();
      return;
    }
    
    // If we have the necessary data, fetch chart data from the service
    if (this.table && this.xAxis && this.yAxis) {
      console.log('Fetching pie chart data for:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection });
      
      // Convert yAxis to string if it's an array
      const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;
      
      // Log the URL that will be called
      const url = `chart/getdashjson/pie?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`;
      console.log('Pie chart data URL:', url);
      
      // Fetch data from the dashboard service with parameter field and value
      // For base level, we pass empty parameter and value
      this.dashboardService.getChartData(this.table, 'pie', this.xAxis, yAxisString, this.connection, '', '').subscribe(
        (data: any) => {
          console.log('Received pie chart data:', data);
          if (data === null) {
            console.warn('Pie chart API returned null data. Check if the API endpoint is working correctly.');
            this.noDataAvailable = true;
            this.pieChartLabels = [];
            this.pieChartData = [];
            // Validate and sanitize data to show default data
            this.validateChartData();
            return;
          }
          
          // Handle the actual data structure returned by the API
          if (data && data.chartLabels && data.chartData) {
            // For pie charts, we need to extract the data differently
            // The first dataset's data array contains the values for the pie chart
            this.noDataAvailable = data.chartLabels.length === 0;
            this.pieChartLabels = data.chartLabels || [];
            if (data.chartData && data.chartData.length > 0) {
              this.pieChartData = data.chartData[0].data.map(value => {
                // Convert to number if it's not already
                const numValue = Number(value);
                return isNaN(numValue) ? 0 : numValue;
              });
            } else {
              this.pieChartData = [];
            }
            // Ensure labels and data arrays have the same length
            this.syncLabelAndDataArrays();
            // Validate and sanitize data
            this.validateChartData();
            // Trigger change detection
            this.pieChartData = [...this.pieChartData];
            console.log('Updated pie chart with data:', { labels: this.pieChartLabels, data: this.pieChartData });
          } else if (data && data.labels && data.data) {
            // Handle the original expected format as fallback
            this.noDataAvailable = data.labels.length === 0;
            this.pieChartLabels = data.labels || [];
            this.pieChartData = data.data.map(value => {
              // Convert to number if it's not already
              const numValue = Number(value);
              return isNaN(numValue) ? 0 : numValue;
            });
            // Ensure labels and data arrays have the same length
            this.syncLabelAndDataArrays();
            // Validate and sanitize data
            this.validateChartData();
            // Trigger change detection
            this.pieChartData = [...this.pieChartData];
            console.log('Updated pie chart with legacy data format:', { labels: this.pieChartLabels, data: this.pieChartData });
          } else {
            console.warn('Pie chart received data does not have expected structure', data);
            // Reset to default data
            this.noDataAvailable = true;
            this.pieChartLabels = [];
            this.pieChartData = [];
            // Validate and sanitize data to show default data
            this.validateChartData();
          }
        },
        (error) => {
          console.error('Error fetching pie chart data:', error);
          this.noDataAvailable = true;
          this.pieChartLabels = [];
          this.pieChartData = [];
          // Validate and sanitize data to show default data
          this.validateChartData();
        }
      );
    } else {
      console.log('Missing required data for pie chart, showing default data:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection });
      // Don't set noDataAvailable to true when there's no required data
      // This allows static data to be displayed
      this.noDataAvailable = false;
      // Validate the chart data to ensure we have some data to display
      this.validateChartData();
      // Force a redraw to ensure the chart displays
      this.pieChartData = [...this.pieChartData];
    }
  }
  
  // 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.noDataAvailable = true;
        this.pieChartLabels = [];
        this.pieChartData = [];
        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.noDataAvailable = true;
      this.pieChartLabels = [];
      this.pieChartData = [];
      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
    const url = `chart/getdashjson/pie?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
    console.log('Drilldown data URL:', url);
    
    // Fetch data from the dashboard service with parameter field and value
    // Backend handles filtering, we just pass the parameter field and value
    this.dashboardService.getChartData(actualApiUrl, 'pie', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue).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.noDataAvailable = true;
          this.pieChartLabels = [];
          this.pieChartData = [];
          return;
        }
        
        // Handle the actual data structure returned by the API
        if (data && data.chartLabels && data.chartData) {
          // For pie charts, we need to extract the data differently
          // The first dataset's data array contains the values for the pie chart
          this.noDataAvailable = data.chartLabels.length === 0;
          this.pieChartLabels = data.chartLabels || [];
          if (data.chartData && data.chartData.length > 0) {
            this.pieChartData = data.chartData[0].data.map(value => {
              // Convert to number if it's not already
              const numValue = Number(value);
              return isNaN(numValue) ? 0 : numValue;
            });
          } else {
            this.pieChartData = [];
          }
          // Ensure labels and data arrays have the same length
          this.syncLabelAndDataArrays();
          // Validate and sanitize data
          this.validateChartData();
          // Trigger change detection
          this.pieChartData = [...this.pieChartData];
          console.log('Updated pie chart with drilldown data:', { labels: this.pieChartLabels, data: this.pieChartData });
        } else if (data && data.labels && data.data) {
          // Handle the original expected format as fallback
          this.noDataAvailable = data.labels.length === 0;
          this.pieChartLabels = data.labels || [];
          this.pieChartData = data.data.map(value => {
            // Convert to number if it's not already
            const numValue = Number(value);
            return isNaN(numValue) ? 0 : numValue;
          });
          // Ensure labels and data arrays have the same length
          this.syncLabelAndDataArrays();
          // Validate and sanitize data
          this.validateChartData();
          // Trigger change detection
          this.pieChartData = [...this.pieChartData];
          console.log('Updated pie chart with drilldown legacy data format:', { labels: this.pieChartLabels, data: this.pieChartData });
        } else {
          console.warn('Drilldown received data does not have expected structure', data);
          this.noDataAvailable = true;
          this.pieChartLabels = [];
          this.pieChartData = [];
          // Validate and sanitize data
          this.validateChartData();
        }
      },
      (error) => {
        console.error('Error fetching drilldown data:', error);
        this.noDataAvailable = true;
        this.pieChartLabels = [];
        this.pieChartData = [];
        // Keep current data in case of error
      }
    );
  }
  
  // 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.originalPieChartLabels.length > 0) {
      this.pieChartLabels = [...this.originalPieChartLabels];
      console.log('Restored original labels');
    }
    if (this.originalPieChartData.length > 0) {
      this.pieChartData = [...this.originalPieChartData];
      console.log('Restored original data');
    }
    
    console.log('After reset - labels:', this.pieChartLabels);
    console.log('After reset - data:', this.pieChartData);
    
    // Re-fetch original data
    this.fetchChartData();
  }

  // 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();
    }
  }
  
  /**
   * Get color for legend item
   * @param index Index of the legend item
   */
  public getLegendColor(index: number): string {
    return this.chartColors[index % this.chartColors.length];
  }

  /**
   * Ensure labels and data arrays have the same length
   */
  private syncLabelAndDataArrays(): void {
    // Ensure we have matching arrays
    if (this.pieChartLabels.length !== this.pieChartData.length) {
      const maxLength = Math.max(this.pieChartLabels.length, this.pieChartData.length);
      while (this.pieChartLabels.length < maxLength) {
        this.pieChartLabels.push(`Label ${this.pieChartLabels.length + 1}`);
      }
      while (this.pieChartData.length < maxLength) {
        this.pieChartData.push(0);
      }
    }
  }
  
  /**
   * Validate and sanitize chart data
   */
  private validateChartData(): void {
    console.log('Validating chart data:', { labels: this.pieChartLabels, data: this.pieChartData });
    
    // Ensure we have valid arrays
    if (!Array.isArray(this.pieChartLabels)) {
      this.pieChartLabels = [];
    }
    
    if (!Array.isArray(this.pieChartData)) {
      this.pieChartData = [];
    }
    
    // Ensure we have some data to display
    if (this.pieChartLabels.length === 0 && this.pieChartData.length === 0) {
      // Add default data to ensure chart visibility
      this.pieChartLabels = ['Category A', 'Category B', 'Category C'];
      this.pieChartData = [30, 50, 20];
      console.log('Added default data for chart display');
    }
    
    // Ensure labels and data arrays have the same length
    this.syncLabelAndDataArrays();
    
    // Ensure all data values are numbers
    this.pieChartData = this.pieChartData.map(value => {
      const numValue = Number(value);
      return isNaN(numValue) ? 0 : numValue;
    });
    
    console.log('After validation:', { labels: this.pieChartLabels, data: this.pieChartData });
  }
  
  ngAfterViewChecked() {
    // Debugging: Log component state after view checks
    console.log('PieChartComponent state:', {
      labels: this.pieChartLabels,
      data: this.pieChartData,
      hasData: this.pieChartLabels.length > 0 && this.pieChartData.length > 0
    });
  }
  
  /**
   * Check if chart data is valid and ready to display
   */
  public isChartDataValid(): boolean {
    return this.pieChartLabels && this.pieChartData && 
           Array.isArray(this.pieChartLabels) && Array.isArray(this.pieChartData) &&
           this.pieChartLabels.length > 0 && this.pieChartData.length > 0 &&
           this.pieChartLabels.length === this.pieChartData.length;
  }
  
  // events
  public chartClicked(e: any): void {
    console.log('Pie chart clicked:', e);
    
    // If drilldown is enabled and we have a valid click event
    if (this.drilldownEnabled && e.active && e.active.length > 0) {
      // Get the index of the clicked element
      const clickedIndex = e.active[0].index;
      
      // Get the label of the clicked element
      const clickedLabel = this.pieChartLabels[clickedIndex];
      
      console.log('Clicked on pie slice:', { index: clickedIndex, label: clickedLabel });
      
      // If we're not at the base level, store original data
      if (this.currentDrilldownLevel === 0) {
        // Store original data before entering drilldown mode
        this.originalPieChartLabels = [...this.pieChartLabels];
        this.originalPieChartData = [...this.pieChartData];
        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,
          clickedIndex: clickedIndex,
          clickedLabel: clickedLabel,
          clickedValue: clickedLabel // Using label as value for now
        };
        
        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 or invalid click event');
    }
  }

  public chartHovered(e: any): void {
    console.log(e);
  }
}