import {Component, EventEmitter, Inject, Input, OnInit, Output} from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ToastrService } from 'ngx-toastr';
import {MAT_DIALOG_DATA} from "@angular/material/dialog";
import {ActivatedRoute, Router} from "@angular/router";
import { PARTITION_TYPES } from '../../../../../shared/constants/partition-types';
import { FILESYSTEM_TYPES } from '../../../../../shared/constants/filesystem-types';
import {toUnredirectedSourceFile} from "@angular/compiler-cli/src/ngtsc/util/src/typescript";
import { ConfigService } from '@services/config.service';

interface Partition {
  uuid?: string;
  partitionNumber: number;
  size: number;
  partitionCode: string;
  filesystem: string;
  sizeBytes: number;
  memoryUsage: number;
  format: boolean;
  color: string;
  percentage: number;
  removed: boolean;
}

@Component({
  selector: 'app-partition-assistant',
  templateUrl: './partition-assistant.component.html',
  styleUrls: ['./partition-assistant.component.css']
})
export class PartitionAssistantComponent {
  baseUrl: string;
  private apiUrl: string;
  @Output() dataChange = new EventEmitter<any>();
  partitionTypes = PARTITION_TYPES;
  filesystemTypes = FILESYSTEM_TYPES;
  errorMessage = '';
  originalPartitions: any[] = [];
  clientId: string | null = null;
  newPartitions: any[] = [];
  selectedDiskNumber: number | null = null;
  updateRequests: any[] = [];
  data: any = {};
  disks: { diskNumber: number; totalDiskSize: number; partitions: Partition[]; chartData: any[]; used: number; percentage: number }[] = [];
  clientData: any = [];
  loading: boolean = false;

  view: [number, number] = [400, 300];
  showLegend = true;
  showLabels = true;

  constructor(
    private http: HttpClient,
    private toastService: ToastrService,
    private route: ActivatedRoute,
    private router: Router,
    private configService: ConfigService,
  ) {
    this.baseUrl = this.configService.apiUrl;
    this.apiUrl = this.baseUrl + '/partitions';
    const navigation = this.router.getCurrentNavigation();
    this.clientData = navigation?.extras?.state?.['clientData'];
    this.clientId = this.clientData[0]['@id'];
    this.loadPartitions();

  }

  get selectedDisk():any {
    return this.disks.find(disk => disk.diskNumber === this.selectedDiskNumber) || null;
  }

  loadPartitions() {
    const url = `${this.baseUrl}${this.clientId}`;
    this.http.get(url).subscribe(
      (response) => {
        this.data = response;
        this.initializeDisks();
      },
      (error) => {
        console.error('Error al cargar los datos del cliente:', error);
      }
    );
  }

  initializeDisks() {
    const partitionsFromData = this.data.partitions;
    this.originalPartitions = JSON.parse(JSON.stringify(partitionsFromData));

    const disksMap = new Map<number, { totalDiskSize: number; partitions: Partition[] }>();

    partitionsFromData.forEach((partition: any) => {
      if (!disksMap.has(partition.diskNumber)) {
        disksMap.set(partition.diskNumber, { totalDiskSize: 0, partitions: [] });
      }

      const disk = disksMap.get(partition.diskNumber);
      if (partition.partitionNumber === 0) {
        disk!.totalDiskSize = this.convertBytesToGB(partition.size);
      } else {
        disk!.partitions.push({
          uuid: partition.uuid,
          partitionNumber: partition.partitionNumber,
          size: this.convertBytesToGB(partition.size),
          memoryUsage: partition.memoryUsage,
          partitionCode: partition.partitionCode,
          filesystem: partition.filesystem,
          sizeBytes: partition.size,
          format: false,
          color: '#1f1b91',
          percentage: 0,
          removed: false
        });
      }
    });

    disksMap.forEach((disk, diskNumber) => {
      this.updatePartitionPercentages(disk.partitions, disk.totalDiskSize);

      const used = this.calculateUsedSpace(disk.partitions);
      const percentage = (used / disk.totalDiskSize) * 100;
      const chartData = this.generateChartData(disk.partitions);

      this.disks.push({
        diskNumber: diskNumber,
        totalDiskSize: disk.totalDiskSize,
        partitions: disk.partitions,
        chartData: chartData,
        used: used,
        percentage: percentage
      });
    });
    this.disks.forEach((disk) => {
      this.updatePartitionPercentages(disk.partitions, disk.totalDiskSize);
    });
  }

