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 { isValid, validateForm } from '@ng-cortex/utils';
import { NzDrawerService } from 'ng-zorro-antd/drawer';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { NcMenuSelectorComponent } from '../nc-menu-selector/nc-menu-selector.component';
import { NcRoleEditorComponent } from '../nc-role-editor/nc-role-editor.component';

/** 字段接口 */
interface Field {
  /** 名称 */
  name: string;
  /** 描述 */
  description?: string;
  /** 可见状态 */
  visible?: boolean;
  /** 对齐 */
  align?: 'left' | 'right' | 'center';
  /** 宽度 */
  width?: string;
  /** 排序键 */
  sortKey?: string;
  /** 排序状态 */
  sortOrder?: string | null;
  /** 默认排序 */
  defaultSequence?: number;
  /** 默认可见状态 */
  defaultVisible?: boolean;
  /** 默认宽度 */
  defaultWidth?: string;
  /** 标题模板 */
  titleTemplate?: TemplateRef<any>;
  /** 内容模板 */
  contentTemplate?: TemplateRef<{ $implicit?: any; source?: any; extra?: any; }>;
}

/** 角色管理页面 */
@Component({
  selector: 'nc-role',
  templateUrl: './nc-role.page.html',
  styleUrls: ['./nc-role.page.scss']
})
export class NcRolePage implements OnInit, AfterViewInit {

  /** 授权应用列表模板 */
  @ViewChild('authorizedApplicationListTemplate') _authorizedApplicationListTemplate!: TemplateRef<{ $implicit: string; extra: string[]; }>;
  /** 时间模板 */
  @ViewChild('timeTemplate') _timeTemplate!: TemplateRef<{ $implicit: string; }>;

  /** 角色列表 */
  _roleList: any[] = [];
  /** 角色额外属性 */
  _roleExtras: any = {};
  /** 角色搜索表单 */
  _roleSearchForm!: FormGroup;
  /** 角色加载状态 */
  _roleLoading: boolean = false;
  /** 角色全部选中状态 */
  _roleAllChecked: boolean = false;
  /** 角色模糊选中状态 */
  _roleIndeterminate: boolean = false;
  /** 角色字段列表 */
  _roleFieldList: Field[] = [
    { name: 'name', description: '角色名称', visible: true, width: '200px' },
    { name: 'description', description: '描述', visible: true, width: '200px' },
    { name: 'dataScope', description: '数据权限', visible: true, width: '200px' },
    { name: 'authorizedApplications', description: '授权应用', visible: true, width: '200px' },
    { name: 'createdBy', description: '创建人', width: '200px' },
    { name: 'createdTime', description: '创建时间', width: '200px' },
    { name: 'lastModifiedBy', description: '最后更新人', width: '200px' },
    { name: 'lastModifiedTime', description: '最后更新时间', width: '200px' }
  ];

  /** 取消获取角色列表 */
  private _cancelGetRoleListFn = () => { };

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

  /** 初始化后 */
  ngOnInit(): void {
    this._roleFieldList.forEach((field, index) => {
      field.defaultSequence = index + 1;
      field.defaultVisible = field.visible;
      field.defaultWidth = field.width;
    });
    this._roleSearchForm = this._formBuilder.group({
      keywords: [null]
    });
    validateForm(this._roleSearchForm, true).subscribe(() => this._getRoleList());
  }

  /** 初始次渲染后 */
  ngAfterViewInit(): void {
    this._roleFieldList.forEach(field => {
      if (/^authorizedApplications$/.test(field.name)) {
        field.contentTemplate = this._authorizedApplicationListTemplate;
      }
      if (/^(createdTime|lastModifiedTime)$/.test(field.name)) {
        field.contentTemplate = this._timeTemplate;
      }
    });
  }

  /** 查询角色列表 */
  _queryRoleList(): void {
    validateForm(this._roleSearchForm).subscribe(() => this._getRoleList());
  }

  /** 重新查询角色列表 */
  _requeryRoleList(): void {
    this._queryRoleList();
  }

  /** 重置角色搜索表单 */
  _resetRoleSearchForm(): void {
    this._roleSearchForm.reset();
    this._queryRoleList();
  }

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

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

  /**
   * 选中所有角色列表
   * @param checked 选中状态
   */
  _checkAllRoleList(checked: boolean): void {
    for (const id in this._roleExtras) {
      this._roleExtras[id].checked = checked;
    }
    this._roleAllChecked = checked;
    this._roleIndeterminate = false;
  }

