import { Location } from '@angular/common';

import { MatSelectionList, MatSelectionListChange } from '@angular/material';

import { Component, EventEmitter, OnDestroy, OnInit, ViewChild } from '@angular/core';

import { Directive, Input, NgModule, Output } from '@angular/core';

import { CreateKnokStepService, CreateKnokStepServiceData } from '../wizardstep.service';

import { AbstractControl, AsyncValidatorFn, ValidationErrors, ValidatorFn } from '@angular/forms';

import { slideToLeft, StepBaseComponent } from '../wizard.basestep.component';
// import { StepTwoModel } from './wizardsteptwo.model';

import { FormControl, FormGroup, Validators } from '@angular/forms';

import { ConfigService, IAnalysisTag, IAnalysisTags, IApiError, IConfig, IKnok, Knok, KnokService, TagService } from '../../../shared';

import { Observable } from 'rxjs/Observable';

import { Subscription } from 'rxjs/Subscription';

import { Subscriber } from 'rxjs/Subscriber';

import 'web-animations-js';

// function validatePrices(knokService: KnokService): AsyncValidatorFn {
//     return (c: FormGroup): Observable<ValidationErrors | null> => {
//         return Observable.of([1, 2, 3]).delay(5000).map(e => {
//             if (c.valid) {
//                 return null;
//             }
//             return null;
//         });
//         // let knok: IKnok = new Knok();
//         // knokService.validateKnock(knok).subscribe(e => {
//         //     return null;
//         // }
//         // );

//         //     map((apiError): ValidationErrors | null  => {
//         //     // return null;
//         // }).

//         // return this.knokService.validateKnock(knok).

//         // // if (isEmptyInputValue(control.value)) {
//         // //     return Observable.of(null);
//         // // }
//         // // else {
//         //     // return forecastService.getForecastByDate(control.value).
//         //     map(forecast => {
//         //         // const ctrlName: string = 'entry';
//         //         // let errors: ValidationErrors = {};
//         //         // errors[ctrlName] = {
//         //         //     msg: 'Entry Price To must be greater then Entry Price From'
//         //         // };
//         //         return null; // forecast ? { 'existingDate': { value: control.value } } : null;
//         //     });
//         // // }
//     };
// }

// export function controlValidator(knokService: KnokService, knok: IKnok): AsyncValidatorFn {
//     return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
//       return knokService.validateKnock(knok).map(
//         error => {
//             let errors: ValidationErrors = {};
//             errors[error.id] = {
//                 msg: 'Entry Price To must be greater then Entry Price From'
//             };
//             return errors;
//         //   return (users && users.length > 0) ? {"mobNumExists": true} : null;
//         }
//       );
//     };
//   }

@Component({
    selector: 'knk-step-two',
    templateUrl: './wizardsteptwo.component.html',
    styleUrls: ['./wizardsteptwo.component.scss'],
    providers: [
        {provide: CreateKnokStepService, useExisting: StepTwoComponent } // forwardRef(() => StepOneComponent)
    ],
    animations: [slideToLeft()]
})
export class StepTwoComponent extends StepBaseComponent implements OnInit, OnDestroy {
    @Input('currency') currency: string;
    @Input('nonBaseCurrency') nonBaseCurrency: string;
    @Input('precision') precision: number;
    @Input('knok') knok: IKnok;
    @Output() changeValid = new EventEmitter<boolean>();
    @Output() changestatus = new EventEmitter<number>();
    entryPriceTo: FormControl;
    entryPriceFrom: FormControl;
    exitPriceTo: FormControl;
    exitPriceFrom: FormControl;
    stopLoss: FormControl;
    duration: FormControl;

    durationMin: number = 1;
    durationMax: number;

    faTitle: FormControl;
    taLinkReferencies: FormControl;

    comment: FormControl;
    faTags: FormControl;

    taTitle: FormControl;
    taUploadGraph: FormControl;
    taExplanation: FormControl;
    taTags: FormControl;

