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';<% if (dictCodeList.length > 0) { %>
import { NgCortexService, NcDictItem } from '@ng-cortex/core';<% } %>
import { isValid, validateForm } from '@ng-cortex/utils';<% if (filterDatePickerFieldList.length > 0) { %>
import { format } from 'date-fns';<% } %>
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { Observable, of } from 'rxjs';
import { catchError, map<% if (pagination) { %>, mergeMap<% } %>, tap } from 'rxjs/operators';
import { <%= getPascalCase(name) %>EditorComponent } from '../<%= getSeparatorCase(name) %>-editor/<%= getSeparatorCase(name) %>-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; }>;
}

/** <%= description %>列表页面 */
@Component({
  selector: '<%= getSeparatorCase(prefix) %>-<%= getSeparatorCase(name) %>',
  templateUrl: './<%= getSeparatorCase(name) %>.page.html',
  styleUrls: ['./<%= getSeparatorCase(name) %>.page.scss']
})
export class <%= getPascalCase(name) %>Page implements OnInit, AfterViewInit {

  /** 标题内容模板 */
  @ViewChild('titleContentTemplate') _titleContentTemplate!: TemplateRef<{ $implicit: any; source: any; }>;<% if (inputNumberFieldList.length > 0) { %>
  /** 数字内容模板 */
  @ViewChild('numberContentTemplate') _numberContentTemplate!: TemplateRef<{ $implicit: number; }>;<% } %><% if (switchFieldList.length > 0) { %>
  /** 布尔内容模板 */
  @ViewChild('booleanContentTemplate') _booleanContentTemplate!: TemplateRef<{ $implicit: boolean; }>;<% } %><% if (datetimePickerFieldList.length > 0) { %>
  /** 时间内容模板 */
  @ViewChild('timeContentTemplate') _timeContentTemplate!: TemplateRef<{ $implicit: string; }>;<% } %>

  /** <%= description %>列表 */
  _<%= getCamelCase(name) %>List: any[] = [];
  /** <%= description %>额外属性 */
  _<%= getCamelCase(name) %>Extras: any = {};<% if (pagination) { %>
  /** <%= description %>总数 */
  _<%= getCamelCase(name) %>Total: number = 0;<% } %>
  /** <%= description %>搜索表单 */
  _<%= getCamelCase(name) %>SearchForm!: FormGroup;<% if (pagination) { %>
  /** <%= description %>参数 */
  _<%= getCamelCase(name) %>Params = {
    page: 1,
    size: 20,
    sort: 'id,desc'
  };<% } %>
  /** <%= description %>加载状态 */
  _<%= getCamelCase(name) %>Loading: boolean = false;
  /** <%= description %>全部选中状态 */
  _<%= getCamelCase(name) %>AllChecked: boolean = false;
  /** <%= description %>模糊选中状态 */
  _<%= getCamelCase(name) %>Indeterminate: boolean = false;
  /** <%= description %>字段列表 */
  _<%= getCamelCase(name) %>FieldList: Field[] = [<% fieldList.forEach(function(field, index) { %>
    { name: '<%= getCamelCase(field.name) %>'<% if (field.description) { %>, description: '<%= field.description %>'<% } %><% if (field.listVisible) { %>, visible: <%= field.listVisible %><% } %><% if (field.controlType === 'inputNumber') { %>, align: 'right'<% } %><% if (field.listWidth) { %>, width: '<%= field.listWidth %>'<% } %><% if (pagination) { %>, sortKey: '<%= field.name %>'<% } %> }<% if (index < fieldList.length - 1) { %>,<% } }) %>
  ];<% if (hiddenFilterFieldList.length > 0) { %>
  /** 显示所有<%= description %>筛选器 */
  _showAll<%= getPascalCase(name) %>Filters: boolean = false;<% } %><% dictCodeList.forEach(function(dictCode) { %>
  /** <%= dictCode %>列表 */
  _<%= dictCode %>List: NcDictItem[] = [];
  /** <%= dictCode %>加载状态 */
  _<%= dictCode %>Loading: boolean = false;<% }) %>

