import { AfterViewInit, Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { DetailsFormBase } from '@objects-view/details-form-base';
import { ITicketModel } from '@fleio-api/plugins/tickets/model/ticket.model';
import { AbstractControl, UntypedFormBuilder, Validators } from '@angular/forms';
import { ITicketCreateOptionsModel } from '@fleio-api/plugins/tickets/model/ticket-create-options.model';
import { ActivatedRoute, Router } from '@angular/router';
import { forkJoin, of } from 'rxjs';
import { TicketDepartmentsApiService } from '@fleio-api/plugins/tickets/ticket-departments-api.service';
import { ClientsApiService } from '@fleio-api/client-user/client/clients-api.service';
import { ConfigService } from '@shared/config/config.service';
import { TicketsApiService } from '@fleio-api/plugins/tickets/tickets-api.service';
import { UploadInterfaceComponent } from '@shared/ui/upload-interface/upload-interface.component';
import { HttpResponse } from '@angular/common/http';
import { ITicketAttachmentModel } from '@fleio-api/plugins/tickets/model/ticket-attachment.model';
import { TicketAttachmentsApiService } from '@fleio-api/plugins/tickets/ticket-attachments-api.service';
import { AppLocalStorageService } from '@shared/ui-api/app-local-storage.service';
import { ServicesApiService } from '@fleio-api/billing/services/service-api.service';
import { ValidatorsHelper } from '@shared/ui-api/helpers/validators-helper';
import { ThemingService } from '@shared/ui/theming/theming.service';
import { EditorComponent } from '@tinymce/tinymce-angular';
import { TinyMCEAttachments, TinymceHelper } from '@shared/ui-api/helpers/tinymce-helper';
import { IUserModel } from '@fleio-api/client-user/model/user.model';
import { UsersApiService } from '@fleio-api/client-user/user/users-api.service';
import { COMMA, ENTER, SEMICOLON, SPACE } from '@angular/cdk/keycodes';
import { NotificationService } from '@shared/ui-api/notification.service';
import { AutocompleteHelper } from '@shared/ui-api/helpers/autocomplete-helper';

let TINYMCE_ATTACHMENTS: TinyMCEAttachments;

@Component({
  selector: 'app-tickets-open-new-tab',
  templateUrl: './tickets-open-new-tab.component.html',
  styleUrls: ['./tickets-open-new-tab.component.scss']
})
export class TicketsOpenNewTabComponent extends DetailsFormBase<ITicketModel>
  implements OnInit, OnDestroy, AfterViewInit {

  @ViewChild('uploadInterface') uploadInterface: UploadInterfaceComponent;
  @ViewChild('tinyMceArea') tinyMceArea: EditorComponent;
  @ViewChild('ccChipInput') ccChipInput: ElementRef;
  tinyMceHelper = new TinymceHelper();
  openTicketForm = this.formBuilder.group({
    title: ['', Validators.required],
    department: ['', [Validators.required, ValidatorsHelper.requiredObjectValidator]],
    cc_recipients: [''],
    cc_recipients_input: [''],
    client: [''],
    description: [''],
    service: [''],
  });

  createOptions: ITicketCreateOptionsModel;
  ccRecipients = this.openTicketForm.controls.cc_recipients;
  tinyMCEOptions = null;
  toRecipients = [];
  separatorKeysCodes: number[] = [ENTER, COMMA, SEMICOLON, SPACE];
  serviceSelectedPlaceholder = $localize`Related service`;
  serviceUnselectedPlaceholder = $localize`Select related service ...`;
  departmentSelectedPlaceholder = $localize`Department`;
  departmentUnselectedPlaceholder = $localize`Select department ...`;

  constructor(private formBuilder: UntypedFormBuilder, private activatedRoute: ActivatedRoute,
              private ticketsApiService: TicketsApiService, private router: Router,
              public ticketDepartmentsApiService: TicketDepartmentsApiService,
              private clientsApiService: ClientsApiService,
              public servicesApiService: ServicesApiService,
              private config: ConfigService,
              private ticketAttachmentsApiService: TicketAttachmentsApiService,
              private appLocalStorageService: AppLocalStorageService,
              private themingService: ThemingService,
              private usersApiService: UsersApiService,
              private notificationService: NotificationService,) {
    super();
    TINYMCE_ATTACHMENTS = new TinyMCEAttachments(this.ticketAttachmentsApiService);
  }

  selectedClient(client) {
    this.getRecipientsForClientID(client.id);
  }

  getRecipientsForClientID(clientID) {
    this.ticketsApiService.getClientRecipients(clientID).subscribe((users: Array<IUserModel>) => {
      if (users && users.length) {
        this.toRecipients = users;
      }
    });
  }

  getRecipientDisplay(recipient) {
    if (typeof recipient === 'string') {
      return recipient;
    } else {
      if (recipient.full_name) {
        return $localize`${recipient.full_name} (${recipient.email})`;
      } else {
        return recipient.email;
      }
    }
  }

  private addRecipient(recipient, formControl: AbstractControl) {
    const recipients = formControl.value as Array<string>;
    if (recipients) {
      recipients.push(recipient);
      formControl.setValue(recipients);
    } else {
      formControl.setValue([recipient]);
    }
  }

  addRecipientOnFocusOut(chipInput, recipients) {
    const inputValue = chipInput.value;
    if (inputValue && inputValue.includes('@')) {
      if (this.findToRecipient(inputValue)) {
        // do not auto add CC email if already found in To recipients
        return;
      }
      this.addRecipient(inputValue, recipients);
      chipInput.value = '';
    }
  }

  removeRecipient(recipientToRemove, formControl: AbstractControl) {
    let recipients = formControl.value as Array<string>;
    recipients = recipients.filter(recipient => recipient !== recipientToRemove);
    formControl.setValue(recipients);
    AutocompleteHelper.refreshAutocompleteOptions(this.openTicketForm.controls.cc_recipients_input);
  }

  private findToRecipient(recipientValue: string) {
    if (this.toRecipients && this.toRecipients.length) {
      return this.toRecipients.find(recipient => {
        if (typeof recipient === 'string') {
          return recipient === recipientValue;
        } else {
          return recipient.email === recipientValue;
        }
      });
    } else {
      return null;
    }
  }

  findCCRecipient(recipientValue) {
    if (this.ccRecipients.value && Array.isArray(this.ccRecipients.value)) {
      return this.ccRecipients.value.find(recipient => {
        if (typeof recipient === 'string') {
          return recipient === recipientValue;
        } else {
          return recipient.email === recipientValue;
        }
      });
    } else {
      return null;
    }
  }

  addCustomCCRecipient(event) {
    const recipientValue = event.value as string;
    if (!recipientValue.includes('@')) {
      // list will be better validated on backend
      this.notificationService.showMessage($localize`Recipients should be email addresses!`);
    } else if (this.findToRecipient(recipientValue)) {
      this.notificationService.showMessage($localize`Recipient ${recipientValue} is already automatically emailed!`);
    } else if (this.findCCRecipient(recipientValue)) {
      this.notificationService.showMessage($localize`Recipient already in "CC" field!`);
    } else {
      this.addRecipient(recipientValue, this.ccRecipients);
      if (event.chipInput) {
        event.chipInput.clear();
      }
      this.openTicketForm.controls.cc_recipients_input.setValue('');
    }
  }

  openTicket() {
    const value = this.openTicketForm.value;
    const fileInputs = this.uploadInterface.getFileInputs();
    const allFiles = [];
    for (const fileInput of fileInputs) {
      if (fileInput.nativeElement.files.length) {
        // on ticket reply, for one input there is at most one file
        allFiles.push(fileInput.nativeElement.files[0]);
      }
    }
    if (allFiles.length) {
      let fd: FormData;
      const queriesList = [];
      for (const file of allFiles) {
        fd = new FormData();
        fd.append('data', file);
        fd.append('file_name', file.name);
        queriesList.push(this.ticketAttachmentsApiService.createWithUpload(fd));
      }
      forkJoin(queriesList).subscribe({
        next: responses => {
          let attachmentIDs = '';
          responses.forEach((queryResponse: HttpResponse<ITicketAttachmentModel>, index) => {
            attachmentIDs += queryResponse.body.id;
            if (index < responses.length - 1) {
              attachmentIDs += ',';
            }
          });
          this.tinyMceArea.editor.uploadImages().then(() => {
            this.addTicket(value, attachmentIDs, true);
          });
          return of(null);
        }, error: error => {
          if (error?.error?.detail) {
            this.notificationService.showMessage(error.error.detail);
          }
          this.objectController.loading = false;
        }
      });
      return of(null);
    } else {
      this.tinyMceArea.editor.uploadImages().then(() => {
        this.addTicket(value, '');
      });
      return of(null);
    }
  }

  private parseRecipients(recipients: Array<any>, joinEmails = false) {
    const parsedRecipients = [];
    recipients.forEach(recipient => {
      if (typeof recipient === 'string') {
        parsedRecipients.push(recipient);
      } else {
        parsedRecipients.push(recipient.email);
      }
    });
    if (parsedRecipients.length) {
      if (joinEmails) {
        return parsedRecipients.join(',');
      } else {
        return JSON.stringify(parsedRecipients);
      }
    } else {
      return null;
    }
  }

  addTicket(value, associatedAttachmentsIds: string, resetFileInputs = false) {
    associatedAttachmentsIds = TINYMCE_ATTACHMENTS.appendAttachments(associatedAttachmentsIds);
    value.description = this.tinyMceArea.editor.getContent();
    if (value.department) {
      value.department = value.department.id;
    }
    if (value.client) {
      value.client = value.client.id;
    }
    if (value.service) {
      value.service = value.service.id;
    }
    if (value.cc_recipients) {
      // parse "CC" recipients before submitting
      value.cc_recipients = this.parseRecipients(value.cc_recipients, true);
    }
    if (associatedAttachmentsIds) {
      value.associated_attachment_ids = associatedAttachmentsIds;
    }
    this.createOrUpdate(this.ticketsApiService, value).subscribe((response: any) => {
      if (resetFileInputs) {
        this.uploadInterface.resetFileInputs();
      }
      this.appLocalStorageService.setTicketOpenData(null);
      this.router.navigateByUrl(
        this.config.getPanelUrl(`tickets/${response.id}`)
      ).catch(() => {
      });
    });
  }

  tinymceUploadHandler(blobInfo, success, failure, progress) {
    const attachmentIdentifier = `${blobInfo.id()}${new Date().getTime()}`;
    const fd = new FormData();
    fd.append('data', blobInfo.blob());
    fd.append('file_name', blobInfo.filename());
    fd.append('custom_id', attachmentIdentifier);
    return TINYMCE_ATTACHMENTS.attachmentsApiService.createWithUpload(fd).toPromise().then((resp) => {
      if (resp?.body?.id) {
        TINYMCE_ATTACHMENTS.attachmentsIDs.push(resp.body.id);
        TINYMCE_ATTACHMENTS.blobsToReplace[blobInfo.blobUri()] = attachmentIdentifier;
        return `cid:${attachmentIdentifier}`;
      }
    });
  }

  ngOnInit(): void {
    super.ngOnInit();
    this.createOptions = this.activatedRoute.snapshot.data.createOptions;
    if (this.objectController) {
      this.objectController.actionCallback = () => this.openTicket();
    }
    if (this.config.current) {
      this.tinyMCEOptions = this.themingService.getTinyMceOptions(this.tinymceUploadHandler);
    }
    this.openTicketForm.valueChanges.subscribe(
      ticketForm => {
        this.appLocalStorageService.setTicketOpenData(ticketForm);
      }
    );
    const temporarySavedCreateForm = this.appLocalStorageService.getTicketOpenData();
    if (temporarySavedCreateForm) {
      this.openTicketForm.patchValue(temporarySavedCreateForm);
      if (temporarySavedCreateForm.cc_recipients_input) {
        this.openTicketForm.controls.cc_recipients_input.setValue('');
      }
      if (this.openTicketForm.controls.client.value?.id) {
        this.getRecipientsForClientID(this.openTicketForm.controls.client.value.id);
      }
      if (temporarySavedCreateForm?.department?.id) {
        this.ticketDepartmentsApiService.get(
          temporarySavedCreateForm.department.id, {}, true
        ).subscribe({
          error: error => {
            if (error?.status === 404) {
              this.openTicketForm.controls.department.setValue('');
            }
          }
        });
      }
    }
    if (!this.openTicketForm.controls.description.value) {
      if (this.createOptions && this.createOptions.user_signature) {
        this.openTicketForm.controls.description.setValue('<br>' + this.createOptions.user_signature);
      }
    }

    this.activatedRoute.params.subscribe(value => {
      if (value && value.forclient) {
        this.clientsApiService.get(value.forclient).subscribe(response => {
          this.openTicketForm.controls.client.setValue(response);
        });
      }
    });

    this.openTicketForm.controls.client.valueChanges.subscribe(value => {
      if (value && value.id) {
        this.selectedClient(value);
      }
    });

  }

  ngAfterViewInit() {
    super.ngAfterViewInit();
    this.tinyMceHelper.manageUndo(this.openTicketForm.controls.description, this.tinyMceArea);
  }

  handleTinyKeyDown(event) {
    if (event && event.event && event.event.ctrlKey && event.event.keyCode === 13) {
      event.event.preventDefault();
      this.openTicket();
    }
  }

  ngOnDestroy() {
    super.ngOnDestroy();
    this.tinyMceHelper.removeSubscriptionForUndo();
  }

}
