import { Component, OnInit } from '@angular/core';
import { ToastrService } from 'ngx-toastr';
import { AlertService } from 'src/app/services/alert.service';
import { Data_lakeservice } from './Data_lake.service';
import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators, ValidationErrors } from '@angular/forms';
import { ExtensionService } from 'src/app/services/fnd/extension.service';
import { DashboardContentModel2 } from 'src/app/models/builder/dashboard';
import { Data_lakecardvariable } from './Data_lake_cardvariable';
import { UserInfoService } from 'src/app/services/user-info.service';
import { SureconnectService } from '../sureconnect/sureconnect.service';
import { HttpClient } from '@angular/common/http';
import { ApiRequestService } from 'src/app/services/api/api-request.service';
declare var JsBarcode: any;
@Component({
  selector: 'app-Data_lake',
  templateUrl: './Data_lake.component.html',
  styleUrls: ['./Data_lake.component.scss']
})
export class Data_lakeComponent implements OnInit {
  cardButton = Data_lakecardvariable.cardButton;
  cardmodeldata = Data_lakecardvariable.cardmodeldata;
  public dashboardArray: DashboardContentModel2[];
  isCardview = Data_lakecardvariable.cardButton;
  cardmodal; changeView() {
    this.isCardview = !this.isCardview;
  }
  beforeText(fieldtext: string): string { // Extract the text before the first '<'
    const index = fieldtext.indexOf('<');
    return index !== -1 ? fieldtext.substring(0, index) : fieldtext;
  }
  afterText(fieldtext: string): string { // Extract the text after the last '>'
    const index = fieldtext.lastIndexOf('>');
    return index !== -1 ? fieldtext.substring(index + 1) : '';
  }
  transform(fieldtext: string): string {
    const match = fieldtext.match(/<([^>]*)>/);
    return match ? match[1] : ''; // Extract the text between '<' and '>'
  }
  userrole;
  rowSelected: any = {};
  modaldelete = false;
  modalEdit = false;
  modalAdd = false;
  public entryForm: FormGroup;
  loading = false;
  product;
  modalOpenedforNewLine = false;
  newLine: any;
  additionalFieldsFromBackend: any[] = [];
  formcode = 'Data_lake_formCode'
  tableName = 'Data_lake'; checkFormCode; selected: any[] = [];

  // New properties for URL handling
  urlModalOpen = false;
  selectedUrl = '';

  // Cron job builder properties
  addCronExpression = '';
  editCronExpression = '';

  // SureConnect properties
  sureConnectList;
  selectedSureConnect: any = null;

  // Calculated field properties
  calculatedFieldModalOpen = false;
  availableKeys: string[] = [];
  selectedDataLakeItem: any = null;
  calculatedFieldForm: FormGroup;
  calculatedFields: any[] = [];
  constantCounter = 1; // Persistent counter for unique constant names

  // New properties for constant value input
  constantValueModalOpen = false;
  currentConstantName = '';
  currentConstantValue = '';
  pendingEquationUpdate = '';
  
  // New properties for group by functionality
  groupByFields: string[] = [];
  selectedGroupByFields: string[] = [];
  showGroupByModal = false;
  
  // Aggregation operations
  aggregationOperations = [
    { value: 'count', label: 'Count' },
    { value: 'sum', label: 'Sum' },
    { value: 'avg', label: 'Average' },
    { value: 'min', label: 'Minimum' },
    { value: 'max', label: 'Maximum' },
    { value: 'median', label: 'Median' },
    { value: 'mode', label: 'Mode' },
    { value: 'stdev', label: 'Standard Deviation' }
  ];
  
  selectedAggregationFields: { field: string; operation: string }[] = [];
  