    taTagsData: IAnalysisTag[];
    faTagsData: IAnalysisTag[];

    validationStatuses: string[] = ['', '', '', '', '', ''];

    isShowAnalysis: boolean = false;

    config: IConfig;

    validateEntryPrice: string = '';
    validateExitPrice: string = '';
    validateStopLoss: string = '';
    validateDuration: string = '';

    recalcStatuses(control: FormGroup, apiError: IApiError): void {
        const entryPriceToCtrlName: string = 'entryPriceTo';
        const entryPriceFromCtrlName: string = 'entryPriceFrom';
        if (!apiError || (!apiError.errors[entryPriceFromCtrlName] && !apiError.errors[entryPriceToCtrlName])) {
            let entryPriceToCtrl: AbstractControl = control.controls[entryPriceToCtrlName];
            let entryPriceFromCtrl: AbstractControl = control.controls[entryPriceFromCtrlName];
            if (entryPriceFromCtrl.validator && entryPriceToCtrl.validator && entryPriceFromCtrl.valid && entryPriceToCtrl.valid) {
                const status: string = this.knokService.getStatus(Number(entryPriceFromCtrl.value), Number(entryPriceToCtrl.value), this.config.marEntry);
                if (this.validationStatuses[0] !== status) {
                    this.validationStatuses[0] = status;
                    this.updateStatus();
                }
                this.validateEntryPrice = status;
            } else {
                this.validateEntryPrice = '';
            }
        } else {
            this.validateEntryPrice = '';
        }

        const exitPriceToCtrlName: string = 'exitPriceTo';
        const exitPriceFromCtrlName: string = 'exitPriceFrom';
        if (!apiError || (!apiError.errors[exitPriceFromCtrlName] && !apiError.errors[exitPriceToCtrlName])) {
            let exitPriceToCtrl: AbstractControl = control.controls[exitPriceToCtrlName];
            let exitPriceFromCtrl: AbstractControl = control.controls[exitPriceFromCtrlName];
            if (exitPriceFromCtrl.validator && exitPriceToCtrl.validator && exitPriceFromCtrl.valid && exitPriceToCtrl.valid) {
                const status: string = this.knokService.getStatus(Number(exitPriceFromCtrl.value), Number(exitPriceToCtrl.value), this.config.marExit);
                if (this.validationStatuses[1] !== status) {
                    this.validationStatuses[1] = status;
                    this.updateStatus();
                }
                this.validateExitPrice = status;
            } else {
                this.validateExitPrice = '';
            }
        } else {
            this.validateExitPrice = '';
        }

        const stopLossCtrlName: string = 'stopLoss';
        if (!apiError || (!apiError.errors[stopLossCtrlName])) {
            let stopLossCtrl: AbstractControl = this.stepForm.controls[stopLossCtrlName];
            let entryPriceFromCtrl: AbstractControl = this.stepForm.controls[entryPriceFromCtrlName];
            if (stopLossCtrl.validator && stopLossCtrl.valid && entryPriceFromCtrl.validator && entryPriceFromCtrl.valid) {
                const status: string = this.knokService.getStatus(Number(stopLossCtrl.value), Number(entryPriceFromCtrl.value), this.config.marStopLoss);
                if (this.validationStatuses[2] !== status) {
                    this.validationStatuses[2] = status;
                    this.updateStatus();
                }
                this.validateStopLoss = status;
            } else {
                this.validateStopLoss = '';
            }
        } else {
            this.validateStopLoss = '';
        }

        const durationCtrlName: string = 'duration';
        if (!apiError || (!apiError.errors[durationCtrlName])) {
            let durationCtrl: AbstractControl = this.stepForm.controls[durationCtrlName];
            if (durationCtrl.valid && (!this.stepForm.errors || !this.stepForm.errors.duration)) {
                let status: string;
                const val: number = Number(durationCtrl.value);

                switch (true) {
                    case val >= this.durationMin && val < 4:
                        status = 'strong';
                        break;
                    case val >= 4 && val < 11:
                        status = 'medium';
                        break;
                    default:
                        status = 'weak';
                        break;
                }
                if (this.validationStatuses[3] !== status) {
                    this.validationStatuses[3] = status;
                    this.updateStatus();
                }
                this.validateDuration = status;
            } else {
                this.validateDuration = '';
            }
        } else {
            this.validateDuration = '';
        }
    }

