import {
  AnalyticalScope,
  Behavior,
  Form,
  NotNull,
  ObjectRef,
  TextField,
  Visible
} from "@webbpm/base-package";
import {HttpClient} from "@angular/common/http";
import {FormField} from "../field/FormField";
import {AuthorizationService} from "../../../modules/app/service/authorization.service";
import {ApplicationKind} from "../enum/ApplicationKind";
import {ProcessKey} from "../enum/ProcessKey";
import {ProcessResponse} from "./response/ProcessResponse";
import {UserApplicationListRpcService} from "../../../generated/ru/micord/ervu/account_applications/component/rpc/UserApplicationListRpcService";
import {Account} from "./dto/Account";
import {Person} from "./dto/Person";
import {Roles} from "./dto/Roles";
import {CreateAccountData} from "./dto/create/CreateAccountData";
import {Role} from "./dto/Role";
import {EditPersonData} from "./dto/edit/EditPersonData";
import {EditAccountData} from "./dto/edit/EditAccountData";
import {EditRolesAccount} from "./dto/edit/EditRolesAccount";
import {EditRolesData} from "./dto/edit/EditRolesData";
import {ResetPasswordAccount} from "./dto/password/ResetPasswordAccount";
import {ResetPasswordData} from "./dto/password/ResetPasswordData";
import {ProcessRequest} from "./dto/ProcessRequest";
import {StatusUpdateService} from "../../../modules/app/service/status-update.service";
import {BlockedRegion} from "../../../generated/ru/micord/ervu/account_applications/enums/BlockedRegion";
import {ErvuPermission} from "../../../modules/app/enum/ErvuPermission";
import {BlockingData} from "./dto/blocking/BlockingData";
import {UnblockingData} from "./dto/blocking/UnblockingData";
import {AccountDetails} from "./dto/blocking/AccountDetails";
import {PersonDetails} from "./dto/blocking/PersonDetails";

@AnalyticalScope(Form)
export class UserManagementService extends Behavior {

  private static PROCESS_START_PATH = '/service/wf/service/start';

  @NotNull()
  @ObjectRef()
  public applicationKind: TextField;

  private form: Form;
  private httpClient: HttpClient;
  private sendToErvu: boolean = false;
  private rpc: UserApplicationListRpcService;
  private authService: AuthorizationService;
  private statusUpdateService: StatusUpdateService;
  private formJson: any;

  initialize() {
    super.initialize();
    this.form = this.getScript(Form);
    this.httpClient = this.injector.get(HttpClient);
    this.rpc = this.getScript(UserApplicationListRpcService);
    this.authService = this.injector.get(AuthorizationService);
    this.statusUpdateService = this.injector.get(StatusUpdateService);
  }