  constructor(
    private extensionService: ExtensionService,
    private userInfoService: UserInfoService,
    private mainService: Data_lakeservice,
    private alertService: AlertService,
    private toastr: ToastrService,
    private _fb: FormBuilder,
    private sureConnectService: SureconnectService,
    private http: HttpClient,
    private apiRequest: ApiRequestService
  ) { }
  private editInterval: any;
  // component button 
  ngOnInit(): void {
    if (this.cardmodeldata !== '') {
      this.cardmodal = JSON.parse(this.cardmodeldata);
      this.dashboardArray = this.cardmodal.dashboard.slice();
      console.log(this.dashboardArray)
    }
    this.userrole = this.userInfoService.getRoles();
    this.getData();
    this.getSureConnectList(); // Fetch SureConnect list
    this.entryForm = this._fb.group({
      name: [null],

      url: [null],

      schedule: [null],

      cron_job: [null],

      json: [null],

      url_endpoint: [null],

      batch_volume: [null],

      sure_connect_id: [null], // Add SureConnect field

    }); // component_button200
    // form code start
    this.extensionService.getJsonObjectsByFormCodeList(this.formcode).subscribe(data => {
      console.log(data);
      const jsonArray = data.map((str) => JSON.parse(str));
      this.additionalFieldsFromBackend = jsonArray;
      this.checkFormCode = this.additionalFieldsFromBackend.some(field => field.formCode === "Data_lake_formCode");
      console.log(this.checkFormCode);
      console.log(this.additionalFieldsFromBackend);
      if (this.additionalFieldsFromBackend && this.additionalFieldsFromBackend.length > 0) {
        this.additionalFieldsFromBackend.forEach(field => {
          if (field.formCode === this.formcode) {
            if (!this.entryForm.contains(field.extValue)) {
              // Add the control only if it doesn't exist in the form
              this.entryForm.addControl(field.extValue, this._fb.control(field.fieldValue));
            }
          }
        });
      }
    });
    console.log(this.entryForm.value);
    // form code end 

    // Initialize calculated field form with FormArray for multiple fields
    this.calculatedFieldForm = this._fb.group({
      fieldName: [''],
      operation: [''],
      complexEquation: [''], // Add complex equation field
      fieldComponents: this._fb.array([this.createFieldComponent()])
    });
    
    // Add real-time validation for complex equation
    this.calculatedFieldForm.get('complexEquation')?.valueChanges.subscribe(value => {
      if (this.calculatedFieldForm.get('operation')?.value === 'complex' && value) {
        this.analyzeComplexEquation(value);
      }
    });
  }
  
  // Helper method to create a field component group
  createFieldComponent(): FormGroup {
    return this._fb.group({
      field: [''],
      constant: ['']
    });
  }
  
  // Getter for field components FormArray
  getFieldComponents(): FormArray {
    return this.calculatedFieldForm.get('fieldComponents') as FormArray;
  }
  
  // Method to add a new field component
  addFieldComponent(): void {
    this.getFieldComponents().push(this.createFieldComponent());
  }
  
  // Method to remove a field component
  removeFieldComponent(index: number): void {
    if (this.getFieldComponents().length > 1) {
      this.getFieldComponents().removeAt(index);
    }
  }
  ngOnDestroy(): void {
    if (this.editInterval) {
      clearInterval(this.editInterval);
    }
  }



  error;
  getData() {
    this.mainService.getAll().subscribe((data) => {
      console.log(data);
      this.product = data;
      this.product = [...this.product].reverse(); if (this.product.length == 0) {
        this.error = "No Data Available"
      }
    }, (error) => {
      console.log(error);
      if (error) {
        this.error = "Server Error";
      }
    });
  }

  // Fetch SureConnect list
  getSureConnectList() {
    this.sureConnectService.getAll().subscribe((data: any[]) => {
      this.sureConnectList = data;
      console.log('SureConnect List:', this.sureConnectList);
    }, (error) => {
      console.log('Error fetching SureConnect list:', error);
    });
  }

  // Get operation symbol for display
  getOperationSymbol(operation: string): string {
    switch(operation) {
      case 'add': return '+';
      case 'subtract': return '-';
      case 'multiply': return '*';
      case 'divide': return '/';
      case 'percentage': return '%';
      case 'concat': return '||'; // Concatenation symbol
      default: return '';
    }
  }

  // Fetch available keys from API
  fetchAvailableKeys(dataLakeItem: any) {
    if (!dataLakeItem.url || !dataLakeItem.sure_connect_id) {
      this.toastr.error('URL and SureConnect ID are required to fetch keys');
      return;
    }
    
    this.selectedDataLakeItem = dataLakeItem;
    
    // Call the service method to get all keys
    this.mainService.fetchAvailableKeys(dataLakeItem.url, dataLakeItem.sure_connect_id).subscribe(
      (keys: string[]) => {
        this.availableKeys = keys;
        // Reset the calculated field form to ensure it starts fresh
        this.resetCalculatedFieldForm();
        this.calculatedFieldModalOpen = true;
        console.log('Available keys:', keys);
      },
      (error) => {
        console.error('Error fetching keys:', error);
        this.toastr.error('Failed to fetch available keys from API');
      }
    );
  }
  