  convertBytesToGB(bytes: number): number {
    return bytes
  }

   activePartitions(diskNumber: number) {
      const disk = this.disks.find((d) => d.diskNumber === diskNumber);
      if (disk) {
        return disk.partitions.filter((partition) => !partition.removed);
      }

      return null;
  }

  updatePartitionPercentages(partitions: Partition[], totalDiskSize: number) {
    let totalUsedPercentage = 0;

    partitions.forEach((partition) => {
      partition.percentage = Number(((partition.size / totalDiskSize) * 100).toFixed(2))
      totalUsedPercentage += partition.percentage;
    });

    const unusedPercentage = 100 - totalUsedPercentage;

    const chartData = partitions
      .filter((partition) => !partition.removed)
      .map((partition) => ({
        name: `Partición ${partition.partitionNumber}`,
        value: partition.percentage,
        color: partition.color,
      }));

    if (unusedPercentage > 0) {
      chartData.push({
        name: 'Espacio sin usar',
        value: unusedPercentage,
        color: '#ffffff'
      });
    }

    const disk = this.disks.find(d => d.partitions === partitions);
    if (disk) {
      disk.chartData = chartData;
    }
  }

  addPartition(diskNumber: number) {
    const disk = this.disks.find((d) => d.diskNumber === diskNumber);

    if (disk) {
      const remainingGB = this.getRemainingGB(disk.partitions, disk.totalDiskSize);
      if (remainingGB > 0) {
        const removedPartitions = disk.partitions.filter((p) => !p.removed);
        const maxPartitionNumber =
          removedPartitions.length > 0 ? Math.max(...removedPartitions.map((p) => p.partitionNumber)) : 0;
        const newPartitionNumber = maxPartitionNumber + 1;


        disk.partitions.push({
          partitionNumber: newPartitionNumber,
          size: 0,
          partitionCode: 'LINUX',
          filesystem: 'EXT4',
          memoryUsage: 0,
          sizeBytes: 0,
          format: false,
          color: '#' + Math.floor(Math.random() * 16777215).toString(16),
          percentage: 0,
          removed: false
        });
        this.updatePartitionPercentages(disk.partitions, disk.totalDiskSize);
        this.updateDiskChart(disk);
      } else {
        this.errorMessage = 'No hay suficiente espacio libre en el disco para crear una nueva partición.';
      }
    }
  }

  updatePartitionSize(diskNumber: number, index: number, size: number) {
    const disk = this.disks.find((d) => d.diskNumber === diskNumber);
    if (disk) {
      const partition = disk.partitions[index];
      const remainingGB = this.getRemainingGB(disk.partitions, disk.totalDiskSize) + partition.size;
      if (partition) {
        partition.percentage = Number(((size / disk.totalDiskSize) * 100).toFixed(2));
      }
      if (size > remainingGB) {
        this.errorMessage = `El tamaño de la partición no puede superar el espacio libre (${remainingGB.toFixed(2)} GB).`;
      } else {
        this.errorMessage = '';
        partition.size = size;
        partition.sizeBytes = size;

        partition.percentage = (size / disk.totalDiskSize) * 100;
        this.updatePartitionPercentages(disk.partitions, disk.totalDiskSize);
        this.updateDiskChart(disk);
      }
    }
  }

  getRemainingGB(partitions: Partition[], totalDiskSize: number): number {
    const totalUsedGB = partitions.reduce((acc, partition) => acc + partition.size, 0);
    return Math.max(0, totalDiskSize - totalUsedGB);
  }

