import { Location } from '@angular/common';
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { MenuItem } from 'primeng/api';
import { Editor } from 'primeng/editor';
import { FileUpload } from 'primeng/fileupload';
import { Subscription } from 'rxjs/Subscription';
import { environment } from '../../../environments/environment';
import { AppService } from '../../app.service';
import { ASSOCS } from '../../constants';
import { ChatAttachmentModel } from '../../models/chat-attachment.model';
import { JobApplicationModel } from '../../models/job-application.model';
import { MessageModel } from '../../models/message.model';
import { SentViaEnum } from '../../models/sent-via.enum';
import { SaveService } from '../../oneit/services/save.service';
import { UtilsService } from '../../oneit/services/utils.service';
import { AdminPortalLayoutService } from '../admin-portal/admin-portal-layout/admin-portal-layout.service';
import { BaseComponent } from '../admin-portal/base/base.component';
import { ApplicantPortalLayoutService } from '../applicant-portal/applicant-portal-layout/applicant-portal-layout.service';
import { MessageEngineService } from './message-engine.service';


@Component({
    selector: 'app-message-engine',
    templateUrl: './message-engine.component.html',
    styleUrls: ['./message-engine.component.scss']
})
export class MessageEngineComponent extends BaseComponent implements OnInit {

    @Input() embedded = false;
    @Input() jobApplicationID = null;
    // tslint:disable-next-line:prefer-output-readonly
    @Output() minimize: EventEmitter<any> = new EventEmitter<any>();
    @ViewChild('message') messageEditor: Editor;
    @ViewChild('form') form: NgForm;
    @ViewChild('uploader') uploader: FileUpload;
    sentViaMenuItems: Array<MenuItem>;
    createdObjs = {};
    updatedObjs = {};
    deletedObjs = {};

    jobApplication = new JobApplicationModel();
    subscriptions: Array<Subscription> = [];
    sentViaEnum: Array<SentViaEnum> = [];
    Message = new MessageModel();
    apiUrl = environment.baseUrl;
    loggedInId = null;
    showLoader = false;
    heading = '...';
    markedAsRead: boolean = false;

    constructor(
        private utilsService: UtilsService,
        private saveService: SaveService,
        private appService: AppService,
        private messageEngineService: MessageEngineService,
        private adminPortalLayoutService: AdminPortalLayoutService,
        private applicantPortalLayoutService: ApplicantPortalLayoutService,
        private location: Location
    ) {
        super(utilsService);
    }

    goBack(): void {
        const url = `${environment.baseUrl}ApplicantPortal-JobApplication.htm?cms.rm=Page&JobID=${this.utilsService.getId(this.jobApplication.Job.ObjectID)}`;
        if (window.history.length > 2) {
            const cur_path = this.location.path();
            this.location.back();
            if (cur_path === this.location.path()) {
                window.location.href = url;
            }
        } else {
            window.location.href = url;
        }
    }

    ngOnInit(): void {

        this.getSentViaOptions();
        // For Hiring Team or Applicant
        const service = this.embedded ? this.adminPortalLayoutService : this.applicantPortalLayoutService;
        if (service.userData) {
            this.initComponent(service);
        } else {
            this.subscriptions.push(service.userDataUpdated.first()
                .subscribe(() => {
                    this.initComponent(service);
                }));
        }
    }

    getSentViaOptions(): void {
        this.subscriptions.push(
            this.appService.getTypes('SentVia')
                .subscribe((data: Array<SentViaEnum>) => {
                    this.sentViaEnum = data;
                    this.sentViaMenuItems = this.sentViaEnum.map(elem =>
                        ({
                            label: elem.Description,
                            command: () => {
                                this.Message.SentVia = elem;
                                this.saveEngineApplicantView();
                            }
                        }));

                })
        );
    }

    initComponent(service: AdminPortalLayoutService | ApplicantPortalLayoutService): void {
        if (service instanceof AdminPortalLayoutService) {
            this.loggedInId = service.userData.CompanyUser.User;
            // jobId should come from @Input (Admin Portal)
        } else {
            this.jobApplicationID = service.jobApplicationID;
            this.loggedInId = service.userData.UserID;
        }

        if (this.jobApplicationID) {
            this.getJobApplicationByID();
        } else {
            // Should never come to this block
            console.error('JobId not found.');
        }
    }

