import { Component, Input, OnInit, OnDestroy, ViewChild, inject } from '@angular/core';
import { trigger, state, style, animate, transition } from '@angular/animations';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatDividerModule } from '@angular/material/divider';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatMenuModule } from '@angular/material/menu';
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatSort, MatSortModule } from '@angular/material/sort';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { BaseChartDirective } from 'ng2-charts';
import { Observable, Subscription } from 'rxjs';

import { MenuItems } from '@components/shared';
import {
    CalculatorInfo,
    CalculatorResult,
    CalculatorState,
    InputParams,
    Jump,
    LineConfig,
    WeightSizeRange,
    TableHeader,
    User,
    WeightSize,
    weightSizes,
} from '@models';
import { CalculatorService, JumpsService, UserService, UtilitiesService } from '@services';

@Component({
    selector: 'app-calculator',
    imports: [
        CommonModule,
        FormsModule,
        RouterModule,
        MatButtonModule,
        MatCardModule,
        MatDividerModule,
        MatFormFieldModule,
        MatInputModule,
        MatIconModule,
        MatMenuModule,
        MatPaginatorModule,
        MatProgressBarModule,
        MatSortModule,
        MatTableModule,
        BaseChartDirective,
    ],
    templateUrl: './calculator.component.html',
    styleUrl: './calculator.component.scss',
    animations: [
        trigger('flyInOut', [
            state('in', style({ transform: 'translateY(0)' })),
            transition('void => *', [style({ transform: 'translateY(-100%)' }), animate(200)]),
            transition('* => void', [style({ transform: 'translateY(100%)' }), animate(200)]),
        ]),
    ],
})
export class CalculatorComponent implements OnInit, OnDestroy {
    private _calculatorService = inject(CalculatorService);
    private _jumpsService = inject(JumpsService);
    private _userService = inject(UserService);
    private _utilitiesService = inject(UtilitiesService);
    menuItems = inject(MenuItems);

    //private _lastjump!: Subscription; // = new Subscription();
    //private _currentUser!: Subscription; // = new Subscription();
    private _subscriptions: Array<Subscription> = [];
    public title = 'Calcul de taille de voile';
    public subtitle = 'DT48 - 08 février 2024';
    public lastjump: Jump = {} as Jump;
    public currentRange: WeightSizeRange = {} as WeightSizeRange;
    public currentUser: User = {} as User;
    public displayedColumns: Array<string> = ['weight'];
    public tableHeader: Array<TableHeader> = [<TableHeader>{ name: 'Poids nu en kg', active: '' }];
    public sizesHeader: Array<TableHeader> = [];
    public sizesValuesFeet: Array<number> = [];
    public sizesMinValuesFeet: Array<number> = [];
    public sizesCharges: Array<number> = [];
    public sizesValuesMeter: Array<number> = [];
    public displayCharts = false;
    public chartConfig: LineConfig = this._utilitiesService.getLineChartConfig();
    public coeffKgLbs: number = this._utilitiesService.getCoeffKgLbs();
    public coeffFtM: number = this._utilitiesService.getCoeffFtM();
    public info: CalculatorInfo = {
        charges: <CalculatorResult>{ current: 0, min: 0, min11: 0 },
        sizesFeet: <CalculatorResult>{ current: 0, min: 0, min11: 0 },
        sizesMeter: <CalculatorResult>{ current: 0, min: 0, min11: 0 },
        state: <CalculatorState>{ color: 'danger' },
    };

    @Input() canopy_size_table!: MatTableDataSource<WeightSize>;
    @Input() inputs: InputParams = (<InputParams>{
        jumps: 0,
        weight: 60,
        gear: 10,
        current: 190,
    }) as InputParams;

    @ViewChild(MatSort) sort!: MatSort;
    @ViewChild(MatPaginator) paginator!: MatPaginator;