  // Reset the calculated field form to initial state
  resetCalculatedFieldForm(): void {
    this.calculatedFieldForm.reset({
      fieldName: '',
      operation: '',
      complexEquation: '',
      fieldComponents: [{}] // Start with one empty field component
    });
    
    // Ensure we have exactly one empty field component
    const fieldComponents = this.getFieldComponents();
    fieldComponents.clear();
    fieldComponents.push(this.createFieldComponent());
    
    // Reset the constant counter for new calculations
    this.constantCounter = 1;
  }

  // Add calculated field
  addCalculatedField() {
    const formData = this.calculatedFieldForm.value;

    if (!formData.fieldName || (!formData.operation && formData.operation !== 'complex')) {
      this.toastr.error('Field name and operation are required');
      return;
    }

    // Handle complex equation separately
    if (formData.operation === 'complex') {
      if (!formData.complexEquation || formData.complexEquation.trim() === '') {
        this.toastr.error('Complex equation is required');
        return;
      }

      // Validate complex equation format
      if (!this.validateComplexEquation(formData.complexEquation)) {
        return;
      }

      // Extract constants used in the equation
      const fieldRefs = this.extractFieldReferences(formData.complexEquation);
      const equationConstants: any[] = [];
      
      for (const fieldRef of fieldRefs) {
        // Check if it's a constant (constant_X format)
        if (fieldRef.startsWith('constant_') && /^\d+$/.test(fieldRef.substring(9))) {
          // Find the constant value from existing calculated fields
          let constantValue = '';
          for (const field of this.calculatedFields) {
            if (field.operation === 'constant' && field.fieldName === fieldRef) {
              if (field.fieldComponents && field.fieldComponents.length > 0) {
                constantValue = field.fieldComponents[0].constant;
                break;
              }
            }
          }
          
          if (constantValue) {
            equationConstants.push({
              field: fieldRef,
              constant: constantValue,
              isConstant: true
            });
          }
        }
      }

      // Create calculated field object for complex equation
      const calculatedField = {
        id: Date.now(),
        fieldName: formData.fieldName,
        operation: 'complex',
        complexEquation: formData.complexEquation,
        fieldComponents: equationConstants // Include constants used in the equation
      };

      this.calculatedFields.push(calculatedField);
      this.toastr.success('Complex calculated field added successfully');

      // Reset form but keep one empty field component
      this.calculatedFieldForm.reset({
        fieldName: '',
        operation: '',
        complexEquation: '',
        fieldComponents: [{}]
      });
      return;
    }

    // Filter out empty field components
    const validFieldComponents = formData.fieldComponents.filter(component => 
      component.field || component.constant
    );

    if (validFieldComponents.length === 0) {
      this.toastr.error('At least one field or constant is required');
      return;
    }

    // Validate constant values - must be numeric for all operations except concatenation
    if (formData.operation !== 'concat') {
      for (const component of validFieldComponents) {
        if (component.constant && component.constant.trim() !== '') {
          const numericValue = Number(component.constant);
          if (isNaN(numericValue)) {
            this.toastr.error('Constant values must be numeric for this operation');
            return;
          }
        }
      }
    }
    
    // Validate that constant values are unique within this calculated field
    const constantValues = validFieldComponents
      .map(component => component.constant)
      .filter(constant => constant && constant.trim() !== '');
    
    if (constantValues.length !== new Set(constantValues).size) {
      this.toastr.error('Constant values must be unique within a calculated field');
      return;
    }
    
    // Generate unique names for constants using the persistent counter
    const processedFieldComponents = validFieldComponents.map(component => {
      if (component.constant && component.constant.trim() !== '') {
        // Generate a unique name for the constant using the persistent counter
        const constantName = `constant_${this.constantCounter++}`;
        return {
          field: constantName,
          constant: component.constant,
          isConstant: true // Flag to indicate this is a constant with a generated name
        };
      }
      return {
        field: component.field,
        constant: component.constant,
        isConstant: false // Flag to indicate this is a regular field
      };
    });

    // Create calculated field object with multiple field components
    const calculatedField = {
      id: Date.now(), // Simple ID generation
      fieldName: formData.fieldName,
      operation: formData.operation,
      fieldComponents: processedFieldComponents
    };

    this.calculatedFields.push(calculatedField);
    this.toastr.success('Calculated field added successfully');

    // Reset form but keep one empty field component
    this.calculatedFieldForm.reset({
      fieldName: '',
      operation: '',
      complexEquation: '',
      fieldComponents: [{}]
    });
  }

