import { Component, EventEmitter, Input, NgZone, OnInit, Output, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { Editor } from 'primeng/editor';
import { OverlayPanel } from 'primeng/overlaypanel';
import { Subscription } from 'rxjs/Subscription';
import { AppService } from '../../../app.service';
import { SERVICES } from '../../../constants';
import { MessageTemplateModel } from '../../../models/message-template.model';
import { PlaceholderOptionsEnum } from '../../../models/placeholder-options.enum';
import { TemplateTypeEnum } from '../../../models/template-type.enum';
import { SaveService } from '../../../oneit/services/save.service';
import { UtilsService } from '../../../oneit/services/utils.service';
import { AdminPortalLayoutService } from '../admin-portal-layout/admin-portal-layout.service';
import { BaseComponent } from '../base/base.component';

@Component({
    selector: 'app-edit-message-template',
    templateUrl: './edit-message-template.component.html'
})
export class EditMessageTemplateComponent extends BaseComponent implements OnInit {

    @Input() objectID: string;
    // tslint:disable-next-line:prefer-output-readonly
    @Output() closeModal: EventEmitter<any> = new EventEmitter<any>();

    subscriptions: Array<Subscription> = [];
    @ViewChild('form') form: NgForm;
    @ViewChild('messageContent') messageContentEditor: Editor;
    @ViewChild('contentLinkModal') contentLinkModal: OverlayPanel;
    createdObjs;
    updatedObjs;
    deletedObjs;

    messageTemplate = new MessageTemplateModel();
    messageTemplateTypes: Array<TemplateTypeEnum> = [];
    subjectPlaceholderOptions: Array<PlaceholderOptionsEnum> = [];
    contentPlaceholderOptions: Array<PlaceholderOptionsEnum> = [];
    ContentPlaceholderOptionsEnum: Array<PlaceholderOptionsEnum> = [];
    subjectPlaceholder: PlaceholderOptionsEnum;
    contentPlaceholder: PlaceholderOptionsEnum;
    contentCursorPoint;
    temporaryMessageContent = '';
    linkText = '';
    options = {minimumResultsForSearch: Infinity};
    showLoader = false;
    editMode = false;
    isGlobalHT = false;

    constructor(
        private router: Router,
        private activatedRoute: ActivatedRoute,
        private utilsService: UtilsService,
        private saveService: SaveService,
        private appService: AppService,
        private adminPortalLayoutService: AdminPortalLayoutService,
        public ngZone: NgZone
    ) {
        super(utilsService);
    }

    ngOnInit(): void {
        window.scrollTo(0, 0);
        this.createdObjs = {};
        this.updatedObjs = {};
        this.deletedObjs = {};
        this.showLoader = true;

        this.utilsService.resetCounter();
        this.getPlaceholderOptions();

        this.subscriptions.push(this.activatedRoute.params
            .subscribe(
                (params: Params) => {
                    if ((params.global && params.global === 'global')) {
                        this.isGlobalHT = true;
                    }
                }
            ));

        if (this.adminPortalLayoutService.userData || this.isGlobalHT) {
            this.initComponent();
        } else {
            this.subscriptions.push(this.adminPortalLayoutService.userDataUpdated.first()
                .subscribe(
                    () => {
                        this.initComponent();
                    }
                ));
        }
    }

    initComponent(): void {
        this.subscriptions.push(this.appService.getMessageTemplateTypeEnum()
            .subscribe(
                data => {
                    this.messageTemplateTypes = data;

                    this.subscriptions.push(this.activatedRoute.params
                        .subscribe(
                            (params: Params) => {

                                /**
                                 * First condition identifies if the template is being created from workflow template
                                 */
                                if (this.templateCreationFromWorkflow()) {

                                    if(!this.isGlobalHT) {
                                        this.messageTemplate.HiringTeam = this.adminPortalLayoutService.getHiringTeamID().ObjectID;
                                    }

                                    if (this.messageTemplateTypes) {
                                        this.messageTemplate.TemplateType = this.messageTemplateTypes[0];
                                    }

                                    this.utilsService.createObject(this.messageTemplate, this.createdObjs);
                                    this.setInputListener();

                                    this.showLoader = false;
                                    /**
                                     * Second condition identifies if the template is being updated from workflow template
                                     */
                                } else if (this.templateUpdateFromWorkflow() || (params.id && params.id !== '0')) {
                                    this.editMode = true;

                                    this.getMessageTemplateByID(this.templateUpdateFromWorkflow() ? this.objectID : params.id);
                                } else {
                                    /**
                                     * Third condition identifies if the template is being created within this component
                                     */
                                    this.messageTemplate.HiringTeam = !this.isGlobalHT ? this.adminPortalLayoutService.getHiringTeamID().ObjectID : null;

                                    if (this.messageTemplateTypes) {
                                        this.messageTemplate.TemplateType = this.messageTemplateTypes[0];
                                    }

                                    this.utilsService.createObject(this.messageTemplate, this.createdObjs);
                                    this.setInputListener();

                                    this.showLoader = false;
                                }

                            }
                        ));
                },
                error => {
                    this.utilsService.handleError(error);
                }
            )
        );
    }

    /**
     * Save button is visible only if selected template is created by the selected hiring team or
     * if the template is in edit mode
     */
    showSaveBtn(): boolean {

        if(this.templateCreationFromWorkflow()) {
            return true;
        }
        
        if(this.templateUpdateFromWorkflow()) {
            return false;
        }

        if(this.isGlobalHT) {
            return true;
        }

        if (!!this.messageTemplate && !!this.messageTemplate.ObjectID) {
            return this.messageTemplate.HiringTeam === this.adminPortalLayoutService.getHiringTeamID().ObjectID ?
                (this.templateCreationFromWorkflow() ? true : !this.templateUpdateFromWorkflow()) : false;
        }
    }

    showSaveIntoAllTemplates(): boolean {

        if(this.isGlobalHT && this.templateUpdateFromWorkflow()) {
            return true;
        }

        if (this.templateCreationFromWorkflow()) {
            return false;
        }

        return !this.isGlobalHT && !!this.messageTemplate && !!this.messageTemplate.ObjectID &&
            (this.messageTemplate.HiringTeam === this.adminPortalLayoutService.getHiringTeamID().ObjectID && !!this.objectID
                && this.editMode);
    }

    showSaveCopyBtn(): boolean {
        if(this.isGlobalHT && this.templateUpdateFromWorkflow()) {
            return true;
        }
        
        if (!this.isGlobalHT && this.messageTemplate && this.messageTemplate.ObjectID) {
            return this.messageTemplate.HiringTeam === null;
        }

        return false;
    }

    /**
     * This function sets two types of input listeners, upon click and upon writing anything in the field.
     * Whenever the event is triggered, it stores the current cursor position of that specific field.
     */
    setInputListener(): void {
        let editElement;
        setTimeout(() => {

            if (this.emailTemplateType()) {
                editElement = this.messageContentEditor.getQuill().container;

                if (editElement) {
                    const editor = editElement.getElementsByClassName('ql-editor');

                    if (editor[0]) {
                        editor[0].classList.add('form-control');
                        editor[0].classList.add('editor');
                    }

                    ['keyup', 'click'].forEach(event => {
                        editElement.addEventListener(event, () => {
                            this.contentCursorPoint = this.messageContentEditor.getQuill()
                                .getSelection().index;
                        });
                    });
                }

            } else {
                editElement = document.getElementById('messageContentTxtAreaId');

                if (editElement) {
                    ['keyup', 'click'].forEach(event => {
                        editElement.addEventListener(event, () => {
                            this.contentCursorPoint = this.getCursorPos(editElement);
                        });
                    });
                }

            }

        }, 0);
    }

    /**
     * In Email template type, user may add anchor tag in editor.
     * This function gets the Quill view child and inserts or updates its content as per placeholder selected.
     */
    addAnchorText(show: boolean): void {

        if (!show || this.linkText === '') {
            this.contentLinkModal.hide();

            return;
        }

        const delta = {
            ops: [
                {retain: this.contentCursorPoint > 0 ? this.contentCursorPoint : this.contentCursorPoint + 1},
                {insert: `\${Placeholder:${this.contentPlaceholder.Placeholder}}`, attributes: {link: this.linkText}}
            ]
        };

        if (this.contentCursorPoint === 0) {
            this.messageContentEditor.getQuill()
                .insertText(this.contentCursorPoint, ' ');
            this.contentCursorPoint++;
        }

        try {
            this.messageContentEditor.getQuill()
                .updateContents(delta);
        } catch (e) {
            this.utilsService.handleError(e);
        }

        this.linkText = '';
        this.contentLinkModal.hide();
    }

    /**
     * When content of editor is updated using placeholder, it doesn't reflect value in the ngModel
     * This function is called only once before saving the template to re-assign value of content in ngModel.
     */
    assignContent(): void {
        if (this.emailTemplateType()) {
            const editor = this.messageContentEditor.getQuill().container;
            if (editor) {
                const editElement = editor.getElementsByClassName('ql-editor')[0];
                this.messageTemplate.MessageContent = editElement.innerHTML;
            }
        }
    }

    addPlaceholderInMessageContent($event): void {

        if (!$event) {
            return;
        }

        this.contentPlaceholder = $event;

        if (!this.contentPlaceholder || !this.contentPlaceholder.Value || this.contentPlaceholder.Value === 'null') {
            return;
        }

        if (typeof this.contentCursorPoint !== 'number') {
            return;
        }

        if (this.emailTemplateType()) {
            if (this.contentPlaceholder.IsLink) {
                const event = new Event('build');
                this.contentLinkModal.toggle(event, this.messageContentEditor.getQuill());
            } else {
                this.messageContentEditor.getQuill()
                    .insertText(this.contentCursorPoint, `\${Placeholder:${this.contentPlaceholder.Placeholder}}`);
            }
        } else {
            const textarea: HTMLTextAreaElement = document.getElementById('messageContentTxtAreaId') as HTMLTextAreaElement;

            this.setValueAndFocus(textarea, 'messageContentTxtArea', `\${Placeholder:${this.contentPlaceholder.Placeholder}}`,
                'MessageContent');
        }

        this.resetSelect('contentPlaceholderOptions');
    }

    /**
     * When a template is switched from Email to SMS type, plain text is shown in the textarea instead of rich HTML.
     */
    showPlainText(HTMLTitle: string): string {
        const temp = document.getElementById('showPlainText');
        temp.innerHTML = HTMLTitle;
        const title = temp.innerText.trim();
        temp.innerHTML = '';

        return title;
    }

    /**
     * User may revert back to EMAIL from SMS, in this case, rich HTML content is preserved in a variable whenever
     * SMS type is changed to EMAIL
     */
    storeMessageContent($event): void {

        if (!$event) {
            return;
        }

        this.messageTemplate.TemplateType = $event;

        if (this.messageTemplate.MessageContent !== undefined) {
            if (this.smsTemplateType()) {
                this.temporaryMessageContent = this.messageTemplate.MessageContent;
                this.messageTemplate.MessageContent = this.showPlainText(this.temporaryMessageContent);
            } else {
                this.messageTemplate.MessageContent = this.temporaryMessageContent !== '' ? this.temporaryMessageContent
                    : this.messageTemplate.MessageContent;
            }
        }

        if (this.ContentPlaceholderOptionsEnum) {
            if (this.emailTemplateType()) {
                this.contentPlaceholderOptions = this.ContentPlaceholderOptionsEnum.filter(option => option.ShowForContent ||
                    option.Value === 'null');
            } else {
                this.contentPlaceholderOptions = this.ContentPlaceholderOptionsEnum
                    .filter(option => option.ShowForContent && !option.IsLink || option.Value === 'null');
            }
        }

        this.setInputListener();
    }

    addPlaceholderInSubject($event): void {
        this.subjectPlaceholder = $event;
        if (this.emailTemplateType() && this.subjectPlaceholder && this.subjectPlaceholder.Value) {
            const input: HTMLInputElement = document.getElementById('subjectInputId') as HTMLInputElement;
            this.setValueAndFocus(input, 'subjectInput', `\${Placeholder:${this.subjectPlaceholder.Placeholder}}`, 'Subject');
        }
        this.resetSelect('subjectPlaceholderOptions');
    }

    resetSelect(key: string): void {
        const temp = this[key];
        this[key] = [];
        setTimeout(() => (this[key] = temp), 0);
    }

    getCursorPos(input): number {

        if ('selectionStart' in input && document.activeElement === input) {
            return input.selectionStart;
        }

        return -1;
    }

    getMessageTemplateByID(id): void {
        this.showLoader = true;
        this.createdObjs = {};
        this.updatedObjs = {};
        this.deletedObjs = {};

        this.utilsService.resetCounter();
        this.utilsService.clearErrorMessages();

        this.subscriptions.push(this.appService.getMessageTemplateByID(id, [])
            .subscribe(
                data => {
                    this.messageTemplate = data;
                    this.updatedObjs[this.messageTemplate.ObjectID] = this.messageTemplate;
                    this.showLoader = false;
                    // Significance of setTimeout is to call the function at the end of browser stack
                    // in order to make sure that UI has been updated prior to calling its view-child
                    setTimeout(() => this.setInputListener(), 0);
                },
                error => {
                    this.showLoader = false;
                    this.utilsService.handleError(error);
                }
            )
        );
    }

    // If new message template is being created from 'EditWorkFlowComponent'
    templateCreationFromWorkflow(): boolean {
        return this.objectID && this.objectID.indexOf('NEW') !== -1;
    }

    // If a message template is being updated from 'EditWorkFlowComponent'
    templateUpdateFromWorkflow(): boolean {
        return this.objectID && this.objectID.indexOf('NEW') === -1;
    }

    cancelClicked(): void {
        // If new message template is being created from 'EditWorkFlowComponent', don't show listing.
        if (this.templateCreationFromWorkflow() || this.templateUpdateFromWorkflow()) {
            this.closeModal.emit(-1);
        } else {
            this.router.navigate([this.isGlobalHT ? '/list-message-templates/global' : '/admin/list-message-templates']);
        }
    }

    saveMessageTemplate(saveCopy = false): void {
        this.assignContent();
        this.utilsService.clearErrorMessages();
        const service = `svc/${saveCopy ? SERVICES.SAVE_MESSAGE_AS_COPY : SERVICES.SAVE}`;

        if (this.form.invalid) {
            this.utilsService.showAllErrorMessages();
        } else {
            this.showLoader = true;
            this.subscriptions.push(this.saveService.saveObjects(service, this.createdObjs, this.updatedObjs, this.deletedObjs)
                .subscribe(
                    data => {
                        this.utilsService.handleSuccess();
                        if (saveCopy && this.templateUpdateFromWorkflow()) {
                            if (data.created.CLONED) {
                                this.closeModal.emit(data.created.CLONED);
                            }
                        } else if (this.templateCreationFromWorkflow()) {
                            let id = this.messageTemplate.ObjectID;

                            if (data.created[id]) {
                                id = data.created[id];
                            }
                            // emitting value to component, in this case 'Edit-Workflow-Template'
                            this.closeModal.emit(id);
                        } else if (this.templateUpdateFromWorkflow()) {
                            this.closeModal.emit(this.messageTemplate.ObjectID);
                        } else {
                            this.router.navigate([this.isGlobalHT ? '/list-message-templates/global' : '/admin/list-message-templates']);
                        }
                    },
                    error => {
                        this.showLoader = false;
                        this.utilsService.handleError(error);
                    }
                )
            );
        }
    }

    getPlaceholderOptions(): void {
        this.subscriptions.push(this.appService.getPlaceholderOptionsEnum()
            .subscribe(options => {
                this.ContentPlaceholderOptionsEnum = options;
                // Changed null value to 'null' in order to use it in select-2 component which takes value as a string
                this.ContentPlaceholderOptionsEnum.filter(option => option.Value === null)
                    .map(val => {
                        val.Value = 'null';

                        return val;
                    });
                this.contentPlaceholderOptions =
                    this.ContentPlaceholderOptionsEnum.filter(option => option.ShowForContent || option.Value === 'null');
                this.subjectPlaceholderOptions =
                    this.ContentPlaceholderOptionsEnum.filter(option => option.ShowForSubject || option.Value === 'null');
            })
        );
    }

    emailTemplateType(): boolean {
        return this.messageTemplate && this.messageTemplate.TemplateType ?
            this.messageTemplate.TemplateType.Value === 'EMAIL' :
            false;
    }

    smsTemplateType(): boolean {
        return this.messageTemplate && this.messageTemplate.TemplateType ?
            this.messageTemplate.TemplateType.Value === 'SMS' :
            false;
    }

    setValueAndFocus(element, elementId, placeholder, modelKey): void {
        const start = element.selectionStart;
        const end = element.selectionEnd;
        this.messageTemplate[modelKey] = `${element.value.substring(0, start)}${placeholder}${element.value.substring(end)}`;

        this.focusField(elementId);

        setTimeout(() => {
            element.selectionStart = element.selectionEnd = end + placeholder.length;
        }, 0);
    }

    focusField(elementId: string): void {
        setTimeout(() => {
            try {
                document.getElementById(`${elementId}Id`)
                    .focus();
                document.getElementById(`${elementId}Id`)
                    .getElementsByTagName('input')[0]
                    .focus();
            } catch (e) {
                // ignore this.
            }
        }, 0);
    }

// tslint:disable-next-line:max-file-line-count
}