  /** 更新角色选中状态 */
  _updateRoleCheckStatus(): void {
    const checkedRoleList = this._roleList.filter(role => this._roleExtras[role.id].checked);
    switch (checkedRoleList.length) {
      case 0:
        this._roleAllChecked = false;
        this._roleIndeterminate = false;
        break;
      case this._roleList.length:
        this._roleAllChecked = true;
        this._roleIndeterminate = false;
        break;
      default:
        this._roleAllChecked = false;
        this._roleIndeterminate = true;
    }
  }

  /** 新增角色 */
  _createRole(): void {
    this._nzModalService.create({
      nzTitle: '新增角色',
      nzContent: NcRoleEditorComponent,
      nzWidth: 520,
      nzOnOk: roleEditor => {
        return roleEditor.submit()
          .pipe(map(({ success, updated }) => {
            if (updated) {
              this._queryRoleList();
            }
            return success;
          }))
          .toPromise();
      }
    });
  }

  /**
   * 编辑角色
   * @param role 角色
   */
  _updateRole(role: any): void {
    this._nzModalService.create({
      nzTitle: '编辑角色',
      nzContent: NcRoleEditorComponent,
      nzComponentParams: {
        role: role
      },
      nzWidth: 520,
      nzOnOk: roleEditor => {
        return roleEditor.submit()
          .pipe(map(({ success, updated }) => {
            if (updated) {
              this._queryRoleList();
            }
            return success;
          }))
          .toPromise();
      }
    });
  }

  /**
   * 删除角色
   * @param role 角色
   */
  _deleteRole(role: any): void {
    let cancelDeleteRoleFn = () => { };
    this._nzModalService.confirm({
      nzTitle: '删除确认',
      nzContent: '是否确认删除角色 “' + role.name + '”',
      nzOnOk: () => {
        return new Observable(subscriber => {
          const url = '@<%= getSeparatorCase(serviceName) %>/api/roles/' + role.id;
          const deleteRoleSubscription = this._httpClient.delete(url, { responseType: 'text' })
            .pipe(map(() => {
              this._queryRoleList();
              return true;
            }))
            .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
              this._nzNotificationService.error('删除角色失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
              return of(false);
            }))
            .subscribe(subscriber);
          cancelDeleteRoleFn = () => {
            deleteRoleSubscription.unsubscribe();
          };
        })
          .toPromise();
      },
      nzOnCancel: () => {
        cancelDeleteRoleFn();
      }
    });
  }

  /** 选择菜单 */
  _selectMenus(role: any): void {
    const selectMenuDrawerRef = this._nzDrawerService.create({
      nzTitle: role.name,
      nzContent: NcMenuSelectorComponent,
      nzContentParams: { role },
      nzWidth: 720,
      nzMaskClosable: false,
      nzBodyStyle: { padding: '0' }
    });
    selectMenuDrawerRef.afterClose.subscribe(({ updated }) => {
      if (updated) {
        this._queryRoleList();
      }
    });
  }

  /** 获取角色列表 */
  private _getRoleList(): void {
    this._cancelGetRoleListFn();
    if (this._roleSearchForm.valid) {
      this._roleLoading = true;
      const completeGetRoleListFn = () => {
        this._cancelGetRoleListFn = () => { };
        this._roleLoading = false;
      };
      const url = '@<%= getSeparatorCase(serviceName) %>/api/roles';
      const params: any = { ...this._roleSearchForm.getRawValue() };
      for (const key in params) {
        if (!isValid(params[key])) {
          delete params[key];
        }
      }
      const getRoleListSubscription = this._httpClient.get<any[]>(url, { params })
        .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
          this._nzNotificationService.error('获取角色列表失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
          return of([]);
        }))
        .subscribe(roleList => {
          completeGetRoleListFn();
          const roleExtras: any = {};
          roleList.forEach(role => {
            let authorizedApplicationList: string[];
            try {
              authorizedApplicationList = JSON.parse(role.authorizedApplications) || [];
            } catch (error) {
              authorizedApplicationList = [];
            }
            roleExtras[role.id] = {
              checked: false,
              authorizedApplicationList: authorizedApplicationList
            };
          });
          this._roleList = roleList;
          this._roleExtras = roleExtras;
          this._roleAllChecked = false;
          this._roleIndeterminate = false;
        });
      this._cancelGetRoleListFn = () => {
        getRoleListSubscription.unsubscribe();
        completeGetRoleListFn();
      };
    } else {
      this._roleList = [];
      this._roleExtras = {};
      this._roleAllChecked = false;
      this._roleIndeterminate = false;
    }
  }

}