  // Validate complex equation format
  validateComplexEquation(equation: string): boolean {
    // Updated validation to include additional operators
    const validPattern = /^[a-zA-Z0-9_+\-*/().\[\]{}^%>=<!&|\s]+$/;
    if (!validPattern.test(equation)) {
      this.toastr.error('Invalid complex equation format. Only alphanumeric characters, underscores, and operators (+, -, *, /, (, ), [, ], {, }, ^, %, =, >, <, !, &, |) are allowed.');
      return false;
    }

    // Check for empty equation
    if (!equation || equation.trim() === '') {
      this.toastr.error('Complex equation cannot be empty');
      return false;
    }

    // Extract all field/constant references from the equation
    const fieldRefs = this.extractFieldReferences(equation);
    
    // Validate each reference
    const invalidReferences: string[] = [];
    for (const fieldRef of fieldRefs) {
      // Skip if it's a direct numeric value
      if (!isNaN(Number(fieldRef))) {
        continue;
      }
      
      // Check if it's a predefined constant (constant_X format)
      if (fieldRef.startsWith('constant_') && /^\d+$/.test(fieldRef.substring(9))) {
        // Check if this constant has been defined in previous calculated fields
        let constantFound = false;
        for (const field of this.calculatedFields) {
          if (field.operation === 'constant' && field.fieldName === fieldRef) {
            constantFound = true;
            break;
          }
        }
        
        if (!constantFound) {
          invalidReferences.push(`Referenced constant '${fieldRef}' has not been defined`);
        }
        continue;
      }
      
      // Check if field exists in available keys
      if (!this.availableKeys.includes(fieldRef)) {
        invalidReferences.push(`Field '${fieldRef}' not found in available keys`);
      }
    }
    
    // Show all validation errors
    if (invalidReferences.length > 0) {
      invalidReferences.forEach(error => this.toastr.error(error));
      return false;
    }
    
    // Try to parse the equation to check for basic syntax errors
    try {
      this.parseEquation(equation);
    } catch (error) {
      this.toastr.error(`Invalid equation syntax: ${error.message}`);
      return false;
    }
    
    // Additional validation for complex expressions
    this.analyzeComplexEquation(equation);
    
    return true;
  }
  
  // Analyze complex equation and provide warnings
  analyzeComplexEquation(equation: string): void {
    // Check for potentially problematic patterns
    if (/[+\-*/]{3,}/.test(equation)) {
      this.toastr.warning('Equation contains multiple consecutive operators which may cause unexpected results');
    }
    
    // Check for unbalanced expressions
    const operators = equation.match(/[+\-*/]/g) || [];
    const operands = equation.match(/[a-zA-Z0-9_]+/g) || [];
    
    if (operators.length > 0 && operands.length === 0) {
      this.toastr.warning('Equation contains operators but no operands (fields or constants)');
    }
    
    // Check for division by zero patterns
    if (/\/\s*0(?!\d)/.test(equation)) {
      this.toastr.warning('Equation may contain division by zero');
    }
    
    // Check for excessive nesting
    let parenDepth = 0;
    let maxParenDepth = 0;
    for (const char of equation) {
      if (char === '(') {
        parenDepth++;
        maxParenDepth = Math.max(maxParenDepth, parenDepth);
      } else if (char === ')') {
        parenDepth--;
      }
    }
    
    if (maxParenDepth > 10) {
      this.toastr.warning('Equation has deep nesting which may affect performance');
    }
    
    // Check for repeated field usage
    const fieldRefs = this.extractFieldReferences(equation);
    const fieldCounts: {[key: string]: number} = {};
    fieldRefs.forEach(field => {
      if (!isNaN(Number(field))) return; // Skip numbers
      fieldCounts[field] = (fieldCounts[field] || 0) + 1;
    });
    
    Object.keys(fieldCounts).forEach(field => {
      if (fieldCounts[field] > 3) {
        this.toastr.warning(`Field '${field}' is used ${fieldCounts[field]} times in the equation`);
      }
    });
  }
  
  // Extract field references from equation
  extractFieldReferences(equation: string): string[] {
    // Remove all operators and parentheses to isolate field names
    const cleanEquation = equation.replace(/[+\-*/()[\]{}^%>=<!&|\s]+/g, ' ');
    // Split by whitespace and filter out empty strings and numbers
    return cleanEquation.split(/\s+/).filter(token => token.length > 0);
  }
  