  /** 取消获取<%= description %>列表 */
  private _cancelGet<%= getPascalCase(name) %>ListFn = () => { };

  constructor(
    private _formBuilder: FormBuilder,
    private _httpClient: HttpClient<% if (dictCodeList.length > 0) { %>,
    private _ngCortexService: NgCortexService<% } %>,
    private _nzModalService: NzModalService,
    private _nzNotificationService: NzNotificationService) { }

  /** 初始化后 */
  ngOnInit(): void {
    this._<%= getCamelCase(name) %>FieldList.forEach((field, index) => {
      field.defaultSequence = index + 1;
      field.defaultVisible = field.visible;
      field.defaultWidth = field.width;
    });
    this._<%= getCamelCase(name) %>SearchForm = this._formBuilder.group({
      keywords: [null]<% filterFieldList.forEach(function(field) { %>,
      <%= getCamelCase(field.name) %>: [null]<% }) %>
    });
    validateForm(this._<%= getCamelCase(name) %>SearchForm, true).subscribe(() => this._get<%= getPascalCase(name) %>List().subscribe());<% dictCodeList.forEach(function(dictCode) { %>

    this._<%= dictCode %>Loading = true;
    this._ngCortexService.getDictItemList('<%= dictCode %>')
      .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
        this._nzNotificationService.error('获取 <%= dictCode %> 列表失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
        return of([]);
      }))
      .subscribe(<%= dictCode %>List => {
        this._<%= dictCode %>List = <%= dictCode %>List;
        this._<%= dictCode %>Loading = false;
      });<% }) %>
  }

  /** 初始次渲染后 */
  ngAfterViewInit(): void {
    requestAnimationFrame(() => {
      this._<%= getCamelCase(name) %>FieldList.forEach(field => {
        if (/^<%= getCamelCase(titleFieldName) %>$/.test(field.name)) {
          field.contentTemplate = this._titleContentTemplate;
        }<% if (inputNumberFieldList.length > 0) { %>
        if (/^(<%= inputNumberFieldList.map(function(field) { return getCamelCase(field.name) }).join('|') %>)$/.test(field.name)) {
          field.contentTemplate = this._numberContentTemplate;
        }<% } %><% if (switchFieldList.length > 0) { %>
        if (/^(<%= switchFieldList.map(function(field) { return getCamelCase(field.name) }).join('|') %>)$/.test(field.name)) {
          field.contentTemplate = this._booleanContentTemplate;
        }<% } %><% if (datetimePickerFieldList.length > 0) { %>
        if (/^(<%= datetimePickerFieldList.map(function(field) { return getCamelCase(field.name) }).join('|') %>)$/.test(field.name)) {
          field.contentTemplate = this._timeContentTemplate;
        }<% } %>
      });
    });
  }

  /** 查询<%= description %>列表 */
  _query<%= getPascalCase(name) %>List(): void {
    validateForm(this._<%= getCamelCase(name) %>SearchForm).subscribe(() => this._get<%= getPascalCase(name) %>List().subscribe());
  }

  /** 重新查询<%= description %>列表 */
  _requery<%= getPascalCase(name) %>List(): void {<% if (pagination) { %>
    this._<%= getCamelCase(name) %>Params.page = 1;<% } %>
    this._query<%= getPascalCase(name) %>List();
  }

  /** 重置<%= description %>搜索表单 */
  _reset<%= getPascalCase(name) %>SearchForm(): void {
    this._<%= getCamelCase(name) %>SearchForm.reset();
    this._query<%= getPascalCase(name) %>List();
  }

  /**
   * 拖拽<%= description %>字段列表
   * @param event 拖拽事件
   */
  _drop<%= getPascalCase(name) %>FieldList(event: CdkDragDrop<string[]>): void {
    moveItemInArray(this._<%= getCamelCase(name) %>FieldList, event.previousIndex, event.currentIndex);
  }

  /** 重置<%= description %>字段列表 */
  _reset<%= getPascalCase(name) %>FieldList(): void {
    this._<%= getCamelCase(name) %>FieldList = this._<%= getCamelCase(name) %>FieldList
      .map(field => {
        field.visible = field.defaultVisible;
        field.width = field.defaultWidth;
        return field;
      })
      .sort((fieldA, fieldB) => fieldA.defaultSequence! - fieldB.defaultSequence!);
  }<% if (pagination) { %>

  /**
   * 改变<%= description %>字段排序
   * @param field 字段
   */
  _change<%= getPascalCase(name) %>FieldSort(field: Field): void {
    const targetField = field;
    this._<%= getCamelCase(name) %>FieldList
      .filter(field => field !== targetField && field.sortOrder)
      .forEach(field => field.sortOrder = null);
    if (field.sortOrder) {
      this._<%= getCamelCase(name) %>Params.sort = field.sortKey + ',' + field.sortOrder.slice(0, -3);
    } else {
      this._<%= getCamelCase(name) %>Params.sort = 'id,desc';
    }
    this._requery<%= getPascalCase(name) %>List();
  }<% } %>

  /**
   * 选中所有<%= description %>列表
   * @param checked 选中状态
   */
  _checkAll<%= getPascalCase(name) %>List(checked: boolean): void {
    for (const id in this._<%= getCamelCase(name) %>Extras) {
      this._<%= getCamelCase(name) %>Extras[id].checked = checked;
    }
    this._<%= getCamelCase(name) %>AllChecked = checked;
    this._<%= getCamelCase(name) %>Indeterminate = false;
  }

  /** 更新<%= description %>选中状态 */
  _update<%= getPascalCase(name) %>CheckStatus(): void {
    const checked<%= getPascalCase(name) %>List = this._<%= getCamelCase(name) %>List.filter(<%= getCamelCase(name) %> => this._<%= getCamelCase(name) %>Extras[<%= getCamelCase(name) %>.id].checked);
    switch (checked<%= getPascalCase(name) %>List.length) {
      case 0:
        this._<%= getCamelCase(name) %>AllChecked = false;
        this._<%= getCamelCase(name) %>Indeterminate = false;
        break;
      case this._<%= getCamelCase(name) %>List.length:
        this._<%= getCamelCase(name) %>AllChecked = true;
        this._<%= getCamelCase(name) %>Indeterminate = false;
        break;
      default:
        this._<%= getCamelCase(name) %>AllChecked = false;
        this._<%= getCamelCase(name) %>Indeterminate = true;
    }
  }

  /** 新增<%= description %> */
  _create<%= getPascalCase(name) %>(): void {
    this._nzModalService.create({
      nzTitle: '新增<%= description %>',
      nzContent: <%= getPascalCase(name) %>EditorComponent<% if (editorWidth) { %>,
      nzWidth: <%= editorWidth %><% } %>,
      nzOnOk: <%= getCamelCase(name) %>Editor => {
        return <%= getCamelCase(name) %>Editor.submit()
          .pipe(map(({ success, updated }) => {
            if (updated) {
              this._query<%= getPascalCase(name) %>List();
            }
            return success;
          }))
          .toPromise();
      }
    });
  }

  /**
   * 编辑<%= description %>
   * @param <%= getCamelCase(name) %> <%= description %>
   */
  _update<%= getPascalCase(name) %>(<%= getCamelCase(name) %>: any): void {
    this._nzModalService.create({
      nzTitle: '编辑<%= description %>',
      nzContent: <%= getPascalCase(name) %>EditorComponent,
      nzComponentParams: {
        <%= getCamelCase(name) %>: <%= getCamelCase(name) %>
      }<% if (editorWidth) { %>,
      nzWidth: <%= editorWidth %><% } %>,
      nzOnOk: <%= getCamelCase(name) %>Editor => {
        return <%= getCamelCase(name) %>Editor.submit()
          .pipe(map(({ success, updated }) => {
            if (updated) {
              this._query<%= getPascalCase(name) %>List();
            }
            return success;
          }))
          .toPromise();
      }
    });
  }

  /**
   * 删除<%= description %>
   * @param <%= getCamelCase(name) %> <%= description %>
   */
  _delete<%= getPascalCase(name) %>(<%= getCamelCase(name) %>: any): void {
    let cancelDelete<%= getPascalCase(name) %>Fn = () => { };
    this._nzModalService.confirm({
      nzTitle: '删除确认',
      nzContent: '是否确认删除<%= description %> “' + <%= getCamelCase(name) %>.<%= getCamelCase(titleFieldName) %> + '”',
      nzOnOk: () => {
        return new Observable(subscriber => {
          const url = '@<%= serviceName %>/api/<%= getPluralForm(getSeparatorCase(name)) %>/' + <%= getCamelCase(name) %>.id;
          const delete<%= getPascalCase(name) %>Subscription = this._httpClient.delete(url, { responseType: 'text' })
            .pipe(map(() => {
              this._query<%= getPascalCase(name) %>List();
              return true;
            }))
            .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
              this._nzNotificationService.error('删除<%= description %>失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
              return of(false);
            }))
            .subscribe(subscriber);
          cancelDelete<%= getPascalCase(name) %>Fn = () => {
            delete<%= getPascalCase(name) %>Subscription.unsubscribe();
          };
        })
          .toPromise();
      },
      nzOnCancel: () => {
        cancelDelete<%= getPascalCase(name) %>Fn();
      }
    });
  }

  /** 获取<%= description %>列表 */
  private _get<%= getPascalCase(name) %>List(): Observable<HttpErrorResponse | Error | void> {
    this._cancelGet<%= getPascalCase(name) %>ListFn();
    return new Observable(subscriber => {
      if (this._<%= getCamelCase(name) %>SearchForm.valid) {
        this._<%= getCamelCase(name) %>Loading = true;
        const completeGet<%= getPascalCase(name) %>ListFn = () => {
          this._cancelGet<%= getPascalCase(name) %>ListFn = () => { };
          this._<%= getCamelCase(name) %>Loading = false;
        };
        const url = '@<%= serviceName %>/api/<%= getPluralForm(getSeparatorCase(name)) %>';<% if (pagination) { %>
        const params: any = {
          ...this._<%= getCamelCase(name) %>SearchForm.getRawValue(),
          ...this._<%= getCamelCase(name) %>Params
        };<% } else { %>
        const params: any = { ...this._<%= getCamelCase(name) %>SearchForm.getRawValue() };<% } %>
        for (const key in params) {
          if (!isValid(params[key])) {
            delete params[key];
          }
        }<% filterDatetimePickerFieldList.forEach(function(field) { %>
        if (params.<%= getCamelCase(field.name) %>) {
          params.<%= getCamelCase(field.name) %>From = params.<%= getCamelCase(field.name) %>[0].toISOString();
          params.<%= getCamelCase(field.name) %>To = params.<%= getCamelCase(field.name) %>[1].toISOString();
          delete params.<%= getCamelCase(field.name) %>;
        }<% }) %><% filterDatePickerFieldList.forEach(function(field) { %>
        if (params.<%= getCamelCase(field.name) %>) {
          params.<%= getCamelCase(field.name) %>From = format(params.<%= getCamelCase(field.name) %>[0], 'yyyy-MM-dd');
          params.<%= getCamelCase(field.name) %>To = format(params.<%= getCamelCase(field.name) %>[1], 'yyyy-MM-dd');
          delete params.<%= getCamelCase(field.name) %>;
        }<% }) %><% if (pagination) { %>
        params.page--;
        const get<%= getPascalCase(name) %>ListSubscription = this._httpClient.get<any[]>(url, { params: params, observe: 'response' })
          .pipe(mergeMap(httpResponse => {
            const <%= getCamelCase(name) %>List = httpResponse.body!;
            const <%= getCamelCase(name) %>Total = Number(httpResponse.headers.get('X-Total-Count'));
            if (<%= getCamelCase(name) %>List.length === 0 && <%= getCamelCase(name) %>Total > 0) {
              this._<%= getCamelCase(name) %>Params.page = Math.ceil(<%= getCamelCase(name) %>Total / params.size);
              params.page = this._<%= getCamelCase(name) %>Params.page - 1;
              return this._httpClient.get<any[]>(url, { params: params, observe: 'response' })
                .pipe(map(httpResponse => {
                  const <%= getCamelCase(name) %>List = httpResponse.body!;
                  const <%= getCamelCase(name) %>Total = Number(httpResponse.headers.get('X-Total-Count'));
                  return { <%= getCamelCase(name) %>List, <%= getCamelCase(name) %>Total };
                }));
            }
            return of({ <%= getCamelCase(name) %>List, <%= getCamelCase(name) %>Total });
          }))
          .pipe(tap(() => subscriber.next(undefined)))
          .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
            this._nzNotificationService.error('获取<%= description %>列表失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
            subscriber.next(httpErrorResponse);
            return of({ <%= getCamelCase(name) %>List: [], <%= getCamelCase(name) %>Total: 0 });
          }))
          .subscribe(({ <%= getCamelCase(name) %>List, <%= getCamelCase(name) %>Total }) => {
            completeGet<%= getPascalCase(name) %>ListFn();
            const <%= getCamelCase(name) %>Extras: any = {};
            <%= getCamelCase(name) %>List.forEach(<%= getCamelCase(name) %> => {
              <%= getCamelCase(name) %>Extras[<%= getCamelCase(name) %>.id] = { checked: false };
            });
            this._<%= getCamelCase(name) %>List = <%= getCamelCase(name) %>List;
            this._<%= getCamelCase(name) %>Total = <%= getCamelCase(name) %>Total;
            this._<%= getCamelCase(name) %>Extras = <%= getCamelCase(name) %>Extras;
            this._<%= getCamelCase(name) %>AllChecked = false;
            this._<%= getCamelCase(name) %>Indeterminate = false;
            subscriber.complete();
          });<% } else { %>
        const get<%= getPascalCase(name) %>ListSubscription = this._httpClient.get<any[]>(url, { params })
          .pipe(tap(() => subscriber.next(null)))
          .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
            this._nzNotificationService.error('获取<%= description %>列表失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
            subscriber.next(httpErrorResponse);
            return of([]);
          }))
          .subscribe(<%= getCamelCase(name) %>List => {
            completeGet<%= getPascalCase(name) %>ListFn();
            const <%= getCamelCase(name) %>Extras: any = {};
            <%= getCamelCase(name) %>List.forEach(<%= getCamelCase(name) %> => {
              <%= getCamelCase(name) %>Extras[<%= getCamelCase(name) %>.id] = { checked: false };
            });
            this._<%= getCamelCase(name) %>List = <%= getCamelCase(name) %>List;
            this._<%= getCamelCase(name) %>Extras = <%= getCamelCase(name) %>Extras;
            this._<%= getCamelCase(name) %>AllChecked = false;
            this._<%= getCamelCase(name) %>Indeterminate = false;
            subscriber.complete();
          });<% } %>
        this._cancelGet<%= getPascalCase(name) %>ListFn = () => {
          get<%= getPascalCase(name) %>ListSubscription.unsubscribe();
          completeGet<%= getPascalCase(name) %>ListFn();
          subscriber.next(new Error('取消获取<%= description %>列表'));
          subscriber.complete();
        };
      } else {
        subscriber.next(new Error('筛选<%= description %>不合法'));
        subscriber.complete();
      }
    });
  }

}