    formValidator(): AsyncValidatorFn {
        return (control: FormGroup): Observable<ValidationErrors | null> => {
            // return Observable.of(null);
          return this.knokService.validateKnock(this.knok).
            map((apiError, i) => {
                const stopLossCtrlName: string = 'stopLoss';
                const durationCtrlName: string = 'duration';
                if (Number(control.controls[stopLossCtrlName].value) === 0 && (!apiError || !apiError.errors[stopLossCtrlName])) {
                    if (!apiError ) {
                        apiError = { id: 5, msg: '',
                            errors: [{}]
                        };
                    }
                    apiError.errors[stopLossCtrlName] = 'Stop Loss schould not be empty';
                }
                // if (Number(control.controls[durationCtrlName].value) === 0 && (!apiError || !apiError.errors[durationCtrlName])) {
                //     if (!apiError) {
                //         apiError = { id: 5, msg: '',
                //             errors: [{}]
                //         };
                //     }
                //     apiError.errors[durationCtrlName] = 'Duration should be greater then zero';
                // }
                if (apiError && apiError.id === 5 && apiError.errors) {
                    this.recalcStatuses(control, apiError);
                    return apiError.errors;
                }
                this.recalcStatuses(control, null);
                // control.statusChange updateValueAndValidity();
                return null;
            }
          );
        };
    }