  // Simple equation parser to check syntax (basic implementation)
  parseEquation(equation: string): void {
    // Remove spaces
    const cleanEquation = equation.replace(/\s/g, '');
    
    // Check for balanced parentheses
    let parenCount = 0;
    for (const char of cleanEquation) {
      if (char === '(') parenCount++;
      if (char === ')') parenCount--;
      if (parenCount < 0) throw new Error('Mismatched parentheses');
    }
    if (parenCount !== 0) throw new Error('Mismatched parentheses');
    
    // Check for balanced square brackets
    let bracketCount = 0;
    for (const char of cleanEquation) {
      if (char === '[') bracketCount++;
      if (char === ']') bracketCount--;
      if (bracketCount < 0) throw new Error('Mismatched square brackets');
    }
    if (bracketCount !== 0) throw new Error('Mismatched square brackets');
    
    // Check for balanced curly braces
    let braceCount = 0;
    for (const char of cleanEquation) {
      if (char === '{') braceCount++;
      if (char === '}') braceCount--;
      if (braceCount < 0) throw new Error('Mismatched curly braces');
    }
    if (braceCount !== 0) throw new Error('Mismatched curly braces');
    
    // Check for invalid sequences
    if (/[+\-*/]{2,}/.test(cleanEquation)) {
      throw new Error('Invalid operator sequence');
    }
    
    // Check that equation doesn't start or end with an operator (except minus for negative numbers)
    if (/^[+*/^%=<>|&]/.test(cleanEquation) || /[+\-*/^%=<>|&]$/.test(cleanEquation)) {
      throw new Error('Equation cannot start or end with an operator');
    }
    
    // Check for empty parentheses
    if (/\(\)/.test(cleanEquation)) {
      throw new Error('Empty parentheses are not allowed');
    }
  }

  // Delete calculated field
  deleteCalculatedField(id: number) {
    this.calculatedFields = this.calculatedFields.filter(field => field.id !== id);
    this.toastr.success('Calculated field deleted');
  }

  onEdit(row) {
    this.rowSelected = row;
    this.editCronExpression = row.cron_job || '';
    // Set the selected SureConnect for edit form
    this.selectedSureConnect = row.sure_connect_id || null;
    // Use setTimeout to ensure the component has time to initialize
    setTimeout(() => {
      this.modalEdit = true;
    }, 0);
  }
  onDelete(row) {
    this.rowSelected = row;
    this.modaldelete = true;
  }
  delete(id) {
    this.modaldelete = false;
    console.log("in delete  " + id);
    this.mainService.delete(id).subscribe(
      (data) => {
        console.log(data);
        this.ngOnInit();
        if (data) { this.toastr.success('Deleted successfully'); }
      });
  }
  onUpdate(id) {
    this.modalEdit = false;

    //console.log("in update");
    console.log("id  " + id);
    console.log(this.rowSelected);
    //console.log("out update");
    this.mainService.update(id, this.rowSelected).subscribe(
      (data) => {
        console.log(data);
        if (data || data.status >= 200 && data.status <= 299) {
          this.toastr.success("Update Successfully");
        }
        setTimeout(() => {
          this.ngOnInit();
        }, 500);



      }, (error) => {
        console.log(error);
        if (error.status >= 200 && error.status <= 299) {
          // this.toastr.success("update Succesfully");
        }
        if (error.status >= 400 && error.status <= 499) {
          this.toastr.error("Not Updated");
        }
        if (error.status >= 500 && error.status <= 599) {
          this.toastr.error("Not Updated");
        }
      });
    setTimeout(() => {
      this.ngOnInit();
    }, 500);
  }

  // New method for updating JSON
  updateJson(id: number) {
    this.mainService.updateJson(id).subscribe(
      (data) => {
        console.log(data);
        if (data || data.status >= 200 && data.status <= 299) {
          this.toastr.success("JSON Updated Successfully");
        }
        setTimeout(() => {
          this.ngOnInit();
        }, 500);
      }, (error) => {
        console.log(error);
        if (error.status >= 200 && error.status <= 299) {
          this.toastr.success("JSON Updated Successfully");
        }
        if (error.status >= 400 && error.status <= 499) {
          this.toastr.error("JSON Not Updated");
        }
        if (error.status >= 500 && error.status <= 599) {
          this.toastr.error("JSON Not Updated");
        }
      });
  }

  // New method to show full URL in a modal
  showFullUrl(url: string) {
    this.selectedUrl = url;
    this.urlModalOpen = true;
  }

  // New method to copy text to clipboard
  copyToClipboard(text: string) {
    const el = document.createElement('textarea');
    el.value = text;
    document.body.appendChild(el);
    el.select();
    document.execCommand('copy');
    document.body.removeChild(el);
    this.toastr.success('Copied to clipboard');
  }