    getJobApplicationByID(): void {
        this.showLoader = true;
        this.createdObjs = {};

        const assocs = [
            ASSOCS.JOB,
            ASSOCS.MESSAGES,
            [ASSOCS.MESSAGES, ASSOCS.SENT_BY].join('.'),
            [ASSOCS.MESSAGES, ASSOCS.ATTACHMENTS].join('.'),
            [ASSOCS.CANDIDATE, ASSOCS.USER].join('.')];

        this.subscriptions.push(this.messageEngineService.getJobApplicationByID(this.jobApplicationID, assocs)
            .subscribe(
                data => {
                    this.jobApplication = data;
                    this.heading = this.embedded ? this.jobApplication.Candidate.User.Name :
                        this.applicantPortalLayoutService.userData.PageTitle;
                    this.jobApplication.Messages = this.jobApplication.Messages || [];
                    this.utilsService.sort(this.jobApplication.Messages, ['ObjectCreated'], [1]);

                    this.jobApplication.Messages.forEach(msg => {
                        msg.ObjectCreated = new Date(msg.ObjectCreated);
                    });

                    this.createMessage();

                    this.showLoader = false;
                    setTimeout(() => {
                        const msgWrapper = document.getElementsByClassName('messages-wrapper')[0];
                        msgWrapper.scrollTop = msgWrapper.scrollHeight;
                    }, 0);
                },
                error => {
                    this.showLoader = false;
                    this.utilsService.handleError(error);
                }
            )
        );
    }

    /**
     * This function sets isRead property of all messages of this job application to true
     */
    markAsRead(): void {
        this.showLoader = true;
        const params = {
            JobApplication: this.jobApplication.ObjectID
        };
        this.utilsService.processObjects('MarkAsRead', params)
            .subscribe(
                () => {
                    this.showLoader = false;
                    this.markedAsRead = true;
                },
                err => {
                    this.utilsService.handleError(err);
                    this.showLoader = false;
                }
            );
    }

    minimizeWindow(): void {
        let response = {
            "JobAppID" : this.utilsService.getId(this.jobApplication.ObjectID),
            "MarkedAsRead" : this.markedAsRead
        }
        this.minimize.emit(response);
    }

    saveEngineApplicantView(): void {
        if (this.showLoader) {
            return;
        }

        if (!this.Message.SentVia) {
            this.Message.SentVia = this.sentViaEnum[2] ? this.sentViaEnum[2] : this.sentViaEnum[0];
        }

        this.showLoader = true;
        const service = this.embedded ? 'svc/Send' : 'svc/Save';
        this.subscriptions.push(this.saveService.saveObjects(service, this.createdObjs,
            this.updatedObjs, this.deletedObjs)
            .subscribe(
                () => {
                    this.showLoader = false;
                    this.getJobApplicationByID();
                },
                error => {
                    this.showLoader = false;
                    this.utilsService.handleError(error);
                }
            )
        );
    }

    /**
     * Creates a new object of ChatAttachment and assigns the FileToken and Name to it.
     * Moreover, pushes it to the current Message's Attachments Array
     * @param event Browser Event
     */
    onUpload(event: any): void {
        const chatAttachment = new ChatAttachmentModel();
        chatAttachment.File = {
            FileToken: JSON.parse(event.xhr.response).files[0].token,
            Name: JSON.parse(event.xhr.response).files[0].fileName,
            Index: this.Message.Attachments.length
        };
        this.utilsService.addMultiRefObject(chatAttachment, this.Message, 'Attachments', this.createdObjs);
    }

    removeAttachment(file): void {
        this.utilsService.removeMultiRefObject(file, this.Message, 'Attachments', this.createdObjs,
            this.updatedObjs, this.deletedObjs);
    }

    /**
     * It simply creates a new object and assigns the default values to it.
     */
    createMessage(): void {
        this.Message = new MessageModel();
        this.Message.SentBy = this.loggedInId;
        this.Message.Attachments = [];
        this.Message.JobApplication = this.jobApplication;
        this.utilsService.createObject(this.Message, this.createdObjs);
    }

    /**
     * Helper functions
     */

    triggerUpload(): void {
        // @ts-ignore
        this.uploader.el.nativeElement.getElementsByTagName('input')[0]
            .click();
    }

    sendCriteria(): boolean {
        if (this.showLoader || !this.Message.Attachments) {
            return true;
        }

        return (this.Message.MessageContent === '' || !this.Message.MessageContent) && !this.Message.Attachments.length;
    }
}
