import { Component, ElementRef, HostListener, Input, SimpleChanges, ViewChild } from '@angular/core';
import { NbpBaseComponent } from '@isp/xdce-widget';
import * as d3 from 'd3';

export interface NbpFidBarChartConfig {
    valueKey: string;
    labelKey: string;
    colorKey?: string;
    colors?: string[];
    format?: (value: number) => string;
    lineHeight?: number;
    chartFontSize?: number;
    symbol?: string;
    ticks?: number;
}

function formatAsIs(value: number): string {
    const numStr = '' + value;
    const length = (numStr.split('.')[1] || '').length || 0;

    return new Intl.NumberFormat('it-IT', {
        minimumFractionDigits: 0,
        maximumFractionDigits: length
    }).format(value);
};

const DEFAULT_CONFIG: NbpFidBarChartConfig = {
    valueKey: 'value',
    labelKey: 'label',
    colors: ['#1F4E79', '#D3D3D3', '#6280a4', '#A9A9A9', '#3CB371', '#FFD700', '#FF6347', '#FF0000'],
    lineHeight: 40,
    chartFontSize: 14,
    symbol: '',
    ticks: 10,
    format: formatAsIs
}

let counter = 0;

@Component({
    selector: 'nbp-fid-bar-chart',
    templateUrl: './nbp-fid-bar-chart.component.html',
    styleUrls: ['./nbp-fid-bar-chart.component.scss']
})
export class NbpFidBarChartComponent extends NbpBaseComponent {
    constructor() {
        super();
    }

    @ViewChild('chart') chart: ElementRef;

    colors: string[] = [
        '#1F4E79',
        '#D3D3D3',
        '#6280a4',
        '#A9A9A9',
        '#3CB371',
        '#FFD700',
        '#FF6347',
        '#FF0000'
    ];

    @Input() data: any[] = [
        { description: "Monetario", perce: 9.7654, color: "#A6CE39" },
        { description: "Obbligazionario", perce: 44.0842, color: "#2C6693" },
        { description: "Azionario", perce: 39.6174, color: "#D94235" },
        { description: "Monetario Valute Estere", perce: 1.5651, color: "#CCCCCC" },
        { description: "Alternative", perce: 3.54, color: "#a3a3a3" },
        { description: "pippo", perce: 1000.54, color: "#987654" },
        { description: "pluto", perce: 3.54, color: "#234567" },
        { description: "paperino", perce: 3333.54, color: "#3741ab" },
        { description: "ciccio", perce: 525.54, color: "#38892a" },
        { description: "lupusinfabula", perce: 3.54, color: "#ae45eb" },
        { description: "aaaa", perce: 11.54, color: "#8399ae" },
        { description: "eeee", perce: 15.54, color: "#BBBBBB" },
        { description: "Altro", perce: 9.45, color: "#AAAAAA" }
    ];

    @Input() config: NbpFidBarChartConfig = {
        labelKey: 'description',
        valueKey: 'perce',
        colorKey: 'color'
    }

    ngOnInit(): void {
        this.init();
        this.setColors();
    }

    private init(): void {
        this.config = {
            ...DEFAULT_CONFIG,
            ...this.config
        };

        if (this.config.symbol) {
            this.data = this.data.map((d: any) => ({
                ...d,
                [this.config.labelKey]: `${d[this.config.labelKey]} (${this.config.symbol})`
            }));
        }
    }

    private d3colors: any;

    private setColors(): void {
        if (this.config.colorKey) {
            this.colors = this.data.map((d: any, i: number): string => d[this.config.colorKey] ? d[this.config.colorKey] : this.config.colors[i]);
        } else if (this.config.colors) {
            this.colors = this.config.colors;
        }

        this.d3colors = d3
            .scaleOrdinal()
            .domain(this.data.map((d: any) => d[this.config.labelKey].toString()))
            .range(this.colors);
    }

    private totalWidth: number = null;
    private totalHeight: number = null;
    private maxLabelWidth: number = null;
    private maxValueWidth: number = null;

    private margin = { top: 20, right: null, bottom: 20, left: null };

    ngAfterViewInit(): void {
        this.calcWidth();
        this.createChart();
    }

