import {AfterViewInit, Component, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {ApexOptions} from 'ng-apexcharts';
import {MatTableDataSource} from '@angular/material/table';
import {MatSort} from '@angular/material/sort';
import {Subject} from 'rxjs';
import {DetailService} from './detail.service';
import {takeUntil} from 'rxjs/operators';
import {DetailSettingsComponent} from 'app/layout/common/detail-settings/detail-settings.component';
import {MatDialog} from '@angular/material/dialog';
import humanizeDuration from 'humanize-duration';
import {TreoConfigService} from '@treo/services/config';
import {AppConfig} from 'app/core/config/app.config';
import {animate, state, style, transition, trigger} from '@angular/animations';
import {formatDate} from '@angular/common';
import { LOCALE_ID, Inject } from '@angular/core';

// from Constants.go - these must match
const AttributeStatusPassed = 0
const AttributeStatusFailedSmart = 1
const AttributeStatusWarningScrutiny = 2
const AttributeStatusFailedScrutiny = 4


@Component({
  selector: 'detail',
  templateUrl: './detail.component.html',
  styleUrls: ['./detail.component.scss'],
    animations: [
        trigger('detailExpand', [
            state('collapsed', style({height: '0px', minHeight: '0'})),
            state('expanded', style({height: '*'})),
            transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
        ]),
    ],
})

export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {

    /**
     * Constructor
     *
     * @param {DetailService} _detailService
     */
    constructor(
        private _detailService: DetailService,
        public dialog: MatDialog,
        private _configService: TreoConfigService,
        @Inject(LOCALE_ID) public locale: string

    )
    {
        // Set the private defaults
        this._unsubscribeAll = new Subject();

        // Set the defaults
        this.smartAttributeDataSource = new MatTableDataSource();
        // this.recentTransactionsTableColumns = ['status', 'id', 'name', 'value', 'worst', 'thresh'];
        this.smartAttributeTableColumns = ['status', 'id', 'name', 'value', 'worst', 'thresh','ideal', 'failure', 'history'];

        this.systemPrefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;

    }

    config: AppConfig;

    onlyCritical = true;
    // data: any;
    expandedAttribute: any | null;

    metadata: any;
    device: any;
    smart_results: any[];

    commonSparklineOptions: Partial<ApexOptions>;
    smartAttributeDataSource: MatTableDataSource<any>;
    smartAttributeTableColumns: string[];

    @ViewChild('smartAttributeTable', {read: MatSort})
    smartAttributeTableMatSort: MatSort;

    // Private
    private _unsubscribeAll: Subject<any>;
    private systemPrefersDark: boolean;

    readonly humanizeDuration = humanizeDuration;

    // -----------------------------------------------------------------------------------------------------
    // @ Lifecycle hooks
    // -----------------------------------------------------------------------------------------------------

    /**
     * On init
     */
    ngOnInit(): void
    {
        // Subscribe to config changes
        this._configService.config$
            .pipe(takeUntil(this._unsubscribeAll))
            .subscribe((config: AppConfig) => {

                this.config = config;
            });

        // Get the data
        this._detailService.data$
            .pipe(takeUntil(this._unsubscribeAll))
            .subscribe((data) => {

                // Store the data
                // this.data = data;
                this.device = data.data.device;
                this.smart_results = data.data.smart_results
                this.metadata = data.metadata;


                // Store the table data
                this.smartAttributeDataSource.data = this._generateSmartAttributeTableDataSource(this.smart_results);

                // Prepare the chart data
                this._prepareChartData();
            });
    }

    /**
     * After view init
     */
    ngAfterViewInit(): void
    {
        // Make the data source sortable
        this.smartAttributeDataSource.sort = this.smartAttributeTableMatSort;
    }

    /**
     * On destroy
     */
    ngOnDestroy(): void
    {
        // Unsubscribe from all subscriptions
        this._unsubscribeAll.next();
        this._unsubscribeAll.complete();
    }

    // -----------------------------------------------------------------------------------------------------
    // @ Private methods
    // -----------------------------------------------------------------------------------------------------

    getAttributeStatusName(attributeStatus: number): string {
        // tslint:disable:no-bitwise

        if(attributeStatus === AttributeStatusPassed){
            return 'passed'

        } else if ((attributeStatus & AttributeStatusFailedScrutiny) !== 0 || (attributeStatus & AttributeStatusFailedSmart) !== 0 ){
            return 'failed'
        } else if ((attributeStatus & AttributeStatusWarningScrutiny) !== 0){
            return 'warn'
        }
        return ''
        // tslint:enable:no-bitwise
    }
    getAttributeScrutinyStatusName(attributeStatus: number): string {
        // tslint:disable:no-bitwise
        if ((attributeStatus & AttributeStatusFailedScrutiny) !== 0){
            return 'failed'
        } else if ((attributeStatus & AttributeStatusWarningScrutiny) !== 0){
            return 'warn'
        } else {
            return 'passed'
        }
        // tslint:enable:no-bitwise
    }

    getAttributeSmartStatusName(attributeStatus: number): string {
        // tslint:disable:no-bitwise
        if ((attributeStatus & AttributeStatusFailedSmart) !== 0){
            return 'failed'
        } else {
            return 'passed'
        }
        // tslint:enable:no-bitwise
    }


    getAttributeName(attribute_data): string {
        const attribute_metadata = this.metadata[attribute_data.attribute_id]
        if(!attribute_metadata){
            return 'Unknown Attribute Name'
        } else {
            return attribute_metadata.display_name
        }
    }
    getAttributeDescription(attribute_data){
        const attribute_metadata = this.metadata[attribute_data.attribute_id]
        if(!attribute_metadata){
            return 'Unknown'
        } else {
            return attribute_metadata.description
        }
        return
    }

    getAttributeValue(attribute_data){
        if(this.isAta()) {
            const attribute_metadata = this.metadata[attribute_data.attribute_id]
            if(!attribute_metadata){
                return attribute_data.value
            } else if (attribute_metadata.display_type == 'raw') {
                return attribute_data.raw_value
            } else if (attribute_metadata.display_type == 'transformed' && attribute_data.transformed_value) {
                return attribute_data.transformed_value
            } else {
                return attribute_data.value
            }
        }
        else{
            return attribute_data.value
        }
    }

    getAttributeValueType(attribute_data){
        if(this.isAta()) {
            const attribute_metadata = this.metadata[attribute_data.attribute_id]
            if(!attribute_metadata){
                return ''
            } else {
                return attribute_metadata.display_type
            }
        } else {
            return ''
        }
    }

    getAttributeIdeal(attribute_data){
        if(this.isAta()){
            return this.metadata[attribute_data.attribute_id]?.display_type == 'raw' ? this.metadata[attribute_data.attribute_id]?.ideal : ''
        } else {
            return this.metadata[attribute_data.attribute_id]?.ideal
        }
    }

    getAttributeWorst(attribute_data){
        const attribute_metadata = this.metadata[attribute_data.attribute_id]
        if(!attribute_metadata){
            return attribute_data.worst
        } else {
            return attribute_metadata?.display_type == 'normalized' ? attribute_data.worst : ''
        }
    }

    getAttributeThreshold(attribute_data){
        if(this.isAta()){
            const attribute_metadata = this.metadata[attribute_data.attribute_id]
            if(!attribute_metadata || attribute_metadata.display_type == 'normalized'){
                return attribute_data.thresh
            } else {
                // if(this.data.metadata[attribute_data.attribute_id].observed_thresholds){
                //
                // } else {
                // }
                // return ''
                return attribute_data.thresh
            }
        } else {
            return (attribute_data.thresh == -1 ? '' : attribute_data.thresh )
        }
    }

    getAttributeCritical(attribute_data){
        return this.metadata[attribute_data.attribute_id]?.critical
    }
    getHiddenAttributes(){
        if (!this.smart_results || this.smart_results.length == 0) {
            return 0
        }

        let attributes_length = 0
        const attributes = this.smart_results[0]?.attrs
        if (attributes) {
            attributes_length = Object.keys(attributes).length
        }

        return attributes_length - this.smartAttributeDataSource.data.length
    }

    isAta(): boolean {
        return this.device.device_protocol == 'ATA'
    }
    isScsi(): boolean {
        return this.device.device_protocol == 'SCSI'
    }
    isNvme(): boolean {
        return this.device.device_protocol == 'NVMe'
    }

    private _generateSmartAttributeTableDataSource(smart_results){
        const smartAttributeDataSource = [];

        if(smart_results.length == 0){
            return smartAttributeDataSource
        }
        const latest_smart_result = smart_results[0];
        let attributes = {}
        if(this.isScsi()) {
            this.smartAttributeTableColumns = ['status', 'name', 'value', 'thresh', 'history'];
            attributes = latest_smart_result.attrs
        } else if(this.isNvme()){
            this.smartAttributeTableColumns = ['status', 'name', 'value', 'thresh', 'ideal', 'history'];
            attributes = latest_smart_result.attrs
        } else {
            // ATA
            attributes = latest_smart_result.attrs
            this.smartAttributeTableColumns = ['status', 'id', 'name', 'value', 'thresh','ideal', 'failure', 'history'];
        }

        for(const attrId in attributes){
            const attr = attributes[attrId]

            // chart history data
            if (!attr.chartData) {


                const attrHistory = []
                for (const smart_result of smart_results){
                    // attrHistory.push(this.getAttributeValue(smart_result.attrs[attrId]))

                    const chartDatapoint = {
                        x: formatDate(smart_result.date, 'MMMM dd, yyyy - HH:mm', this.locale),
                        y: this.getAttributeValue(smart_result.attrs[attrId])
                    }
                    const attributeStatusName = this.getAttributeStatusName(smart_result.attrs[attrId].status)
                    if(attributeStatusName === 'failed') {
                        chartDatapoint['strokeColor'] = '#F05252'
                        chartDatapoint['fillColor'] = '#F05252'
                    } else if (attributeStatusName === 'warn'){
                        chartDatapoint['strokeColor'] = '#C27803'
                        chartDatapoint['fillColor'] = '#C27803'
                    }
                    attrHistory.push(chartDatapoint)
                }

                // var rawHistory = (attr.history || []).map(hist_attr => this.getAttributeValue(hist_attr)).reverse()
                // rawHistory.push(this.getAttributeValue(attr))

                attributes[attrId].chartData = [
                    {
                        name: 'chart-line-sparkline',
                        data: attrHistory
                    }
                ]
            }
            // determine when to include the attributes in table.

            if(!this.onlyCritical || this.onlyCritical && this.metadata[attr.attribute_id]?.critical || attr.value < attr.thresh){
                smartAttributeDataSource.push(attr)
            }
        }
        return smartAttributeDataSource
    }

    /**
     * Prepare the chart data from the data
     *
     * @private
     */
    private _prepareChartData(): void
    {

        // Account balance
        this.commonSparklineOptions = {
            chart: {
                type: 'bar',
                width: 100,
                height: 25,
                sparkline: {
                    enabled: true
                },
                animations: {
                    enabled: false
                }
            },
            // theme:{
            //     // @ts-ignore
            //     // mode:
            //     mode: 'dark',
            // },
            tooltip: {
                fixed: {
                    enabled: false
                },
                x: {
                    show: true
                },
                y: {
                    title: {
                        formatter: function(seriesName) {
                            return '';
                        }
                    }
                },
                marker: {
                    show: false
                },
                theme: this.determineTheme(this.config)

            },
            stroke: {
                width: 2,
                colors: ['#667EEA']
            }
        };
    }

    private determineTheme(config:AppConfig): string {
        if (config.theme === 'system') {
            return this.systemPrefersDark ? 'dark' : 'light'
        } else {
            return config.theme
        }
    }
    // -----------------------------------------------------------------------------------------------------
    // @ Public methods
    // -----------------------------------------------------------------------------------------------------

    toHex(decimalNumb){
        return '0x' + Number(decimalNumb).toString(16).padStart(2, '0').toUpperCase()
    }
    toggleOnlyCritical(){
        this.onlyCritical = !this.onlyCritical
        this.smartAttributeDataSource.data = this._generateSmartAttributeTableDataSource(this.smart_results);

    }

    openDialog() {
        const dialogRef = this.dialog.open(DetailSettingsComponent);

        dialogRef.afterClosed().subscribe(result => {
            console.log(`Dialog result: ${result}`);
        });
    }

    /**
     * Track by function for ngFor loops
     *
     * @param index
     * @param item
     */
    trackByFn(index: number, item: any): any
    {
        return index;
        // return item.id || index;
    }

}