  // Handle cron expression change for add form
  onAddCronExpressionChange(expression: string) {
    this.addCronExpression = expression;
    // Update the form control
    if (this.entryForm && this.entryForm.get('cron_job')) {
      this.entryForm.get('cron_job')?.setValue(expression);
    }
  }

  // Handle cron expression change for edit form
  onEditCronExpressionChange(expression: string) {
    this.editCronExpression = expression;
    // Update the rowSelected
    if (this.rowSelected) {
      this.rowSelected.cron_job = expression;
    }
  }


  onCreate() {
    this.modalAdd = false;


    this.mainService.create(this.entryForm.value).subscribe(
      (data) => {
        console.log(data);
        if (data || data.status >= 200 && data.status <= 299) {
          this.toastr.success("Added Successfully");
        }
        setTimeout(() => {
          this.ngOnInit();
        }, 500);



      }, (error) => {
        console.log(error);
        if (error.status >= 200 && error.status <= 299) {
          // this.toastr.success("Added Succesfully");
        }
        if (error.status >= 400 && error.status <= 499) {
          this.toastr.error("Not Added");
        }
        if (error.status >= 500 && error.status <= 599) {
          this.toastr.error("Not Added");
        }
      });
    setTimeout(() => {
      this.ngOnInit();
    }, 500);
  }
  
  goToAdd(row) {
    this.modalAdd = true;
    this.addCronExpression = '';
    this.selectedSureConnect = null; // Reset SureConnect selection
    this.submitted = false;
    // Reset the form control for cron_job and sure_connect_id
    if (this.entryForm) {
      if (this.entryForm.get('cron_job')) {
        this.entryForm.get('cron_job')?.setValue('');
      }

    }
  }
  submitted = false;
  onSubmit() {
    console.log(this.entryForm.value);
    this.submitted = true;
    if (this.entryForm.invalid) {
      return;
    } this.onCreate();

  }


  isValidurl(url: string): boolean {
    return /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/.test(url);
  }
  goTourlUrl(val) { window.open(val) }


  rsModaljson = false;
  goToReplaceStringjson(row) {
    this.rowSelected = row; this.rsModaljson = true;
  }

  // Generate JSON from calculated fields and update the record
  updateCalculatedFields() {
    if (!this.selectedDataLakeItem || this.calculatedFields.length === 0) {
      this.toastr.error('No calculated fields to update');
      return;
    }
    
    // Convert calculated fields to JSON string
    const calculatedFieldJson = JSON.stringify(this.calculatedFields);
    
    // Call the service method to update the record
    this.mainService.updateCalculatedFields(
      this.selectedDataLakeItem.id, 
      calculatedFieldJson, 
      true // iscalculatedfield = true
    ).subscribe(
      (response) => {
        console.log('Calculated fields updated successfully:', response);
        this.toastr.success('Calculated fields updated successfully');
        
        // Update the local data
        const index = this.product.findIndex(item => item.id === this.selectedDataLakeItem.id);
        if (index !== -1) {
          this.product[index].calculated_field_json = calculatedFieldJson;
          this.product[index].iscalculatedfield = true;
        }
        
        // Close the modal only when called directly from the UI
        if (this.calculatedFieldModalOpen) {
          this.calculatedFieldModalOpen = false;
        }
      },
      (error) => {
        console.error('Error updating calculated fields:', error);
        this.toastr.error('Failed to update calculated fields');
      }
    );
  }

  // Add operator to complex equation
  addOperatorToEquation(operator: string) {
    const equationControl = this.calculatedFieldForm.get('complexEquation');
    if (equationControl) {
      const currentValue = equationControl.value || '';
      equationControl.setValue(currentValue + operator);
    }
  }
  
  // Add field or constant to complex equation
  addFieldToEquation(field: string) {
    const equationControl = this.calculatedFieldForm.get('complexEquation');
    if (equationControl) {
      const currentValue = equationControl.value || '';
      // Add space before and after if needed
      const newValue = currentValue ? `${currentValue} ${field} ` : `${field} `;
      equationControl.setValue(newValue);
      
      // Validate after adding field
      if (this.calculatedFieldForm.get('operation')?.value === 'complex') {
        this.analyzeComplexEquation(equationControl.value);
      }
    }
  }
  
  // Get all defined constants from existing calculated fields
  getDefinedConstants(): string[] {
    const constants: string[] = [];
    this.calculatedFields.forEach(field => {
      // Check for actual constant operations
      if (field.operation === 'constant' && field.fieldName) {
        constants.push(field.fieldName);
      }
    });
    return constants;
  }
  
