import { Component, OnInit, ElementRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';
import { Chart, registerables } from 'chart.js';
import { SensorService } from '../../../../cores/services/sensor.service';
import { ApiResponse, ParameterSensor } from '../../../../cores/interface/sensor-data'; 
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';

Chart.register(...registerables); 

const parameterColors: { [key: string]: string } = {
  vicitemperature: '#8F5A62',
  vicihumidity: '#16423C',
  viciluminosity: '#DF9B55',
  soiltemperature: '#FF6347',  
  soilhumidity: '#0389b5',     
  soilconductivity: '#A52A2A',  
  soilph: '#228B22', 
  soilnitrogen: '#fece48',
  soilphosphorus: '#B80F0A',
  soilpotassium: '#4c1f74',
};

@Component({
  selector: 'app-graph',
  standalone: true,
  imports: [CommonModule, FormsModule],
  templateUrl: './graph.component.html',
  styleUrls: ['./graph.component.scss']
})
export class GraphComponent implements OnInit, AfterViewInit, OnDestroy {
  @ViewChild('myChartDHT', { static: false }) dhtChartElement!: ElementRef<HTMLCanvasElement>;
  @ViewChild('myChartNPK1', { static: false }) npk1ChartElement!: ElementRef<HTMLCanvasElement>;
  @ViewChild('myChartNPK2', { static: false }) npk2ChartElement!: ElementRef<HTMLCanvasElement>;

  isLoadingDHT: boolean = true;
  isLoadingNPK1: boolean = true;
  isLoadingNPK2: boolean = true;

  isNoDataDHT: boolean = false;
  isNoDataNPK1: boolean = false;
  isNoDataNPK2: boolean = false;

  allNoData: boolean = false;

  sensorParameters: { [key: string]: string[] } = {
    dht: ['vicitemperature', 'vicihumidity', 'viciluminosity'],
    npk1: ['soiltemperature', 'soilhumidity', 'soilconductivity', 'soilph', 'soilnitrogen', 'soilphosphorus', 'soilpotassium'],
    npk2: ['soiltemperature', 'soilhumidity', 'soilconductivity', 'soilph', 'soilnitrogen', 'soilphosphorus', 'soilpotassium'],
  };

  parameterDisplayNames: { [key: string]: string } = {
    vicitemperature: 'Temperature (°C)',
    vicihumidity: 'Humidity (%)',
    viciluminosity: 'Luminosity (lux)',
    soiltemperature: 'Soil Temperature (°C)',
    soilhumidity: 'Soil Humidity (%)',
    soilconductivity: 'Conductivity (μS/cm)',
    soilph: 'pH',
    soilnitrogen: 'Nitrogen (mg/l)',
    soilphosphorus: 'Phosphorus (mg/l)',
    soilpotassium: 'Kalium (mg/l)',
  };

  charts: { [key: string]: Chart | undefined } = {
    dht: undefined,
    npk1: undefined,
    npk2: undefined,
  };

  selectedNPK1: string = 'npk';
  selectedNPK2: string = 'npk';

  private resizeListener!: () => void; 

  constructor(private sensorService: SensorService) {}

  ngOnInit(): void {
    this.resizeListener = this.onResize.bind(this);
    window.addEventListener('resize', this.resizeListener);
    this.updateCharts();
  }

  ngAfterViewInit(): void {
    this.onResize();
  }

  ngOnDestroy(): void {
    window.removeEventListener('resize', this.resizeListener); 
  }

  onResize(): void {
    Object.values(this.charts).forEach(chart => {
      if (chart) {
        chart.destroy();
      }
    });
    this.updateCharts();
  }

  updateCharts(): void {
    this.isLoadingDHT = this.isLoadingNPK1 = this.isLoadingNPK2 = true; 
  
    const today = new Date();
    const year = today.getFullYear();
    const month = String(today.getMonth() + 1).padStart(2, '0'); 
    const day = String(today.getDate()).padStart(2, '0');
  

    const startEnd = `${year}-${month}-${day}`; 
    const timeRange = 'HOURLY';

    Object.keys(this.charts).forEach(key => {
      if (this.charts[key]) {
        this.charts[key]?.destroy();
        this.charts[key] = undefined;
      }
    });
  
    // Fetch data for DHT
    this.sensorService.getSensorData('dht', '', startEnd, timeRange).subscribe({
      next: (response) => {
          this.isLoadingDHT = false;
          if (response.statusCode === 200 && response.data.dht?.length > 0) {
              this.createChart(this.dhtChartElement.nativeElement, response, 'dht', 'npk');
              this.isNoDataDHT = false;
          } else {
              this.isNoDataDHT = true;
          }
      },
      error: () => {
          this.isLoadingDHT = false;
          this.isNoDataDHT = true;
      }
  });

  
    // Fetch data for NPK1
    this.sensorService.getSensorData('npk1', '', startEnd, timeRange).subscribe({
      next: (response) => {
        this.isLoadingNPK1 = false;
        if (response.statusCode === 200 && response.data.npk1?.length > 0) {
          this.createChart(this.npk1ChartElement.nativeElement, response, 'npk1', this.selectedNPK1);
          this.isNoDataNPK1 = false;
        } else {
          this.isNoDataNPK1 = true;  
        }
      },
      error: () => {
        this.isLoadingNPK1 = false;
        this.isNoDataNPK1 = true;  
      }
    });

    // Fetch data for NPK2
    this.sensorService.getSensorData('npk2', '', startEnd, timeRange).subscribe({
      next: (response) => {
        this.isLoadingNPK2 = false;
        if (response.statusCode === 200 && response.data.npk2?.length > 0) {
          this.createChart(this.npk2ChartElement.nativeElement, response, 'npk2', this.selectedNPK2);
          this.isNoDataNPK2 = false;
        } else {
          this.isNoDataNPK2 = true;  
        }
      },
      error: () => {
        this.isLoadingNPK2 = false;
        this.isNoDataNPK2 = true;  
      }
    });
  }


  
  createChart(canvas: HTMLCanvasElement, response: ApiResponse, sensor: string, selectedOption: string): void {
    const ctx = canvas.getContext('2d');
    const parameters = this.sensorParameters[sensor];
  
    if (!ctx) {
      console.error('Failed to get canvas context for sensor:', sensor);
      return;
    }
  
    let datasets: any[] = [];
  
    if (sensor === 'dht') {
      datasets = ['vicitemperature', 'viciluminosity', 'vicihumidity'].map(parameter => {
        const { data, labels } = this.getDataFromResponse(response, sensor, parameter);
        
        if (data.length === 0) {
          console.warn(`No data found for parameter: ${parameter}`);
          return null;
        }
  
        const displayName = this.parameterDisplayNames[parameter] || parameter;
        const borderColor = parameterColors[parameter] || '#000000';
        const backgroundColor = `${borderColor}4D`;
  
        return {
          label: displayName,
          data,
          borderColor,
          borderWidth: 1.5,
          fill: true,
          backgroundColor,
          tension: 0.5,
          pointRadius: 0,
          pointHoverRadius: 0,
        };
      }).filter(dataset => dataset !== null);
    } else {
      datasets = parameters
        .filter(parameter => {
          if (selectedOption === 'npk') {
            return ['soilphosphorus', 'soilnitrogen', 'soilpotassium'].includes(parameter);
          } else if (selectedOption === 'others') {
            return !['soilphosphorus', 'soilnitrogen', 'soilpotassium'].includes(parameter);
          }
          return true;
        })
        .map(parameter => {
          const { data, labels } = this.getDataFromResponse(response, sensor, parameter);
          
          if (data.length === 0) {
            console.warn(`No data found for parameter: ${parameter}`);
            return null;
          }
  
          const displayName = this.parameterDisplayNames[parameter] || parameter;
          const borderColor = parameterColors[parameter] || '#000000';
          const backgroundColor = `${borderColor}4D`;
  
          return {
            label: displayName,
            data,
            borderColor,
            borderWidth: 1.5,
            fill: true,
            backgroundColor,
            tension: 0.5,
            pointRadius: 0,
            pointHoverRadius: 0,
          };
        })
        .filter(dataset => dataset !== null);
    }
  
    if (datasets.length === 0) {
      console.warn('No valid datasets to render for sensor:', sensor);
      return;
    }
  
    if (this.charts[sensor]) {
      this.charts[sensor]?.destroy();
    }
  
    this.charts[sensor] = new Chart(ctx, {
      type: 'line',
      data: {
        labels: this.getLabels(response, sensor),
        datasets,
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        aspectRatio: 2,
        plugins: {
          tooltip: {
            enabled: true,
            mode: 'nearest',
            intersect: false,
            callbacks: {
              label: (tooltipItem) => {
                const paramLabel = tooltipItem.dataset.label;
                const value = tooltipItem.formattedValue;
                return `${paramLabel}: ${value}`;
              }
            }
          },
          legend: { display: true }
        },
        scales: {
          x: { grid: { display: false }, beginAtZero: true },
          y: { grid: { display: false }, beginAtZero: true }
        }
      }
    });
  }
  
  getDataFromResponse(response: ApiResponse, sensor: string, parameter: string): { data: number[], labels: string[] } {
    const sensorData = response.data[sensor as keyof typeof response.data];

    const data: number[] = [];
    const labels: string[] = [];

    if (sensorData) {
      sensorData.forEach(item => {
        data.push(item[parameter as keyof ParameterSensor] ?? 0);
        labels.push(`${item.hour}.00`);
      });
    } else {
      console.error('No data found for sensor:', sensor);
    }

    return { data, labels };
  }

  getLabels(response: ApiResponse, sensor: string): string[] {
    const sensorData = response.data[sensor as keyof typeof response.data];
    return sensorData ? sensorData.map(item => `${item.hour}.00`) : [];
  }
}
