import { AfterContentChecked, AfterViewInit, Component, ElementRef, Inject, Input, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';

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

import { WizardStepDirective } from '../core/components/wizard/wizard.component';

import { WizardComponent } from '../core/components/wizard/wizard.component';

import { Observer } from 'rxjs/Observer';

import { Observable } from 'rxjs/Observable';

import 'rxjs/add/observable/empty';
import 'rxjs/add/observable/interval';
import { take } from 'rxjs/operators';

import { IntervalObservable } from 'rxjs/observable/IntervalObservable';

import { BaseComponent } from '../core/components/base.component';

import { ActivatedRoute, Router } from '@angular/router';

import { AccountService, ConfigService, IApiError, IKnok, IKnokAnalysis, IKnokImage, IReference, isApiResponseError, IUserAccounts, Knok, KnokService, TokenService, UserCredentials, UserService } from '../core/shared';

import { Chart } from 'chart.js';

import 'chartjs-plugin-annotation';

import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';

export class StubWizardStepService implements CreateKnokStepService {
  show(): void {
    console.log('show');
  }

  hide(): void {
    console.log('hide');
  }

  set changeCallback(handler: { (): void }) {
    console.log('changeCallback');
  }

  markAsTouched(): void {
    console.log('markAsTouched');
  }

  get valid(): boolean {
    return false;
  }

  get isCompleted(): boolean {
    return false;
  }

  get stepName(): string[] {
    return [];
  }

  loadData(value: { [key: string]: string }): void {
    console.log('loadData');
  }

  saveData(): { [key: string]: string } {
    return null;
  }

  getValue(propName: string): string {
    return null;
  }
}

abstract class Evt extends EventTarget {
  abstract get value(): string;
}

@Component({
  selector: 'knk-createknok',
  templateUrl: './createknok.component.html',
  styleUrls: ['./createknok.component.scss']
})
export class CreateKnokComponent extends BaseComponent implements OnInit, AfterViewInit {
  steps: Array<CreateKnokStepService> = [new StubWizardStepService()];
  newknok: IKnok = new Knok();
  observer: MutationObserver;
  observer1: MutationObserver;
  animationState: string = 'center';
  indicatorPos: number = 0;
  backendError: IApiError;
  chart: Chart;
  @ViewChild('canvas') canvas;

  get activeStep(): CreateKnokStepService {
    return this.wizard ? this.wizard.activeStep : null;
  }

  get activeStepIndex(): number {
    return this.steps.indexOf(this.currentStep);
  }

  get currentStep(): CreateKnokStepService {
    return this.wizard ? this.wizard.activeStep : null;
  }

  @ViewChild(WizardComponent)
  wizard: WizardComponent;

  @ViewChildren('stepper')
  steppers: QueryList<ElementRef>;

  isPreviewDisplayed: boolean = false;
  dataUser: IUserAccounts;
  avatarHref: string; // SafeResourceUrl;
  referesesContent: Array<IReference> = [];

  maximumDuration: number;
  marEntry: number;
  marExit: number;
  marStopLoss: number;
  startDate: Date;

  constructor(private router: Router,
              route: ActivatedRoute,
              private tokenService: TokenService,
              private knokService: KnokService,
              private configService: ConfigService,
              userService: UserService,
              private domSanitizer: DomSanitizer,
              private accountService: AccountService) {
    super(userService, route);
  }

  ngOnInit(): void {
    super.ngOnInit();
    this.configService.config.subscribe((params) => {
      this.maximumDuration = params.maximumDuration;
      this.marEntry = params.marEntry;
      this.marExit = params.marExit;
      this.marStopLoss = params.marStopLoss;
    });
  }

  ngAfterViewInit(): void {
    let config: MutationObserverInit = {
      attributes: true,
      childList: true,
      characterData: true
    };

    this.observer = new MutationObserver((mutations: MutationRecord[]) => {
      mutations.forEach((mutation: MutationRecord) => {
        this.steps = this.wizard.steps.toArray();
      });
    });

    this.steppers.forEach((el: ElementRef) => {
      this.observer.observe(el.nativeElement, config);
    });
  }

  discardAndCancel(): void {
    this.router.navigate([this.lang, `discover`]);
  }

  previewKnok(): void {
    this.userService.loadUser().subscribe((user) => {
      this.dataUser = user;
      if (this.dataUser.user.hasAvatar) {
        this.avatarHref = `${SETTINGS.API_URL}${this.dataUser.user.avatarUrl}`;
      }
      // if (this.dataUser.user.hasAvatar) {
      //     this.accountService.getAvatar().subscribe(
      //         (src) => {
      //             let reader: FileReader = new FileReader();
      //             reader.onloadend = () => {
      //                 this.avatarHref = reader.result;
      //             };
      //             reader.readAsDataURL(src);
      //         },
      //         (error) => {
      //             console.log(error);
      //     });
      // }
    });

    if (this.newknok.fundamental && this.newknok.fundamental.references) {
      const refs: Array<{ reference: string }> = JSON.parse(this.newknok.fundamental.references);
      this.referesesContent = [];
      this.startDate = new Date();
      refs.forEach(r => {
        // this.referesesContent.push({header: `Bitcoin Could Emerge As A ‘Threat’ To US Dollar In Future, Suggests St. Louis Fed Chief`,
        //     description: `The president of the St. Louis Fed says the US dollar could end up “threatened” by Bitcoin, notes crypto’s ability to cut costs in trade.`,
        //     url: `https://cointelegraph.com/news/bitcoin-could-emerge-as-a-threat-to-us-dollar-in-future-suggests-st-louis-fed-chief`,
        //     image: `https://images.cointelegraph.com/images/725_Ly9jb2ludGVsZWdyYXBoLmNvbS9zdG9yYWdlL3VwbG9hZHMvdmlldy85MGI0NmQzNDZjNWY5ZDQyZTEwYTc3MjBkZDMyNWI4NC5qcGc=.jpg`,
        //     publishedBy: 'Test',
        //     published: new Date('05/15/2018')
        // });
        this.knokService.getKnokFAReference({url: r.reference}).subscribe(res => {
          if (!this.isApiError(res)) {
            this.referesesContent.push(res);
          }
        });
      });
    }
    this.initChart();
    this.isPreviewDisplayed = true;
    window.scrollTo(0, 0);
  }

  isApiError<T>(data: IApiError | IReference): data is IApiError {
    return (<IApiError>data).id === -1;
  }

  initChart(): void {
    if (this.canvas && this.canvas.nativeElement) {
      setTimeout(() => {
        const self: CreateKnokComponent = this;
        this.chart = new Chart(this.canvas.nativeElement, {
          type: 'line',
          data: {
            // labels: ['July 1', '2', '3', '4', '5', '6', '7'],
            datasets: [
              {
                pointBackgroundColor: ['rgba(0,0,0,0)', 'rgba(0,0,0,0)', 'rgba(0,0,0,0)', 'rgba(0,0,0,0)', 'rgba(0,0,0,0)', 'rgba(0,0,0,0)', 'green'],
                pointBorderColor: ['rgba(0,0,0,0)', 'rgba(0,0,0,0)', 'rgba(0,0,0,0)', 'rgba(0,0,0,0)', 'rgba(0,0,0,0)', 'rgba(0,0,0,0)', 'green'],
                backgroundColor: 'rgba(0,0,0,0.1)',
                borderWidth: 2,
                hoverBackgroundColor: 'rgba(0,0,0,0)',
                hoverBorderColor: 'rgba(0,0,0,0)',
                data: [
                  {x: this.startKnokDate, y: null},
                  {x: this.endKnokDate, y: null}
                  // {x: new Date('05/01/2018 23:15:30'), y: 1.2},
                  // {x: new Date('05/02/2018 23:15:30'), y: 1.1},
                  // {x: new Date('05/03/2018 13:15:30'), y: 1.3},
                  // {x: new Date('05/03/2018 23:15:30'), y: 1.25},
                  // {x: new Date('05/04/2018 03:15:30'), y: 1.3},
                  // {x: new Date('05/04/2018 13:15:30'), y: 1.3},
                  // {x: new Date('05/05/2018 00:00:00'), y: 1.3},
                  // {x: new Date('05/12/2018 00:00:00'), y: null}
                ],
                borderColor: '#3cba9f',
                fill: false
                // pointColor: 'rgba(0, 0, 0, 0)'
              }
            ]
          },
          options: {
            // tension: 0,
            maintainAspectRatio: false,
            //   responsive: true,
            elements: {
              point: {
                radius: 10,
                hitRadius: 10,
                hoverRadius: 10
              }
              // line: {
              //     tension: 0 // disables bezier curves
              // }
            },
            // //   layout: {
            // //     padding: {
            // //         left: 0,
            // //         right: 0,
            // //         top: 0,
            // //         bottom: 0
            // //     }
            // //   },
            // //   // showLines: false,
            scales: {
              xAxes: [{
                type: 'time',
                time: {
                  unit: 'day',
                  displayFormats: {
                    day: 'MMM D'
                  }
                },
                ticks: {
                  display: true,
                  beginAtZero: false,
                  stepSize: 1,
                  // suggestedMin: new Date('05/01/2018'),
                  min: this.startKnokDate,
                  max: this.endKnokDate
                  // gridLines : {
                  //   display : false
                  // },
                }
              }],
              yAxes: [{
                ticks: {
                  display: true,
                  beginAtZero: false,
                  stepSize: this.newknok.entryPriceFrom - this.newknok.stopLoss,
                  min: this.newknok.stopLoss,
                  max: this.newknok.exitPriceTo,
                  fontColor: ['rgb(0,128,0)', 'rgba(44,44,44,0.8)', 'rgba(44,44,44,0.8)', 'rgba(0,0,0,1)', 'rgba(255,0,0,1)'],
                  callback: (value: number, index: number, values: string): string => {
                    if (value === self.newknok.stopLoss) {
                      return 'Stop Loss ' + value.toFixed(2);
                    }
                    if (value === self.newknok.entryPriceFrom) {
                      return 'Entry ' + value.toFixed(2);
                    }

                    if (value === self.newknok.exitPriceTo) {
                      return 'Exit ' + value.toFixed(2);
                    }
                    return value.toFixed(2);
                  }
                }
              }]
            },
            legend: {
              display: false
            },
            title: {
              display: false
            },
            tooltips: {
              enabled: false
            },
            annotation: {
              annotations: [{
                type: 'line',
                mode: 'horizontal',
                scaleID: 'y-axis-0', // this is the default value. if your chart has custom IDs for the axis you need to use that value here
                value: this.newknok.stopLoss, // should be a number
                borderColor: 'red',
                borderWidth: 3
              },
                {
                  type: 'line',
                  mode: 'horizontal',
                  scaleID: 'y-axis-0', // this is the default value. if your chart has custom IDs for the axis you need to use that value here
                  value: this.newknok.entryPriceFrom, // should be a number
                  borderColor: 'black',
                  borderWidth: 1,
                  borderDash: [10, 4]
                },
                {
                  type: 'line',
                  mode: 'horizontal',
                  scaleID: 'y-axis-0', // this is the default value. if your chart has custom IDs for the axis you need to use that value here
                  value: this.newknok.exitPriceTo, // should be a number
                  borderColor: 'rgb(0,128,0)',
                  borderWidth: 3,
                  label: {
                    // Background color of label, default below
                    backgroundColor: 'rgba(0,0,0,0.8)',

                    // Font family of text, inherits from global
                    // fontFamily: 'sans-serif',

                    // Font size of text, inherits from global
                    fontSize: 12,

                    // Font style of text, default below
                    fontStyle: 'bold',

                    // Font color of text, default below
                    fontColor: '#000',

                    // Padding of label to add left/right, default below
                    // xPadding: 6,

                    // Padding of label to add top/bottom, default below
                    // yPadding: 6,

                    // Radius of label rectangle, default below
                    // cornerRadius: 6,

                    // Anchor position of label on line, can be one of: top, bottom, left, right, center. Default below.
                    position: 'left',

                    // Adjustment along x-axis (left-right) of label relative to above number (can be negative)
                    // For horizontal lines positioned left or right, negative values move
                    // the label toward the edge, and positive values toward the center.
                    xAdjust: -10,

                    // Adjustment along y-axis (top-bottom) of label relative to above number (can be negative)
                    // For vertical lines positioned top or bottom, negative values move
                    // the label toward the edge, and positive values toward the center.
                    yAdjust: 10,

                    // Whether the label is enabled and should be displayed
                    enabled: false,

                    // Text to display in label - default is null
                    content: 'Test label'
                  }
                },
                {
                  type: 'box',
                  xScaleID: 'x-axis-0',
                  yScaleID: 'y-axis-0',
                  xMin: this.startKnokDate,
                  xMax: this.endKnokDate,
                  yMin: this.newknok.stopLoss,
                  yMax: this.newknok.exitPriceTo,
                  backgroundColor: 'rgba(0, 0, 0, 0.288)',
                  borderColor: 'rgba(0, 0, 0, 0.288)',
                  borderWidth: 0
                }]
            }
            // //   spanGaps: false,
            // //   scaleShowLabels : false,
            //   scales: {
            //     xAxes: [{
            //       display: true,
            //       gridLines : {
            //         display : false
            //       },
            //       ticks: {
            //         display: false
            //       }
            //     }],
            //     yAxes: [{
            //       display:  true,
            //       gridLines : {
            //         display : false
            //     },
            //     ticks: {
            //       display: false
            //     }
            //     }]
            //   }
          }
        });
        // this.chart.canvas.parentNode.style.height = '24px';
      }, 10);
    }
  }

  publishKnok(): void {
    let knok: IKnok = Object.assign({}, this.newknok);
    if (!knok.hasTechnical) {
      knok.technical = null;
    }
    if (!knok.hasFundamental) {
      knok.fundamental = null;
    }
    // console.log(this.newknok);
    this.knokService.createKnok(knok).subscribe(
      (savedKnok) => {
        console.log('knok is created, go to discover');
        this.router.navigate([this.lang, `discover`]);
      },
      (err) => {
        this.backendError = err.error;
      }
    );

    console.log('The dialog was closed');
    this.isPreviewDisplayed = false;
  }

  getDataSet(): Observable<{ [key: string]: string }> {
    return Observable.empty();
    // return IntervalObservable.create(3000)\
    //    .map((val, i) => {
    //     return {title: 'Title' + i.toString(),
    //         name: 'Name' + i.toString(),
    //         firstName: 'First Name' + i.toString(),
    //         lastName: 'Last Name' + i.toString()};
    // }).pipe(take(2));

    // return Observable.create((observer: Observer<{[key: string]: string}>) => {

    //     observer.next({title: 'Title1',
    //         name: 'Name1',
    //         firstName: 'First Name1',
    //         lastName: 'Last Name1'});

    //       setInterval(() => {
    //         observer.next({title: 'Title2',
    //         name: 'Name2',
    //         firstName: 'First Name2',
    //         lastName: 'Last Name2'});
    //         observer.complete();
    //       }, 5000);
    // });
  }

  updateIndicator(pos: number): void {
    // this.configService.config.subscribe((params) => {
    // Entry price range (spread)	10	        (1 - Entry price range/MAR entry)*100
    const entryWeight: number = 0.10;
    let entry: number = (this.newknok.entryPriceTo > 0 && this.newknok.entryPriceFrom > 0) ?
      (1 - (this.newknok.entryPriceTo - this.newknok.entryPriceFrom) / (this.marEntry / 100)) * 100 : 0;

    // Exit price range (spread)	10	        (1 - Exit price range/MAR exit)*100
    const exitWeight: number = 0.10;
    let exit: number = (this.newknok.exitPriceTo > 0 && this.newknok.exitPriceFrom > 0) ?
      (1 - (this.newknok.exitPriceTo - this.newknok.exitPriceFrom) / (this.marExit / 100)) * 100 : 0;

    // Distance from entry to exit price (potential profit)	40
    const entryToExitWeight: number = 0.40;
    let entryToExit: number = (this.newknok.exitPriceFrom > 0 && this.newknok.entryPriceTo > 0) ?
      ((this.newknok.exitPriceTo - this.newknok.entryPriceFrom) / this.newknok.entryPriceTo) * 100 : 0;

    // Distance from entry to stop loss	10
    const entryToStopWeight: number = 0.10;
    let entryToStopLoss: number = (this.newknok.stopLoss > 0 && this.newknok.entryPriceFrom > 0) ?
      // ((this.newknok.entryPriceFrom - this.newknok.stopLoss) / this.newknok.stopLoss) * 100 : 0;
      (1 - (this.newknok.entryPriceFrom - this.newknok.stopLoss) / (this.marStopLoss / 100)) * 100 : 0;

    // Knok duration	            30           (1 - knok duration/MAD)*100
    const durationWeight: number = 0.30;
    let duration: number = this.newknok.duration > 0 ?
      (1 - this.newknok.duration / this.maximumDuration) * 100 : 0;

    let profit: number = 0;
    profit = entry * entryWeight +
      exit * exitWeight +
      entryToExit * entryToExitWeight +
      entryToStopLoss * entryToStopWeight +
      duration * durationWeight;
    // Once it's only the 50% we need to divide it to 2 (50%)
    // profit = profit / 2;

    if (this.newknok.hasTechnical) {
      profit += 25;
    }

    if (this.newknok.hasFundamental) {
      profit += 25;
    }

    // Makes the indicator posision in the center of the check mark
    if (profit > 95) {
      profit = 95;
    }

    // if (profit <= 0) {
    //     profit = 0;
    // }
    let self: CreateKnokComponent = this;
    setTimeout(() => self.indicatorPos = 2 * profit, 10); // 200px / 100% * pos
    // });
  }

  get profitValue(): number {
    if (this.newknok.exitPriceFrom && this.newknok.entryPriceTo) {
      return (this.newknok.exitPriceFrom - this.newknok.entryPriceTo) / this.newknok.entryPriceTo * 100;
    } else {
      return 0;
    }
  }

  get profitStatus(): string {
    const profit: number = this.profitValue;
    if (profit < 30) {
      return 'Low';
    } else if (profit < 100) {
      return 'Med.';
    } else {
      return 'High';
    }
  }

  get entryPriceRange(): string {
    return `${this.newknok.entryPriceFrom} ~ ${this.newknok.entryPriceTo}`;
  }

  get exitPriceRange(): string {
    return `${this.newknok.exitPriceFrom} ~ ${this.newknok.exitPriceTo}`;
  }

  // get entryPriceRangeStatus(): string {
  //     return this.knokService.getStatus(this.newknok.entryPriceFrom, this.newknok.entryPriceTo, this.marEntry);
  // }

  // get exitPriceRangeStatus(): string {
  //     return this.knokService.getStatus(this.newknok.exitPriceFrom, this.newknok.exitPriceTo, this.marExit);
  // }

  get ratingValue(): Array<number> {
    const arraycount: number = 5;
    let array: Array<number> = [0, 0, 0, 0, 0];
    // array.forEach((el, i) => {
    //   if (i <= this.dataUser.user.knokerRatingPoints - 1) {
    //     array[i] = 1;
    //   } else if (this.dataUser.user.knokerRatingPoints % 1 > 0) {
    //     array[i] = 0.5;
    //   } else {
    //     array[i] = 0;
    //   }
    // });
    return array;
  }

  get technicalImage(): SafeResourceUrl | string {
    if (this.newknok.technical.image && this.newknok.technical.image.url !== '') {
      return this.newknok.technical.image.url;
    }
    if (this.newknok.technical.image.content && this.newknok.technical.image.content !== '') {
      return this.domSanitizer.bypassSecurityTrustResourceUrl('data:' + this.newknok.technical.image.contentType + ';base64,' + this.newknok.technical.image.content);
    }
    return null;
  }

  getRefByLink(ref: string): SafeResourceUrl {
    return this.domSanitizer.bypassSecurityTrustResourceUrl(ref);
  }

  getTimeAgo(date: Date): string {
    let hours: number = this.truncateToInt((this.startDate.getTime() - (new Date(date)).getTime()) / (1000 * 60 * 60));
    let days: number = 0;
    if (hours >= 24) {
      days = this.truncateToInt(hours / 24);
    }
    hours = hours - days * 24;
    if (days > 0) {
      return days === 1 ? `${days} day ago` : `${days} days ago`;
    }
    return hours === 1 ? `${hours} hour ago` : `${hours} hours ago`;
  }

  openRef(url: string): void {
    window.open(url, '_blank');
  }

  private truncateToInt(n: number): number {
    return parseInt(n.toString().match(/^-?\d+(?:\.\d{0})?/)[0], 10);
  }

  private get progressSteps(): number {
    const stepWidth: number = 100 / this.steps.length;
    const currentIndex: number = this.steps.indexOf(this.currentStep) + 1;
    return stepWidth * currentIndex;
  }

  private get startKnokDate(): Date {
    let currDate: Date = new Date();
    currDate = new Date(`${currDate.getMonth() + 1}/${currDate.getDate()}/${currDate.getFullYear()}`);
    return currDate;
  }

  private get endKnokDate(): Date {
    const currTime: number = (new Date()).getTime();
    const durationTime: number = (this.newknok.duration * 24 * 60 * 60 * 1000);
    let currDate: Date = new Date(currTime + durationTime);
    currDate = new Date(`${currDate.getMonth() + 1}/${currDate.getDate()}/${currDate.getFullYear()}`);
    return currDate;
  }
}
