import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Component, OnInit, OnDestroy, Input } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { NcDictItem, NgCortexService } from '@ng-cortex/core';
import { getEntityUpdate, isValid, validateForm, Validators } from '@ng-cortex/utils';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { NzTreeNodeOptions } from 'ng-zorro-antd/tree';
import { Observable, of } from 'rxjs';
import { catchError, distinctUntilChanged, map, mergeMap, tap } from 'rxjs/operators';

/** 角色编辑器组件 */
@Component({
  selector: 'nc-role-editor',
  templateUrl: './nc-role-editor.component.html',
  styleUrls: ['./nc-role-editor.component.scss']
})
export class NcRoleEditorComponent implements OnInit, OnDestroy {

  /** 角色 */
  @Input() role: any = null;

  /** 角色表单 */
  _roleForm!: FormGroup;
  /** 数据范围列表 */
  _dataScopeList: NcDictItem[] = [];
  /** 数据范围加载状态 */
  _dataScopeLoading: boolean = false;
  /** 机构列表 */
  _organizationList: any[] = [];
  /** 机构树形选项列表 */
  _organizationTreeNodeOptionList: any[] = [];
  /** 机构加载状态 */
  _organizationLoading: boolean = false;
  /** 实体比较 */
  _entityCompareWith = (entityA: any, entityB: any) => (entityA && entityA.id) === (entityB && entityB.id);

  /** 取消提交 */
  private _cancelSubmitFn = () => { };

  constructor(
    private _formBuilder: FormBuilder,
    private _httpClient: HttpClient,
    private _nzNotificationService: NzNotificationService,
    private _ngCortexService: NgCortexService) { }

  /** 初始化后 */
  ngOnInit(): void {
    const { passport, currentApplication } = this._ngCortexService.data;
    this._roleForm = this._formBuilder.group({
      companyId: [null],
      applicationCode: [null],
      name: [null, [Validators.required, Validators.maxLength(30)]],
      description: [null, [Validators.maxLength(50)]],
      dataScope: [null, [Validators.required, Validators.maxLength(20)]],
      organizations: [null, Validators.required]
    });
    const { dataScope, organizations } = this._roleForm.controls;
    dataScope.valueChanges
      .pipe(distinctUntilChanged())
      .subscribe(dataScope => {
        if (dataScope === '自定义数据权限') {
          organizations.enable();
        } else {
          organizations.disable();
          organizations.reset();
        }
      });
    const roleFormPatch = {
      companyId: passport!.companyId,
      applicationCode: currentApplication!.code,
      dataScope: null,
      ...this.role
    };
    if (roleFormPatch.dataScope) {
      const dictItem: any = { label: roleFormPatch.dataScope, value: roleFormPatch.dataScope };
      this._dataScopeList = [dictItem];
    }
    if (roleFormPatch.organizations) {
      roleFormPatch.organizations = roleFormPatch.organizations.map((organization: any) => organization.id.toString());
    }
    this._roleForm.patchValue(roleFormPatch);

    this._getOrganizationList();

    this._dataScopeLoading = true;
    this._ngCortexService.getDictItemList('dataScope')
      .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
        this._nzNotificationService.error('获取数据范围列表失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
        return of([]);
      }))
      .subscribe(dataScopeList => {
        this._dataScopeList = dataScopeList;
        this._dataScopeLoading = false;
      });
  }

  /** 注销后 */
  ngOnDestroy(): void {
    this._cancelSubmitFn();
  }

  /** 提交 */
  submit(): Observable<{ success: boolean; updated: any }> {
    return new Observable(subscriber => {
      const submitResult = {
        success: false,
        updated: null
      };
      const submitSubscription = validateForm(this._roleForm)
        .pipe(mergeMap(valid => {
          if (valid) {
            const roleUpdate = this._getRoleUpdate();
            if (roleUpdate) {
              return this._submitRole(roleUpdate)
                .pipe(tap(roleUpdated => {
                  submitResult.success = true;
                  submitResult.updated = roleUpdated;
                }));
            } else {
              submitResult.success = true;
            }
          }
          return of(null);
        }))
        .pipe(catchError(() => of(null)))
        .pipe(map(() => submitResult))
        .subscribe(subscriber);
      this._cancelSubmitFn = () => {
        submitSubscription.unsubscribe();
      };
    });
  }

  /** 获取机构列表 */
  private _getOrganizationList(): void {
    this._organizationLoading = true;
    const url = '@<%= getSeparatorCase(serviceName) %>/api/organizations';
    this._httpClient.get<any[]>(url)
      .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
        this._nzNotificationService.error('获取机构列表失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
        return of([]);
      }))
      .subscribe(organizationList => {
        this._organizationList = organizationList.sort((organization1, organization2) => organization1.sequence - organization2.sequence);
        this._organizationLoading = false;
        this._generateOrganizationTreeNodeList();
      });
  }

  /** 生成机构树形选项列表 */
  private _generateOrganizationTreeNodeList(): void {
    const organizationTreeNodeOptionList: NzTreeNodeOptions[] = [];
    const organizationTreeNodeOptions: any = {};
    this._organizationList.forEach(organization => {
      const organizationTreeNodeOption: NzTreeNodeOptions = organizationTreeNodeOptions[organization.id] = organizationTreeNodeOptions[organization.id] || {};
      organizationTreeNodeOption.key = organization.id.toString();
      organizationTreeNodeOption.title = organization.name;
      if (!organizationTreeNodeOption.children) {
        organizationTreeNodeOption.isLeaf = true;
      }
      if (organization.parentId) {
        const parentOrganizationTreeNodeOption: NzTreeNodeOptions = organizationTreeNodeOptions[organization.parentId] = organizationTreeNodeOptions[organization.parentId] || {};
        if (!parentOrganizationTreeNodeOption.children) {
          delete parentOrganizationTreeNodeOption.isLeaf;
          parentOrganizationTreeNodeOption.children = [];
        }
        parentOrganizationTreeNodeOption.children.push(organizationTreeNodeOption);
      } else {
        organizationTreeNodeOptionList.push(organizationTreeNodeOption);
      }
    });
    this._organizationTreeNodeOptionList = organizationTreeNodeOptionList;
  }

  /** 获取角色更新 */
  private _getRoleUpdate(): any {
    const update = { ...this._roleForm.getRawValue() };
    for (const key in update) {
      if (!isValid(update[key])) {
        update[key] = null;
      }
    }
    if (update.organizations) {
      const organizations: any = {};
      this._organizationList.forEach(organization => {
        organizations[organization.id] = organization;
      });
      update.organizations = update.organizations
        .map((organizationId: string) => organizations[organizationId])
        .filter((organization: any) => organization);
    }
    return getEntityUpdate(update, this.role);
  }

  /**
   * 提交角色
   * @param update 更新
   */
  private _submitRole(update: any): Observable<any> {
    const url = '@<%= getSeparatorCase(serviceName) %>/api/roles';
    const body = update;
    if (body.id) {
      return this._httpClient.patch(url, body).pipe(tap(
        () => {
          this._nzNotificationService.success('更新角色成功', null!);
        },
        (httpErrorResponse: HttpErrorResponse) => {
          this._nzNotificationService.success('更新角色失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
        }));
    } else {
      return this._httpClient.post(url, body).pipe(tap(
        () => {
          this._nzNotificationService.success('新增角色成功', null!);
        },
        (httpErrorResponse: HttpErrorResponse) => {
          this._nzNotificationService.success('新增角色失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
        }));
    }
  }

}