    private calcWidth(): void {
        if (this.chart && this.chart.nativeElement && this.data && this.data.length > 0) {
            // Crea un elemento SVG temporaneo
            const tempSvg = d3.select('body').append('svg')
                .style('visibility', 'hidden')
                .style('position', 'fixed')
                .style('z-index', '-1');

            // Calcola la larghezza massima delle etichette
            const maxLabelWidth = d3.max(this.data.map((d: any) => {
                const label = this.config.symbol ? `${d[this.config.labelKey]} (${this.config.symbol})` : d[this.config.labelKey].toString();
                const text = tempSvg.append('text')
                    .text(label)
                    .style('font-size', `${this.config.chartFontSize}px`) // Assicurati di usare la stessa dimensione del font

                const bbox = text.node().getBBox();
                text.remove(); // Rimuovi l'elemento temporaneo
                return bbox.width;
            })) || 0;

            const maxValueWidth = d3.max(this.data.map((d: any) => {
                const text = tempSvg.append('text')
                    .text(this.config.format(d[this.config.valueKey]))
                    .style('font-size', `${this.config.chartFontSize}px`) // Assicurati di usare la stessa dimensione del font

                const bbox = text.node().getBBox();
                text.remove(); // Rimuovi l'elemento temporaneo
                return bbox.width;
            })) || 0;

            tempSvg.remove(); // Rimuovi l'elemento SVG temporaneo

            this.maxLabelWidth = maxLabelWidth;
            this.maxValueWidth = maxValueWidth;
            this.margin.right = this.maxValueWidth + 10;
            this.margin.left = this.maxLabelWidth + 10;
            this.totalWidth = this.chart.nativeElement.offsetWidth - this.margin.left - this.margin.right;
            this.totalHeight = this.config.lineHeight * this.data.length - this.margin.top - this.margin.bottom;
        }
    }

    @HostListener('window:resize', ['$event'])
    onResize() {
        this.calcWidth();
        this.updateBars();
    }

    ngOnChanges(changes: SimpleChanges): void {
        if (changes['data'] || changes['config']) {
            this.ngOnInit();
            this.updateBars();
        }
    }

    private createChart(): void {
        if (!this.data || !this.data.length) return;

        const margin = this.margin;
        const width = this.totalWidth;
        const height = this.totalHeight;

        const svg = d3.select(this.chart.nativeElement)
            .append('svg')
            .attr('width', width + margin.left + margin.right)
            .attr('height', height + margin.top + margin.bottom)
            .append('g')
            .attr('transform', `translate(${margin.left}, ${margin.top})`);

        const xMin = d3.min([{ [this.config.valueKey]: 0 }, ...this.data], (d: any) => d[this.config.valueKey]) || 0;
        const xMax = d3.max(this.data, (d: any) => d[this.config.valueKey]) || 0;
        const xScale = d3.scaleLinear()
            .domain([xMin - (xMin < 0 ? this.maxValueWidth : 10), xMax * 1.1])
            .range([0, width]);

        const yScale = d3.scaleBand()
            .domain(this.data.map((d: any) => d[this.config.labelKey]))
            .range([0, height])
            .padding(0.3);

        const xAxis = d3.axisBottom(xScale).ticks(this.config.ticks);
        const yAxis = d3.axisLeft(yScale);

        svg.append('g')
            .call(xAxis)
            .attr('transform', `translate(0, ${height})`)
            .selectAll('text')
            .style('font-size', this.config.chartFontSize);

        svg.append('g')
            .call(yAxis)
            .selectAll('text')
            .style('font-size', this.config.chartFontSize);

        // Aggiunta linea dell'asse 0 se ci sono valori negativi
        if (xMin < 0) {
            svg.append('line')
                .attr('x1', xScale(0))
                .attr('x2', xScale(0))
                .attr('y1', 0)
                .attr('y2', height)
                .attr('stroke', 'black')
                .attr('stroke-width', 1);
        }

        svg.selectAll('.bar')
            .data(this.data)
            .enter()
            .append('rect')
            .attr('class', 'bar')
            .attr('x', (d: any) => xScale(Math.min(0, d[this.config.valueKey])))
            .attr('y', (d: any) => yScale(d[this.config.labelKey]) || 0)
            .attr('width', (d: any) => Math.abs(xScale(d[this.config.valueKey]) - xScale(0)))
            .attr('height', yScale.bandwidth())
            .attr('fill', (d: any) => this.d3colors(d[this.config.labelKey]));

        svg.selectAll('.label')
            .data(this.data)
            .enter()
            .append('text')
            .attr('x', (d: any) => xScale(d[this.config.valueKey]) + (d[this.config.valueKey] < 0 ? -5 : 5))
            .attr('y', (d: any) => (yScale(d[this.config.labelKey]) || 0) + yScale.bandwidth() / 2)
            .attr('dy', '0.35em')
            .attr('text-anchor', (d: any) => (d[this.config.valueKey] < 0 ? 'end' : 'start'))
            .text((d: any) => this.config.format(d[this.config.valueKey]));
    }

    private updateBars() {
        d3.select(this.chart.nativeElement).selectAll("*").remove();
        this.createChart();
    }
}