  // Add a new constant to the equation
  addNewConstantToEquation() {
    // Generate a new constant name
    this.currentConstantName = `constant_${this.constantCounter}`;
    
    // Open the constant value modal
    this.currentConstantValue = '';
    this.constantValueModalOpen = true;
  }
  
  // Save constant value and update equation
  saveConstantValue() {
    if (this.currentConstantValue === '') {
      this.toastr.error('Constant value is required');
      return;
    }
    
    // Validate constant value based on operation type
    const operation = this.calculatedFieldForm.get('operation')?.value;
    if (operation !== 'concat' && operation !== 'complex') {
      const numericValue = Number(this.currentConstantValue);
      if (isNaN(numericValue)) {
        this.toastr.error('Constant values must be numeric for this operation');
        return;
      }
    }
    
    // For non-complex operations, add to field components directly
    if (operation && operation !== 'complex') {
      const fieldComponents = this.getFieldComponents();
      fieldComponents.push(this._fb.group({
        field: [this.currentConstantName],
        constant: [this.currentConstantValue]
      }));
    } else if (operation === 'complex') {
      // For complex equations, add to the equation and create a constant field
      const equationControl = this.calculatedFieldForm.get('complexEquation');
      if (equationControl) {
        const currentValue = equationControl.value || '';
        const newValue = currentValue ? `${currentValue} ${this.currentConstantName} ` : `${this.currentConstantName} `;
        equationControl.setValue(newValue);
      }
      
      // Also create a constant field that can be referenced
      const constantField = {
        id: Date.now(),
        fieldName: this.currentConstantName,
        operation: 'constant',
        fieldComponents: [{
          field: this.currentConstantName,
          constant: this.currentConstantValue,
          isConstant: true
        }]
      };
      
      this.calculatedFields.push(constantField);
    } else {
      // If no operation is selected, just create the constant field
      const constantField = {
        id: Date.now(),
        fieldName: this.currentConstantName,
        operation: 'constant',
        fieldComponents: [{
          field: this.currentConstantName,
          constant: this.currentConstantValue,
          isConstant: true
        }]
      };
      
      this.calculatedFields.push(constantField);
    }
    
    // Increment the counter for next constant
    this.constantCounter++;
    
    // Close modal and show success message
    this.constantValueModalOpen = false;
    this.toastr.success(`Constant ${this.currentConstantName} added with value ${this.currentConstantValue}`);
  }
  
  // Cancel constant value input
  cancelConstantValue() {
    this.constantValueModalOpen = false;
    this.currentConstantName = '';
    this.currentConstantValue = '';
  }
  
  // Test method to verify constant validation
  testConstantFunctionality() {
    // Clear existing calculated fields for testing
    this.calculatedFields = [];
    
    // Add a test constant
    const testConstant = {
      id: Date.now(),
      fieldName: 'constant_1',
      operation: 'constant',
      fieldComponents: [{
        field: 'constant_1',
        constant: '15',
        isConstant: true
      }]
    };
    
    this.calculatedFields.push(testConstant);
    
    // Test validation
    const testEquation = 'pincode + mobno * constant_1';
    const isValid = this.validateComplexEquation(testEquation);
    
    console.log('Test equation:', testEquation);
    console.log('Validation result:', isValid);
    console.log('Defined constants:', this.getDefinedConstants());
  }
  
  // Method to open group by modal
  openGroupByModal(dataLakeItem: any) {
    this.selectedDataLakeItem = dataLakeItem;
    
    // Fetch available keys if not already fetched
    if (this.availableKeys.length === 0) {
      this.fetchAvailableKeys(dataLakeItem);
    }
    
    // Initialize selected group by fields as empty array
    this.selectedGroupByFields = [];
    this.selectedAggregationFields = [];
    this.showGroupByModal = true;
  }
  
  // Method to add a field to group by selection
  addGroupByField(field: string) {
    if (!this.selectedGroupByFields.includes(field)) {
      this.selectedGroupByFields.push(field);
    }
  }
  
  // Method to remove a field from group by selection
  removeGroupByField(field: string) {
    const index = this.selectedGroupByFields.indexOf(field);
    if (index > -1) {
      this.selectedGroupByFields.splice(index, 1);
    }
  }
  
  // Method to add an aggregation field
  addAggregationField() {
    this.selectedAggregationFields.push({ field: '', operation: 'count' });
  }
  