  @Visible()
  public processDeclaration(): void {
    if (!this.authService.hasPermission(ErvuPermission.APPROVER)
        || !this.sendToErvu
        || !this.formJson) {
      return;
    }
    const kind = this.applicationKind.getValue();
    const appNumber = this.formJson['appNumber'];
    const accountId = this.formJson['accountId'];
    const personId = this.formJson['idPerson'];
    const login = this.formJson['login'];
    let request;

    switch (kind) {
      case ApplicationKind.CREATE_USER:
        let createData = new CreateAccountData();
        createData.account = this.populateDto(new Account(), this.formJson);
        createData.person = this.populateDto(new Person(), this.formJson);
        let roles = new Roles();
        roles.add = this.formJson['rolesList'].map(id => {
          let role = new Role();
          role.id = id;
          return role;
        });
        createData.roles = roles;
        request = new ProcessRequest<CreateAccountData>();
        request.data = createData;
        request.processKey = ProcessKey.CREATE;
        this.doRequest(request, appNumber);
        break;
      case ApplicationKind.EDIT_USER_MAIN:
        let editPersonData = new EditPersonData();
        editPersonData.accountId = accountId;
        editPersonData.personId = personId;
        editPersonData.organizationId = this.formJson['idDomain'];
        editPersonData.personData = this.populateDto(new Person(), this.formJson);
        request = new ProcessRequest<EditPersonData>();
        request.data = editPersonData;
        request.processKey = ProcessKey.EDIT_PERSON;
        this.doRequest(request, appNumber);
        break;
      case ApplicationKind.EDIT_USER_ACCOUNT:
        let editAccountData = new EditAccountData();
        let account = this.populateDto(new Account(), this.formJson);
        editAccountData.account = account;
        editAccountData.accountId = accountId;
        request = new ProcessRequest<EditAccountData>();
        request.data = editAccountData;
        request.processKey = ProcessKey.EDIT_ACCOUNT;
        this.doRequest(request, appNumber);
        break;
      case ApplicationKind.EDIT_USER_ROLES:
        let editRolesAccount = new EditRolesAccount();
        let rolesList = this.formJson['rolesList'];
        editRolesAccount.accountId = accountId;
        let roles2 = new Roles();
        roles2.add = rolesList.map(id => {
          let role = new Role();
          role.id = id;
          return role;
        });
        this.rpc.getRemovedRoleIds(accountId, rolesList)
            .then(list => {
              roles2.remove = list;
              editRolesAccount.roles = roles2;
              let editRolesData = new EditRolesData();
              editRolesData.data = editRolesAccount;
              request = new ProcessRequest<EditRolesData>();
              request.data = editRolesData;
              request.processKey = ProcessKey.EDIT_ROLES;
              this.doRequest(request, appNumber);
            });
        break;
      case ApplicationKind.BLOCK_USER:
        let blockingData = new BlockingData();
        blockingData.accountList = [
          new AccountDetails(accountId, login)
        ];
        request = new ProcessRequest<BlockingData>();
        request.data = blockingData;
        request.processKey = ProcessKey.BLOCK;
        this.doRequest(request, appNumber);
        break;
      case ApplicationKind.UNBLOCK_USER:
        let unblockingData = new UnblockingData();
        let blockedRegion = this.formJson['blockedRegion'];

        switch (blockedRegion) {
          case BlockedRegion.ACCOUNT:
            unblockingData.accountList = [
              new AccountDetails(accountId, login)
            ];
            break;
          case BlockedRegion.PERSON:
            unblockingData.personList = [
              new PersonDetails(personId, login)
            ];
            break;
          case BlockedRegion.BOTH:
            unblockingData.accountList = [
              new AccountDetails(accountId, login)
            ];
            unblockingData.personList = [
              new PersonDetails(personId, login)
            ];
            break;
        }
        request = new ProcessRequest<UnblockingData>();
        request.data = unblockingData;
        request.processKey = ProcessKey.UNBLOCK;
        this.doRequest(request, appNumber);
        break;
      case ApplicationKind.RESET_PASSWORD:
        let resetPasswordAccount = new ResetPasswordAccount();
        resetPasswordAccount.id = accountId;
        let resetPasswordData = new ResetPasswordData();
        resetPasswordData.account = resetPasswordAccount;
        request = new ProcessRequest<ResetPasswordData>();
        request.data = resetPasswordData;
        request.processKey = ProcessKey.RESET_PASSWORD;
        this.doRequest(request, appNumber);
        break;
      default: break;
    }
  }

  @Visible()
  public allowSendToErvu(): void {
    this.formJson = this.collectData();
    this.sendToErvu = true;
  }

  private collectData(): any {
    let jsonObj = {};
    let fields: FormField[] = this.form.getScriptsInChildren(FormField);

    for (let field of fields) {
      jsonObj[`${field.name}`] = field.getValue();
    }
    return jsonObj;
  }

  private populateDto(dto: any, jsonObj: any): any {
    Object.keys(dto).forEach(key => {
      if (jsonObj[key]) {
        dto[key] = jsonObj[key]
      }
    });
    return dto;
  }

  private doRequest(request: any, appNumber: number): void {
    const url = window.location.origin + UserManagementService.PROCESS_START_PATH;
    request.userId = this.authService.getUserId();
    request.data.applicationNumber = appNumber;
    this.httpClient.post(url, request).toPromise()
        .then((response: ProcessResponse) => {
          let code = response.code;
          if (code !== '200') {
            this.saveError(appNumber, response.msg);
          }
          else {
            this.statusUpdateService.trackDeclaration(appNumber);
          }
        })
        .catch(reason => {
          console.error("Error while executing request:", reason.toString());
          this.saveError(appNumber, reason.toString());
        });
  }

  private saveError(appNumber: number, errorMsg: string): void {
    this.rpc.saveError(appNumber, errorMsg)
        .then(() => this.statusUpdateService.publishStatus(appNumber, false))
        .catch(err => console.log('failed to update application status', err));
  }
}