    ngOnInit() {
        const currentUser$: Observable<User> = this._userService.currentUser;
        const lastjump$: Observable<Jump> = this._jumpsService.getLastJump();

        weightSizes[0].ranges.forEach((range: WeightSizeRange) => {
            const header: TableHeader = { name: range.label, active: range.active };
            this.tableHeader.push(header);
            this.sizesHeader.push(header);
            this.displayedColumns.push(range.name);
        });
        this.chartConfig.lineChartData.labels = [...this.sizesHeader.map((data: TableHeader): string => data.name)];
        this.chartConfig.lineChartData.datasets = [
            {
                label: 'Tailles min -11%',
                data: this.sizesMinValuesFeet,
                fill: true,
                stepped: true,
                pointStyle: false,
                borderColor: 'rgba(241, 80, 80, 1)',
                backgroundColor: 'rgba(241, 80, 80, 0.3)',
            },
            {
                label: 'Tailles min',
                data: this.sizesValuesFeet,
                fill: true,
                stepped: true,
                pointStyle: false,
                borderColor: 'rgba(32, 182, 252, 1)',
                backgroundColor: 'rgba(32, 182, 252, 0.3)',
            },
        ];
        this._subscriptions.push(
            currentUser$.subscribe((userData: User) => {
                this.currentUser = userData;
                this._subscriptions.push(
                    lastjump$.subscribe((jump) => {
                        this.lastjump = jump;
                        this.inputs.jumps = jump.numero;
                        this.inputs.weight = this.currentUser.poids!;
                        this.inputs.current = jump.taille!;
                        this.canopy_size_table = new MatTableDataSource<WeightSize>(weightSizes);
                        this.refresh();
                    }),
                );
            }),
        );
    }

    ngOnDestroy() {
        this._subscriptions.forEach((sub: Subscription) => {
            sub.unsubscribe();
        });
    }

    public refresh(): void {
        this._refreshActive();
        this._refreshSizes();
    }

    private _refreshActive(): void {
        let weight: number = this.inputs.weight;
        if (this.inputs.weight < 60) {
            weight = 60;
        }
        weightSizes.forEach((element) => {
            element.active = '';
            element.ranges.forEach((range) => {
                range.active = '';
            });
        });
        this.tableHeader.forEach((element) => {
            element.active = '';
        });
        if (weight >= 60 && weight <= 110) {
            weightSizes[weight - 60].active = 'active';
        }
        if (this.inputs.jumps >= 0) {
            const num = this._calculatorService.getRangeNum(this.inputs.jumps);
            this.tableHeader[num].active = 'active';
            weightSizes.forEach((element) => {
                element.ranges[num - 1].active = 'active';
            });
            this.currentRange = weightSizes[0].ranges[num - 1];
        }
    }

    private _refreshSizes(): void {
        let weight: number = this.inputs.weight;
        if (this.inputs.weight < 60) {
            weight = 60;
        }
        if (this.inputs.jumps > 2000) {
            this.info.state.error = '2K+ Jumps';
        }
        this.sizesValuesFeet = this._calculatorService.getCanopySizes(weight);
        this.sizesMinValuesFeet = this._calculatorService.getCanopySizes(weight, true);
        this.sizesValuesMeter = this.sizesValuesFeet.map((value: number, index: number) => {
            this.sizesCharges[index] = this._calculatorService.getCharge(value, this.inputs.weight, this.inputs.gear);
            return this._calculatorService.convertFeet2Meters(value);
        });
        this.info.sizesFeet = this._calculatorService.canopySizeCalc(weight, this.inputs.jumps);
        this.info.sizesFeet.current = this.inputs.current;
        this.info.sizesMeter = {
            current: this._calculatorService.convertFeet2Meters(this.inputs.current),
            min: this._calculatorService.convertFeet2Meters(this.info.sizesFeet.min),
            min11: this._calculatorService.convertFeet2Meters(this.info.sizesFeet.min11),
        };
        this.info.charges = {
            current: this._calculatorService.getCharge(this.inputs.current, this.inputs.weight, this.inputs.gear),
            min: this._calculatorService.getCharge(this.info.sizesFeet.min, this.inputs.weight, this.inputs.gear),
            min11: this._calculatorService.getCharge(this.info.sizesFeet.min11, this.inputs.weight, this.inputs.gear),
        };
        this.info.state.color = this._calculatorService.getStateColor(this.info.sizesFeet);

        this.chartConfig.lineChartData.datasets[0].data = this.sizesMinValuesFeet;
        this.chartConfig.lineChartData.datasets[1].data = this.sizesValuesFeet;
        this.displayCharts = true;
    }

    public setCurrentWeight(weight: number) {
        this.inputs.weight = weight;
        this.refresh();
    }
}