  // Method to remove an aggregation field
  removeAggregationField(index: number) {
    this.selectedAggregationFields.splice(index, 1);
  }
  
  // Method to update aggregation field
  updateAggregationField(index: number, field: string, operation: string) {
    this.selectedAggregationFields[index] = { field, operation };
  }
  
  // Method to apply group by
  applyGroupBy() {
    if (this.selectedGroupByFields.length === 0) {
      this.toastr.error('Please select at least one field for grouping');
      return;
    }
    
    // Validate aggregation fields
    for (const agg of this.selectedAggregationFields) {
      if (!agg.field) {
        this.toastr.error('Please select a field for all aggregation operations');
        return;
      }
    }
    
    // Create group by configuration
    const groupByConfig = {
      id: Date.now(),
      type: 'groupby',
      groupFields: [...this.selectedGroupByFields],
      aggregations: [...this.selectedAggregationFields],
      timestamp: new Date().toISOString()
    };
    
    // Add to calculated fields
    this.calculatedFields.push(groupByConfig);
    this.toastr.success('Group by configuration added successfully');
    
    // Update the calculated fields in the backend
    this.updateCalculatedFieldsAfterGroupBy();
    
    this.showGroupByModal = false;
  }
  
  // New method to update calculated fields after adding group by configuration
  updateCalculatedFieldsAfterGroupBy() {
    if (!this.selectedDataLakeItem || this.calculatedFields.length === 0) {
      return;
    }
    
    // Convert calculated fields to JSON string
    const calculatedFieldJson = JSON.stringify(this.calculatedFields);
    
    // Call the service method to update the record
    this.mainService.updateCalculatedFields(
      this.selectedDataLakeItem.id, 
      calculatedFieldJson, 
      true // iscalculatedfield = true
    ).subscribe(
      (response) => {
        console.log('Calculated fields updated successfully:', response);
        this.toastr.success('Group by configuration saved successfully');
        
        // Update the local data
        const index = this.product.findIndex(item => item.id === this.selectedDataLakeItem.id);
        if (index !== -1) {
          this.product[index].calculated_field_json = calculatedFieldJson;
          this.product[index].iscalculatedfield = true;
        }
      },
      (error) => {
        console.error('Error updating calculated fields:', error);
        this.toastr.error('Failed to save group by configuration');
      }
    );
  }
  
  // Method to remove group by configuration
  removeGroupByConfig(id: number) {
    this.calculatedFields = this.calculatedFields.filter(field => field.id !== id || field.type !== 'groupby');
    this.toastr.success('Group by configuration removed');
  }
  
  // Method to check if a field is selected for group by
  isGroupByFieldSelected(field: string): boolean {
    return this.selectedGroupByFields.includes(field);
  }

  // Helper method to get the count of calculated fields
  getCalculatedFieldsCount(calculatedFieldJson: string): number {
    try {
      const fields = JSON.parse(calculatedFieldJson);
      return Array.isArray(fields) ? fields.length : 0;
    } catch (e) {
      return 0;
    }
  }

  // Helper method to get the count of group by configurations
  getGroupByFieldsCount(groupByJson: string): number {
    try {
      const configs = JSON.parse(groupByJson);
      return Array.isArray(configs) ? configs.length : 0;
    } catch (e) {
      return 0;
    }
  }

  // Helper method to check if the selected data is JSON
  isJsonData(data: any): boolean {
    if (!data) return false;
    
    try {
      const parsed = typeof data === 'string' ? JSON.parse(data) : data;
      return Array.isArray(parsed) && parsed.length > 0;
    } catch (e) {
      return false;
    }
  }

  // Helper method to get JSON headers for grid columns
  getJsonHeaders(data: any): string[] {
    if (!this.isJsonData(data)) return [];
    
    try {
      const parsed = typeof data === 'string' ? JSON.parse(data) : data;
      if (Array.isArray(parsed) && parsed.length > 0) {
        // Get all unique keys from the first few items
        const headers = new Set<string>();
        const sampleItems = parsed.slice(0, 3); // Check first 3 items for headers
        
        sampleItems.forEach(item => {
          if (typeof item === 'object' && item !== null) {
            Object.keys(item).forEach(key => headers.add(key));
          }
        });
        
        return Array.from(headers);
      }
      return [];
    } catch (e) {
      return [];
    }
  }

  // Helper method to get JSON data for grid rows
  getJsonData(data: any): any[] {
    if (!this.isJsonData(data)) return [];
    
    try {
      return typeof data === 'string' ? JSON.parse(data) : data;
    } catch (e) {
      return [];
    }
  }
}
