import { Component, Input, OnInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatTableModule } from '@angular/material/table';
import { MatTooltipModule } from '@angular/material/tooltip';
import { map, tap, filter, Subscription } from 'rxjs';
import { HttpResponse } from '@angular/common/http';

import { DashboardComponentService } from '../../service/dashboard-component.service';
import { IDashboardComponentDetailValue } from '../../dashboard-component-detail-value.model';
import { ResilientEnvironmentService } from 'app/resilient/resilient-environment/service/resilient-environment.service';
import { FormatHelper } from 'app/shared/utils/format-helper';

export interface AccordionItem {
  id: string;
  label: string;
  help?: string;
  values: string[];
  target?: number;
  loading: boolean;
  expanded: boolean;
  children?: AccordionItem[]; // Nested children
}

@Component({
  standalone: true,
  selector: 'app-nested-accordion',
  templateUrl: './nested-accordion.component.html',
  styleUrls: ['./nested-accordion.component.css'],
  imports: [CommonModule, MatExpansionModule, MatTableModule, MatTooltipModule]
})
export class NestedAccordionComponent implements OnInit {
  @Input() data: AccordionItem[] = [];  // Input data (array)
  @Input() labels: string[] = [];  // Input labels (array)
  @Input() level: number = 0;           // Current level for styling
  @Input() periodVersionId: number | null = null; 
  
  loading = true;

  subscriptionWorkOrganization!: Subscription;  // Store the subscription
  selectedOrganizationId?: number;
  displayedColumns: string[] = ['name', 'age', 'address', 'expand'];

  protected dashboardComponentService = inject(DashboardComponentService);
  protected envService = inject(ResilientEnvironmentService);

  ngOnInit(): void {
    // Get the currently selected ORGANIZATION, by ResilientEnvironmentService
    this.subscriptionWorkOrganization = this
      .envService
      .selectedWorkOrganization
      /* .pipe(first())		// READS the Observable only once. Doesn't react to later changes on the subscription */
      .subscribe(org => {
        if(org){
          // Set selected
          this.selectedOrganizationId = org.id;
          
        }
      });
      
    this.loading = false;
  }

  // Simulates loading child data
  loadChildren(item: AccordionItem) {
    if (!item.children && item.target) {
      item.loading = true;  // Show loading

      //Invoke
      this.loadValues(item, item.target);
    }
  }
  
  panelOpened(row: AccordionItem) {
    this.loadChildren(row);
    row.expanded = true;
  }

  panelClosed(row: AccordionItem) {
    row.expanded = false;
  }
  
  private loadValues(item: AccordionItem, dashboardComponentId: number): void {
    if (dashboardComponentId && this.periodVersionId && this.selectedOrganizationId) {
      this.dashboardComponentService
        .loadOrganizationValuesForComponent(this.selectedOrganizationId, dashboardComponentId, this.periodVersionId)
        .pipe(
          map(
            (res: HttpResponse<any>) => {
              const data = res.body ?? {};

              // Check if the data is already a Map or if it's a plain object
              if (data instanceof Map) {
                return data;
              } else {
                // Convert object to Map if it's not. 
                // I had to do it like this, otherwise, it wouldn't be a Map().
                const map = new Map<string, IDashboardComponentDetailValue[]>();
                Object.keys(data).forEach(key => {
                  map.set(key, data[key]);
                });
                
                const reorderedMap = this.moveTopOrgToLast(map);
                
                return reorderedMap;
              }
            }
          )
        )
        .subscribe(
          (_dashboardComponentDetailValues: Map<string, IDashboardComponentDetailValue[]>) => {
              this.buildAccordion(item, _dashboardComponentDetailValues);
          }
        );
    }
  }
  
  private moveTopOrgToLast(map: Map<string, IDashboardComponentDetailValue[]>): Map<string, IDashboardComponentDetailValue[]> {
    if (!map.has("1")) return map; // If key "9" doesn't exist, return map as is

    const entries = Array.from(map.entries()); // Convert Map to array of entries
    const entryTopOrg = entries.find(([key]) => key === "1"); // Find the entry with key "1"
    const filteredEntries = entries.filter(([key]) => key !== "1"); // Remove "9" entry

    if (entryTopOrg) {
      filteredEntries.push(entryTopOrg); // Move it to the end
    }

    return new Map(filteredEntries); // Create a new Map with updated order
  }
  
  private buildAccordion(item: AccordionItem, dashboardComponentDetailValues: Map<string, IDashboardComponentDetailValue[]> ): void {
    // Clear previous table
    //this.labels.length = 0;
    //this.data.length = 0;
  
    const variableMap: Map<string, number[]> = new Map();
    const variableLabelValues: Map<string, string> = new Map();
    const variableTargetValues: Map<string, number|null> = new Map();
    const variableColorValues: Map<string, string> = new Map();
    const variableHelpValues: Map<string, string> = new Map();
    
    // First column header. Variable description column
    //this.labels.push("");
    
    // Rebuild
    dashboardComponentDetailValues.forEach((value, key) => {
      let isFirst = true;
      
      value.forEach(item => {
        //if (isFirst) this.labels.push(item?.organization?.code || 'undefined');  //Add company label. Get it from the first element.
        //isFirst = false;
        
        const variableValues = variableMap.get(item?.dashboardComponentDetail?.variable?.id.toString() || '');
        
        if (variableValues !== undefined) {
          // Append value to array
          variableValues.push(item.value || 0);
        } else {
          // Insert first entry
          variableMap.set(item?.dashboardComponentDetail?.variable?.id.toString() || '', [item.value || 0]);
          variableLabelValues.set(item?.dashboardComponentDetail?.variable?.id.toString() || '', item?.dashboardComponentDetail?.name || 'undefined');
          variableColorValues.set(item?.dashboardComponentDetail?.variable?.id.toString() || '', item?.dashboardComponentDetail?.color || '');
          variableHelpValues.set(item?.dashboardComponentDetail?.variable?.id.toString() || '', item?.dashboardComponentDetail?.help || '');
          variableTargetValues.set(item?.dashboardComponentDetail?.variable?.id.toString() || '', item?.targetDashboardComponent?.id || null);
        }
      });
    });
    
    // Build row array (Label | Value 1 | Value 2 | .. )
    item.children = [];
    variableMap.forEach((value, key) => {
      let newDataRow : AccordionItem = {
        id: key,
        label: variableLabelValues.get(key) || "",
        help: variableHelpValues.get(key) || "",
        values: [],
        target: variableTargetValues.get(key) || undefined,
        loading: false,
        expanded: false,
        children: undefined,
      };
      
      value.forEach(val => {
        let roundedNumber = FormatHelper.formatDecimalValue(val);

        newDataRow.values.push(roundedNumber); 
      });
      
      if (item.children) item.children.push(newDataRow);
    });
    
    item.loading = false;
  }
}