    constructor(private tagService: TagService,
        private configService: ConfigService,
        private knokService: KnokService) {
        super();
        configService.config.subscribe((params) => {
            this.config = params;
            // - (MAD) Maximum Allowed Duration : 21 days
            this.durationMax = params.maximumDuration;
                // a. Entry Price Range : From < To
                // - (MAR Entry) : Maximum Allowed Range between Entry From and To  (in Percent)
                // validatePriceRange('entry', params.marEntry),
                // b. Exit Price Range : From < To
                // - (MAR Exit) :  Maximum Allowed Range between Exit From and To  (in Percent)
                // validatePriceRange('exit', params.marExit),
                // - Minimum Allowed Profit Between [Entry To] to  [ Exit From]
                // validateMinProfit(params.minProfit),
                // c. Entry To Price <  Exit From Price
                // validateEntryExitPriceRange(),
                // d. StopLoss < Entry From
                // - Maximum Allowed Range Between StopLoss and Entry Price From
                // validateStopLoss('stopLossCtrl', params.marStopLoss),
                // validateDuration('durationCtrl', this.durationMin)]
            // );
        });

        this.configService = configService;
        // const model: StepTwoModel = this.stepModel as StepTwoModel;
        this.currStepName = ['Price Ranges'];
        this.entryPriceTo = new FormControl();
        // this.entryPriceToCtrl.setValue(0.00);
        this.entryPriceTo.valueChanges.subscribe(x => {
            this.knok.entryPriceTo = Number(x);
        });
        this.stepForm.addControl('entryPriceTo', this.entryPriceTo);

        this.entryPriceFrom = new FormControl();
        // this.entryPriceFromCtrl.setValue(model.entryPriceFrom);
        this.entryPriceFrom.valueChanges.subscribe(x => {
            this.knok.entryPriceFrom = Number(x);
        });
        this.stepForm.addControl('entryPriceFrom', this.entryPriceFrom);

        this.exitPriceTo = new FormControl();
        // this.exitPriceToCtrl.setValue(model.exitPriceTo);
        this.exitPriceTo.valueChanges.subscribe(x => {
            this.knok.exitPriceTo = Number(x);
        });
        this.stepForm.addControl('exitPriceTo', this.exitPriceTo);

        this.exitPriceFrom = new FormControl();
        // this.exitPriceFromCtrl.setValue(model.exitPriceFrom);
        this.exitPriceFrom.valueChanges.subscribe(x => {
            this.knok.exitPriceFrom = Number(x);
        });
        this.stepForm.addControl('exitPriceFrom', this.exitPriceFrom);

        this.stopLoss = new FormControl();
        // this.stopLossCtrl.setValue(model.stopLoss);
        this.stopLoss.valueChanges.subscribe(x => {
            this.knok.stopLoss = Number(x);
        });
        this.stepForm.addControl('stopLoss', this.stopLoss);

        this.duration = new FormControl();
        this.duration.valueChanges.subscribe(x => {
            this.knok.duration = Number(x);
        });
        this.stepForm.addControl('duration', this.duration);
        // this.duration.setValue(this.durationMin);

        // Analysis
        // TA
        this.taTitle = new FormControl();
        this.taTitle.valueChanges.subscribe(x => {
            this.knok.technical.header = x;
            this.knok.hasTechnical = (x && x.length > 0);
        });
        this.stepForm.addControl('taTitle', this.taTitle);

        this.taUploadGraph = new FormControl();
        this.taUploadGraph.valueChanges.subscribe(x => {
            // this.knok.technical.image. uploadGraph = x;
            const uploadGraph: string = 'uploadGraph';
            const imageSrc: string = x;
            if (imageSrc && imageSrc !== '') {
                if (imageSrc.startsWith('http://') || imageSrc.startsWith('https://')) {
                    this.knok.technical.image.url = imageSrc;
                } else {
                    // data:image/png;base64,
                    const contentType: string = imageSrc.substr(imageSrc.indexOf('data:') + 5, imageSrc.indexOf(';') - 5);
                    this.knok.technical.image.contentType = contentType;
                    this.knok.technical.image.content = imageSrc.substr(imageSrc.indexOf('base64,') + 7); // this.b64toBlob(imageSrc.substr(imageSrc.indexOf('base64,') + 7), contentType);
                }
            }
        });
        this.stepForm.addControl('taUploadGraph', this.taUploadGraph);

        this.taExplanation = new FormControl();
        this.taExplanation.valueChanges.subscribe(x => {
            this.knok.technical.description = x;
        });
        this.stepForm.addControl('taExplanation', this.taExplanation);

        this.taTags = new FormControl();
        this.taTags.valueChanges.subscribe(x => {
            this.knok.technical.tags = x;
        });
        this.stepForm.addControl('taTags', this.taTags);

        // FA
        this.faTitle = new FormControl();
        this.faTitle.valueChanges.subscribe(x => {
            this.knok.fundamental.header = x;
            this.knok.hasFundamental = (x && x.length > 0);
        });
        this.stepForm.addControl('faTitle', this.faTitle);

        this.taLinkReferencies = new FormControl();
        this.taLinkReferencies.valueChanges.subscribe(x => {
            this.knok.fundamental.references = JSON.stringify(x);
        });
        this.stepForm.addControl('taLinkReferencies', this.taLinkReferencies);

        this.comment = new FormControl();
        this.comment.valueChanges.subscribe(x => {
            this.knok.fundamental.description = x;
        });
        this.stepForm.addControl('comment', this.comment);

        this.faTags = new FormControl();
        this.faTags.valueChanges.subscribe(x => {
            this.knok.fundamental.tags = x;
        });
        this.stepForm.addControl('faTags', this.faTags);

        this.stepForm.setAsyncValidators(this.formValidator());

        this.stepForm.statusChanges.subscribe(
            (res) => {
                if (res === 'PENDING') {
                    return;
                }
                const isValid: boolean = res === 'VALID';
                this.isShowAnalysis = this.isShowAnalysis || isValid;
                this.changeValid.emit(isValid);
            }
        );
    }