  getModifiedOrNewPartitions() {
    const modifiedPartitions: any[] = [];

    this.disks.forEach((disk) => {
      disk.partitions.forEach((partition) => {
        const originalPartition = this.originalPartitions.find(
          (p) => p.diskNumber === disk.diskNumber && p.partitionNumber === partition.partitionNumber
        );
        modifiedPartitions.push({
          partition,
          diskNumber: disk.diskNumber,
          partitionNumber: partition.partitionNumber,
        });
      });
    });

    return modifiedPartitions;
  }

  save() {
    if (!this.selectedDisk) {
      this.errorMessage = 'Por favor selecciona un disco antes de guardar.';
      return;
    }

    this.loading = true;

    const totalPartitionSize = this.selectedDisk.partitions.reduce((sum: any, partition: { size: any; }) => sum + partition.size, 0);

    if (totalPartitionSize > this.selectedDisk.totalDiskSize) {
      this.errorMessage = 'El tamaño total de las particiones en el disco seleccionado excede el tamaño total del disco.';
      this.loading = false;
      return;
    }

    const modifiedPartitions = this.selectedDisk.partitions.filter((partition: { removed: any; format: any; }) => !partition.removed || partition.format);

    if (modifiedPartitions.length === 0) {
      this.loading = false;
      this.errorMessage = 'No hay cambios para guardar en el disco seleccionado.';
      return;
    }

    const newPartitions = modifiedPartitions.map((partition: { partitionNumber: any; memoryUsage: any; size: any; partitionCode: any; filesystem: any; uuid: any; removed: any; format: any; }) => ({
      diskNumber: this.selectedDisk.diskNumber,
      partitionNumber: partition.partitionNumber,
      memoryUsage: partition.memoryUsage,
      size: partition.size,
      partitionCode: partition.partitionCode,
      filesystem: partition.filesystem,
      uuid: partition.uuid,
      removed: partition.removed || false,
      format: partition.format || false,
    }));

    if (newPartitions.length > 0) {
      const bulkPayload = {
        partitions: newPartitions,
        clients: this.clientData.map((client: any) => client['@id']),
      };

      this.http.post(this.apiUrl, bulkPayload).subscribe(
        (response) => {
          this.toastService.success('Particiones creadas exitosamente para el disco seleccionado.');
          this.loading = false;
          this.router.navigate(['/commands-logs']);
        },
        (error) => {
          console.error('Error al crear las particiones:', error);
          this.loading = false;
          this.toastService.error('Error al crear las particiones.');
        }
      );
    }
  }


  removePartition(diskNumber: number, partition: Partition) {
    const disk = this.disks.find((d) => d.diskNumber === diskNumber);
    if (disk) {
      const partitionToRemove = disk.partitions.find((p) => p === partition);
      if (partitionToRemove) {
        partitionToRemove.removed = true;
      }
      this.updateDiskChart(disk);
      this.updatePartitionPercentages(disk.partitions, disk.totalDiskSize);
    }
  }

  updatePartitionSizeFromPercentage(diskNumber: number, partitionIndex: number, percentage: number): void {
    const disk = this.disks.find(d => d.diskNumber === diskNumber);
    if (disk) {
      const partition = disk.partitions[partitionIndex];
      if (partition) {
        partition.size = (disk.totalDiskSize * percentage) / 100;
      }
      this.updateDiskChart(disk);
      this.updatePartitionPercentages(disk.partitions, disk.totalDiskSize);
    }
  }

  calculateUsedSpace(partitions: Partition[]): number {
    return partitions.reduce((acc, partition) => acc + partition.size, 0);
  }

  generateChartData(partitions: Partition[]): any[] {
    return partitions.map((partition) => ({
      name: `Partición ${partition.partitionNumber}`,
      value: partition.percentage,
      color: partition.color
    }));
  }

  updateDiskChart(disk: any) {
    disk.chartData = this.generateChartData(disk.partitions);
    disk.used = this.calculateUsedSpace(disk.partitions);
    disk.percentage = (disk.used / disk.totalDiskSize) * 100;
  }
}
