import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { AfterViewInit, Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { NcOptionResource, NcTableField, NgCortexService } from '@ng-cortex/core';
import { getErrorMessage, isValid, validateForm } from '@ng-cortex/utils';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { NzTreeNodeOptions } from 'ng-zorro-antd/tree';
import { Observable, of } from 'rxjs';
import { catchError, map, mergeMap, tap } from 'rxjs/operators';
import { NcUserEditorComponent } from '../nc-user-editor/nc-user-editor.component';

/** 用户管理页面 */
@Component({
  selector: 'nc-user',
  templateUrl: './nc-user.page.html',
  styleUrls: ['./nc-user.page.less']
})
export class NcUserPage implements OnInit, AfterViewInit {

  /** 时间模板 */
  @ViewChild('timeTemplate') _timeTemplate!: TemplateRef<{ $implicit: string; }>;
  /** 有效状态主体模板 */
  @ViewChild('enabledBodyTemplate') _enabledBodyTemplate!: TemplateRef<{ $implicit: boolean; }>;
  /** 角色列表主体模板 */
  @ViewChild('roleListBodyTemplate') _roleListBodyTemplate!: TemplateRef<{ $implicit: any[]; }>;

  /** 用户列表 */
  _userList: any[] = [];
  /** 用户额外属性 */
  _userExtras: { [id: string]: any; } = {};
  /** 用户总数 */
  _userTotal: number = 0;
  /** 用户搜索表单 */
  _userSearchForm!: FormGroup;
  /** 用户参数 */
  _userParams = {
    page: 1,
    size: 20,
    sort: 'id,desc'
  };
  /** 用户加载状态 */
  _userLoading: boolean = false;
  /** 用户全部选中状态 */
  _userAllChecked: boolean = false;
  /** 用户模糊选中状态 */
  _userIndeterminate: boolean = false;
  /** 用户字段列表 */
  _userFieldList: NcTableField[] = [
    { key: 'account', name: '账号', visible: true, width: '150px', sortKey: 'account' },
    { key: 'name', name: '姓名', visible: true, width: '120px', sortKey: 'name' },
    { key: 'gender', name: '性别', visible: true, width: '100px', sortKey: 'gender' },
    { key: 'jobTitle', name: '职务', visible: true, width: '120px', sortKey: 'jobTitle' },
    { key: 'mobileNumber', name: '手机号', visible: true, width: '120px', sortKey: 'mobileNumber' },
    { key: 'email', name: '邮箱', visible: true, width: '150px', sortKey: 'email' },
    { key: 'identityCardNumber', name: '身份证号', width: '200px', sortKey: 'identityCardNumber' },
    { key: 'enabled', name: '有效状态', visible: true, width: '100px', sortKey: 'enabled' },
    { key: 'roles', name: '角色', visible: true, width: '200px' },
    { key: 'createdBy', name: '创建人', width: '120px', sortKey: 'createdBy' },
    { key: 'createdTime', name: '创建时间', width: '160px', sortKey: 'createdTime' },
    { key: 'lastModifiedBy', name: '最后更新人', width: '120px', sortKey: 'lastModifiedBy' },
    { key: 'lastModifiedTime', name: '最后更新时间', width: '160px', sortKey: 'lastModifiedTime' }
  ];
  /** 机构选项资源 */
  _organizationOptionResource!: NcOptionResource;

  /** 取消获取用户列表 */
  private _cancelGetUserListFn = () => { };

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

  /** 初始化后 */
  ngOnInit(): void {

    // 初始化用户字段列表
    this._userFieldList.forEach((field, index) => {
      field.defaultSequence = index + 1;
      field.defaultVisible = field.visible;
      field.defaultWidth = field.width;
    });

    // 构建用户搜索表单
    this._userSearchForm = this._formBuilder.group({
      organizationId: [null],
      keywords: [null]
    });

    // 获取机构选项资源
    const organizationOptionUrl = 'source::@' + this._ngCortexService.coreService + '/api/organizations';
    this._organizationOptionResource = this._ngCortexService.getOptionResource(organizationOptionUrl, {
      map: this._generateOrganizationTreeNodeList,
      error: error => this._nzNotificationService.error('获取机构列表失败', getErrorMessage(error))
    });

    // 初始化较验用户搜索表单
    validateForm(this._userSearchForm, true).subscribe(() => this._getUserList().subscribe());
  }

  /** 初始次渲染后 */
  ngAfterViewInit(): void {
    this._userFieldList.forEach(field => {
      if (/^(createdTime|lastModifiedTime)$/.test(field.key)) {
        field.bodyTemplate = this._timeTemplate;
      }
      if (/^(enabled)$/.test(field.key)) {
        field.bodyTemplate = this._enabledBodyTemplate;
      }
      if (/^(roles)$/.test(field.key)) {
        field.bodyTemplate = this._roleListBodyTemplate;
      }
    });
  }

  /** 查询用户列表 */
  _queryUserList(): void {
    validateForm(this._userSearchForm).subscribe(() => this._getUserList().subscribe());
  }

  /** 重新查询用户列表 */
  _requeryUserList(): void {
    this._userParams.page = 1;
    this._queryUserList();
  }

  /** 重置用户搜索表单 */
  _resetUserSearchForm(): void {
    this._userSearchForm.reset();
    this._queryUserList();
  }

  /**
   * 拖拽用户字段列表
   * @param event 拖拽事件
   */
  _dropUserFieldList(event: CdkDragDrop<string[]>): void {
    moveItemInArray(this._userFieldList, event.previousIndex, event.currentIndex);
  }

  /** 重置用户字段列表 */
  _resetUserFieldList(): void {
    this._userFieldList = this._userFieldList
      .map(field => {
        field.visible = field.defaultVisible!;
        field.width = field.defaultWidth;
        return field;
      })
      .sort((fieldA, fieldB) => fieldA.defaultSequence! - fieldB.defaultSequence!);
  }

  /**
   * 改变用户字段排序
   * @param field 字段
   */
  _changeUserFieldSort(field: NcTableField): void {
    const targetField = field;
    this._userFieldList
      .filter(field => field !== targetField && field.sortOrder)
      .forEach(field => field.sortOrder = null);
    if (field.sortOrder) {
      this._userParams.sort = field.sortKey + ',' + field.sortOrder.slice(0, -3);
    } else {
      this._userParams.sort = 'id,desc';
    }
    this._requeryUserList();
  }

  /**
   * 选中所有用户列表
   * @param checked 选中状态
   */
  _checkAllUserList(checked: boolean): void {
    for (const id in this._userExtras) {
      this._userExtras[id].checked = checked;
    }
    this._userAllChecked = checked;
    this._userIndeterminate = false;
  }

  /** 更新用户选中状态 */
  _updateUserCheckStatus(): void {
    const checkedUserList = this._userList.filter(user => this._userExtras[user.id].checked);
    switch (checkedUserList.length) {
      case 0:
        this._userAllChecked = false;
        this._userIndeterminate = false;
        break;
      case this._userList.length:
        this._userAllChecked = true;
        this._userIndeterminate = false;
        break;
      default:
        this._userAllChecked = false;
        this._userIndeterminate = true;
    }
  }

  /** 新增用户 */
  _createUser(): void {
    this._nzModalService.create({
      nzTitle: '新增用户',
      nzContent: NcUserEditorComponent,
      nzWidth: 520,
      nzOnOk: userEditor => {
        return userEditor.submit()
          .pipe(map(({ success, updated }) => {
            if (updated) {
              this._queryUserList();
            }
            return success;
          }))
          .toPromise();
      }
    });
  }

  /**
   * 编辑用户
   * @param user 用户
   */
  _updateUser(user: any): void {
    this._nzModalService.create({
      nzTitle: '编辑用户',
      nzContent: NcUserEditorComponent,
      nzComponentParams: {
        user: user
      },
      nzWidth: 520,
      nzOnOk: userEditor => {
        return userEditor.submit()
          .pipe(map(({ success, updated }) => {
            if (updated) {
              this._queryUserList();
            }
            return success;
          }))
          .toPromise();
      }
    });
  }

  /**
   * 删除用户
   * @param user 用户
   */
  _deleteUser(user: any): void {
    let cancelDeleteUserFn = () => { };
    this._nzModalService.confirm({
      nzTitle: '删除确认',
      nzContent: '是否确认删除用户 “' + user.name + '”',
      nzOnOk: () => {
        return new Observable(subscriber => {
          const url = '@' + this._ngCortexService.coreService + '/api/users/' + user.id;
          const deleteUserSubscription = this._httpClient.delete(url, { responseType: 'text' })
            .pipe(map(() => {
              this._queryUserList();
              return true;
            }))
            .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
              this._nzNotificationService.error('删除用户失败', getErrorMessage(httpErrorResponse));
              return of(false);
            }))
            .subscribe(subscriber);
          cancelDeleteUserFn = () => {
            deleteUserSubscription.unsubscribe();
          };
        })
          .toPromise();
      },
      nzOnCancel: () => {
        cancelDeleteUserFn();
      }
    });
  }

  /** 获取用户列表 */
  private _getUserList(): Observable<HttpErrorResponse | Error | void> {
    this._cancelGetUserListFn();
    return new Observable(subscriber => {
      if (this._userSearchForm.valid) {
        this._userLoading = true;
        const completeGetUserListFn = () => {
          this._cancelGetUserListFn = () => { };
          this._userLoading = false;
        };
        const url = '@' + this._ngCortexService.coreService + '/api/users';
        const params: any = {
          ...this._userSearchForm.getRawValue(),
          ...this._userParams
        };
        for (const key in params) {
          if (!isValid(params[key])) {
            delete params[key];
          }
        }
        if (params.organizationId) {
          const organizationChildIds: { [key: string]: number[] } = {};
          if (this._organizationOptionResource.origin) {
            this._organizationOptionResource.origin.forEach((organization: any) => {
              const { id, parentId } = organization;
              if (parentId) {
                if (!organizationChildIds[parentId]) {
                  organizationChildIds[parentId] = [];
                }
                organizationChildIds[parentId].push(id);
              }
            });
          }
          const getOrganizationChildIdList = (id: number) => {
            let organizationChildIdList: string[] = [];
            if (organizationChildIds[id]) {
              organizationChildIds[id].forEach(organizationChildId => {
                organizationChildIdList = organizationChildIdList
                  .concat(organizationChildId.toString())
                  .concat(getOrganizationChildIdList(organizationChildId));
              });
            }
            return organizationChildIdList;
          };
          params.organizationIds = [params.organizationId, ...getOrganizationChildIdList(params.organizationId)];
          delete params.organizationId;
        }
        params.page--;
        const getUserListSubscription = this._httpClient.get<any[]>(url, { params: params, observe: 'response' })
          .pipe(mergeMap(httpResponse => {
            const userList = httpResponse.body!;
            const userTotal = Number(httpResponse.headers.get('X-Total-Count'));
            if (userList.length === 0 && userTotal > 0) {
              this._userParams.page = Math.ceil(userTotal / params.size);
              params.page = this._userParams.page - 1;
              return this._httpClient.get<any[]>(url, { params: params, observe: 'response' })
                .pipe(map(httpResponse => {
                  const userList = httpResponse.body!;
                  const userTotal = Number(httpResponse.headers.get('X-Total-Count'));
                  return { userList, userTotal };
                }));
            }
            return of({ userList, userTotal });
          }))
          .pipe(tap(() => subscriber.next(undefined)))
          .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
            this._nzNotificationService.error('获取用户列表失败', getErrorMessage(httpErrorResponse));
            subscriber.next(httpErrorResponse);
            return of({ userList: [], userTotal: 0 });
          }))
          .subscribe(({ userList, userTotal }) => {
            completeGetUserListFn();
            const userExtras: { [id: string]: any; } = {};
            userList.forEach(user => {
              userExtras[user.id] = { checked: false };
            });
            this._userList = userList;
            this._userTotal = userTotal;
            this._userExtras = userExtras;
            this._userAllChecked = false;
            this._userIndeterminate = false;
            subscriber.complete();
          });
        this._cancelGetUserListFn = () => {
          getUserListSubscription.unsubscribe();
          completeGetUserListFn();
          subscriber.next(new Error('取消获取用户列表'));
          subscriber.complete();
        };
      } else {
        subscriber.next(new Error('筛选用户不合法'));
        subscriber.complete();
      }
    });
  }

  /**
   * 生成机构树形选项列表
   * @param organizationList 机构列表
   */
  private _generateOrganizationTreeNodeList(organizationList: any[]): NzTreeNodeOptions[] {
    const organizationTreeNodeOptionList: NzTreeNodeOptions[] = [];
    const organizationTreeNodeOptions: { [id: string]: NzTreeNodeOptions; } = {};
    organizationList.forEach(organization => {
      const organizationTreeNodeOption = 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 = organizationTreeNodeOptions[organization.parentId] = organizationTreeNodeOptions[organization.parentId] || {};
        if (!parentOrganizationTreeNodeOption.children) {
          delete parentOrganizationTreeNodeOption.isLeaf;
          parentOrganizationTreeNodeOption.children = [];
        }
        parentOrganizationTreeNodeOption.children.push(organizationTreeNodeOption);
      } else {
        organizationTreeNodeOptionList.push(organizationTreeNodeOption);
      }
    });
    return organizationTreeNodeOptionList;
  }

}