    showAnalysis(): void {
        this.isShowAnalysis = true;
    }

    ngOnInit(): void {
        super.ngOnInit();
        this.tagService.taTags.subscribe((tags: IAnalysisTags) => {
            if (tags) {
                this.taTagsData = tags.items;
            } else {
                console.log('TA Tags are not found');
            }
        });

        this.tagService.faTags.subscribe((tags: IAnalysisTags) => {
            if (tags) {
                this.faTagsData = tags.items;
            } else {
                console.log('FA Tags are not found');
            }
        });
    }

    ngOnDestroy(): void {
        // this.exchangeChange.unsubscribe();
    }

    show(): void {
        super.show();
        if (this.knok.entryPriceFrom) {
            this.entryPriceFrom.setValue(this.knok.entryPriceFrom);
        } else {
            this.entryPriceFrom.setValue(0);
        }
        if (this.knok.entryPriceTo) {
            this.entryPriceTo.setValue(this.knok.entryPriceTo);
        } else {
            this.entryPriceTo.setValue(0);
        }
        if (this.knok.exitPriceFrom) {
            this.exitPriceFrom.setValue(this.knok.exitPriceFrom);
        } else {
            this.exitPriceFrom.setValue(0);
        }
        if (this.knok.exitPriceTo) {
            this.exitPriceTo.setValue(this.knok.exitPriceTo);
        } else {
            this.exitPriceTo.setValue(0);
        }
        if (this.knok.stopLoss) {
            this.stopLoss.setValue(this.knok.stopLoss);
        } else {
            this.stopLoss.setValue(0);
        }
        if (this.knok.duration) {
            this.duration.setValue(this.knok.duration);
        } else {
            this.duration.setValue(this.durationMin);
        }
    }

    get validateFA(): string {
        const faTitleCtrl: string = 'faTitle';
        let ctrl: AbstractControl = this.stepForm.controls[faTitleCtrl];
        let status: string = '';
        if (!ctrl || !ctrl.value) {
            status = 'missing';
        }
        if (this.validationStatuses[4] !== status) {
            this.validationStatuses[4] = status;
            this.updateStatus();
        }
        return status;
    }

    get validateTA(): string {
        const taTitleCtrl: string = 'taTitle';
        let ctrl: AbstractControl = this.stepForm.controls[taTitleCtrl];
        let status: string = '';
        if (!ctrl || !ctrl.value) {
            status = 'missing';
        }
        if (this.validationStatuses[5] !== status) {
            this.validationStatuses[5] = status;
            this.updateStatus();
        }
        return status;
    }

    private updateStatus(): void {
        if (this.changestatus) {
            let totalPersent: number = 0;
            this.validationStatuses.forEach(status =>
                totalPersent += (status === 'weak' ? 33.333 : status === 'medium' ? 66.666 : status === 'strong' ? 100 : 0));
            this.changestatus.emit(totalPersent / 4);
        }
    }

    // private getStatus(valueFrom: number, valueTo: number, MAR: number): string {
    //     // (Entry price range/MAR)*100
    //     const val: number =  (1 - (valueTo - valueFrom) / (MAR / 100)) * 100; // Math.round((valueTo - valueFrom) / (valueFrom / 100 * MAR) * 100);
    //     // const val: number = (valueTo - valueFrom) / (valueFrom * this.MAR);
    //     switch (true) {
    //     case val <= 100 && val > 80 : // 100 - 80 = week
    //         return 'weak';
    //     case val <= 80 && val > 40 : // 80 - 40 = medium
    //         return 'medium';
    //     case val <= 40 && val >= 0 : // 40 - 0 = strong
    //         return 'strong';
    //     default :
    //         return 'weak';
    //     }
    // }
}
