// NG2
import { Component, Input, SimpleChanges, Output, EventEmitter, forwardRef, ElementRef, trigger, state, style, transition, animate, AfterContentInit, OnChanges, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
// APP
import { Helpers } from '../../utils/Helpers';

// Value accessor for the component (supports ngModel)
const TILES_VALUE_ACCESSOR = {
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => NovoTilesElement),
    multi: true
};

@Component({
    selector: 'novo-tiles',
    providers: [TILES_VALUE_ACCESSOR],
    template: `
        <div class="tile-container" [class.active]="focused">
            <div class="tile" *ngFor="let option of _options; let i = index" [ngClass]="{active: option.checked, disabled: option.disabled}" (click)="select($event, option, i)" [attr.data-automation-id]="option.label || option">
                <input class="tiles-input" [name]="name" type="radio" [value]="option.checked || option" [attr.id]="name + i" (change)="select($event, option, i)" (focus)="setFocus(true)" (blur)="setFocus(false)">
                <label [attr.for]="name + i" [attr.data-automation-id]="option.label || option">
                    {{ option.label || option}}
                </label>
            </div>
            <span class="active-indicator" [@tileState]="state" [hidden]="activeTile === undefined || activeTile === null"></span>
        </div>
    `,
    animations: [
        trigger('tileState', [
            state('inactive', style({
                opacity: '0'
            })),
            state('active', style({
                opacity: '1'
            })),
            transition('inactive => active', animate('200ms ease-in')),
            transition('active => inactive', animate('200ms ease-out'))
        ])
    ],
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NovoTilesElement implements ControlValueAccessor, AfterContentInit, OnChanges {
    @Input() name: string;
    @Input() options: any;
    @Input() required: boolean;
    @Output() onChange: EventEmitter<any> = new EventEmitter();
    @Output() onDisabledOptionClick: EventEmitter<any> = new EventEmitter();

    _options: Array<any> = [];
    public activeTile: any = null;
    public state: String = 'inactive';
    public focused: boolean = false;

    model: any;
    onModelChange: Function = () => {
    };
    onModelTouched: Function = () => {
    };

    constructor(private element: ElementRef, private ref: ChangeDetectorRef) {
    }

    public setFocus(focus: boolean): void {
        this.focused = focus;
    }

    ngAfterContentInit() {
        this.name = this.name || '';
        this.setupOptions();
    }

    ngOnChanges(change: SimpleChanges) {
        if (change['options'] && change['options'].currentValue && !change['options'].firstChange) {
            this.name = this.name || '';
            this._options = [];
            this.setupOptions();
        }
    }

    setupOptions() {
        if (this.options && this.options.length && (this.options[0].value === undefined || this.options[0].value === null)) {
            this._options = this.options.map((x) => {
                let item = { value: x, label: x, checked: this.model === x };
                if (item.checked) {
                    this.setTile(item);
                }
                return item;
            });
        } else {
            this._options = this.options.map((x) => {
                x.checked = this.model === x.value;
                if (x.checked) {
                    this.setTile(x);
                }
                return x;
            });
        }
        this.ref.markForCheck();
    }

    select(event, item) {
        if (event) {
            event.stopPropagation();
            event.preventDefault();
        }
        if (item.checked) {
            return;
        }

        if (!item.disabled) {
            for (let option of this._options) {
                option.checked = false;
            }

            item.checked = !item.checked;
            this.onChange.emit(item.value);
            this.onModelChange(item.value);
            this.setTile(item);
            this.model = item.value;
        } else {
            this.onDisabledOptionClick.emit(item);
        }
        this.ref.markForCheck();
    }

    setTile(item) {
        if (item) {
            this.activeTile = item.value;
            this.moveTile();
        }
    }

    moveTile() {
        setTimeout(() => {
            let ind = this.element.nativeElement.querySelector('.active-indicator');
            let el = this.element.nativeElement.querySelector('.tile.active');
            let w = el.clientWidth;
            let left = el.offsetLeft;

            // These style adjustments need to occur in this order.
            setTimeout(() => {
                ind.style.width = `${w + 4}px`;
                setTimeout(() => {
                    ind.style.transform = `translateX(${left}px)`;
                    setTimeout(() => {
                        this.state = 'active';
                        this.ref.markForCheck();
                    });
                });
            });
        });
    }

    writeValue(model: any): void {
        this.model = model;
        if (!Helpers.isBlank(model)) {
            this.setupOptions();
        }
    }

    registerOnChange(fn: Function): void {
        this.onModelChange = fn;
    }

    registerOnTouched(fn: Function): void {
        this.onModelTouched = fn;
    }
}
