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 { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { Observable, of } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { NcCompanyEditorComponent } from '../nc-company-editor/nc-company-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-company',
  templateUrl: './nc-company.page.html',
  styleUrls: ['./nc-company.page.scss']
})
export class NcCompanyPage implements OnInit, AfterViewInit {

  /** 启用模板 */
  @ViewChild('enabledTemplate') _enabledTemplate!: TemplateRef<{ $implicit: boolean; }>;
  /** 标签列表模板 */
  @ViewChild('tagListTemplate') _tagListTemplate!: TemplateRef<{ extra: any; }>;
  /** 应用列表模板 */
  @ViewChild('applicationListTemplate') _applicationListTemplate!: TemplateRef<{ $implicit: any[]; }>;
  /** 时间模板 */
  @ViewChild('timeTemplate') _timeTemplate!: TemplateRef<{ $implicit: string; }>;

  /** 公司列表 */
  _companyList: any[] = [];
  /** 公司额外属性 */
  _companyExtras: any = {};
  /** 公司总数 */
  _companyTotal: number = 0;
  /** 公司搜索表单 */
  _companySearchForm!: FormGroup;
  /** 公司参数 */
  _companyParams = {
    page: 1,
    size: 20,
    sort: 'id,desc'
  };
  /** 公司加载状态 */
  _companyLoading: boolean = false;
  /** 公司全部选中状态 */
  _companyAllChecked: boolean = false;
  /** 公司模糊选中状态 */
  _companyIndeterminate: boolean = false;
  /** 公司字段列表 */
  _companyFieldList: Field[] = [
    { name: 'name', description: '公司名称', visible: true, width: '360px', sortKey: 'name' },
    { name: 'alias', description: '公司简称', visible: true, width: '200px', sortKey: 'alias' },
    { name: 'enabled', description: '有效状态', visible: true, width: '200px', sortKey: 'enabled' },
    { name: 'logoPath', description: 'Logo路径', width: '200px', sortKey: 'logoPath' },
    { name: 'tags', description: '标签', visible: true, width: '200px' },
    { name: 'applications', description: '授权应用', visible: true, width: '320px' },
    { name: 'createdBy', description: '创建人', width: '200px', sortKey: 'createdBy' },
    { name: 'createdTime', description: '创建时间', width: '200px', sortKey: 'createdTime' },
    { name: 'lastModifiedBy', description: '最后更新人', width: '200px', sortKey: 'lastModifiedBy' },
    { name: 'lastModifiedTime', description: '最后更新时间', width: '200px', sortKey: 'lastModifiedTime' }
  ];

  /** 取消获取公司列表 */
  private _cancelGetCompanyListFn = () => { };

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

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

  /** 初始次渲染后 */
  ngAfterViewInit(): void {
    this._companyFieldList.forEach(field => {
      if (/^enabled$/.test(field.name)) {
        field.contentTemplate = this._enabledTemplate;
      }
      if (/^tags$/.test(field.name)) {
        field.contentTemplate = this._tagListTemplate;
      }
      if (/^applications$/.test(field.name)) {
        field.contentTemplate = this._applicationListTemplate;
      }
      if (/^(createdTime|lastModifiedTime)$/.test(field.name)) {
        field.contentTemplate = this._timeTemplate;
      }
    });
  }

  /** 查询公司列表 */
  _queryCompanyList(): void {
    validateForm(this._companySearchForm).subscribe(() => this._getCompanyList());
  }

  /** 重新查询公司列表 */
  _requeryCompanyList(): void {
    this._companyParams.page = 1;
    this._queryCompanyList();
  }

  /** 重置公司搜索表单 */
  _resetCompanySearchForm(): void {
    this._companySearchForm.reset();
    this._queryCompanyList();
  }

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

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

  /**
   * 改变公司字段排序
   * @param field 字段
   */
  _changeCompanyFieldSort(field: Field): void {
    const targetField = field;
    this._companyFieldList
      .filter(field => field !== targetField && field.sortOrder)
      .forEach(field => field.sortOrder = null);
    if (field.sortOrder) {
      this._companyParams.sort = field.sortKey + ',' + field.sortOrder.slice(0, -3);
    } else {
      this._companyParams.sort = 'id,desc';
    }
    this._requeryCompanyList();
  }

  /**
   * 选中所有公司列表
   * @param checked 选中状态
   */
  _checkAllCompanyList(checked: boolean): void {
    for (const id in this._companyExtras) {
      this._companyExtras[id].checked = checked;
    }
    this._companyAllChecked = checked;
    this._companyIndeterminate = false;
  }

  /** 更新公司选中状态 */
  _updateCompanyCheckStatus(): void {
    const checkedCompanyList = this._companyList.filter(company => this._companyExtras[company.id].checked);
    switch (checkedCompanyList.length) {
      case 0:
        this._companyAllChecked = false;
        this._companyIndeterminate = false;
        break;
      case this._companyList.length:
        this._companyAllChecked = true;
        this._companyIndeterminate = false;
        break;
      default:
        this._companyAllChecked = false;
        this._companyIndeterminate = true;
    }
  }

  /** 新增公司 */
  _createCompany(): void {
    this._nzModalService.create({
      nzTitle: '新增公司',
      nzContent: NcCompanyEditorComponent,
      nzWidth: 520,
      nzOnOk: companyEditor => {
        return companyEditor.submit()
          .pipe(map(({ success, updated }) => {
            if (updated) {
              this._queryCompanyList();
            }
            return success;
          }))
          .toPromise();
      }
    });
  }

  /**
   * 编辑公司
   * @param company 公司
   */
  _updateCompany(company: any): void {
    this._nzModalService.create({
      nzTitle: '编辑公司',
      nzContent: NcCompanyEditorComponent,
      nzComponentParams: {
        company: company
      },
      nzWidth: 520,
      nzOnOk: companyEditor => {
        return companyEditor.submit()
          .pipe(map(({ success, updated }) => {
            if (updated) {
              this._queryCompanyList();
            }
            return success;
          }))
          .toPromise();
      }
    });
  }

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

  /** 获取公司列表 */
  private _getCompanyList(): void {
    this._cancelGetCompanyListFn();
    if (this._companySearchForm.valid) {
      this._companyLoading = true;
      const completeGetCompanyListFn = () => {
        this._cancelGetCompanyListFn = () => { };
        this._companyLoading = false;
      };
      const url = '@<%= getSeparatorCase(serviceName) %>/api/companies';
      const params: any = {
        ...this._companySearchForm.getRawValue(),
        ...this._companyParams
      };
      for (const key in params) {
        if (!isValid(params[key])) {
          delete params[key];
        }
      }
      params.page--;
      const getCompanyListSubscription = this._httpClient.get<any[]>(url, { params: params, observe: 'response' })
        .pipe(mergeMap(httpResponse => {
          const companyList = httpResponse.body!;
          const companyTotal = Number(httpResponse.headers.get('X-Total-Count'));
          if (companyList.length === 0 && companyTotal > 0) {
            this._companyParams.page = Math.ceil(companyTotal / params.size);
            params.page = this._companyParams.page - 1;
            return this._httpClient.get<any[]>(url, { params: params, observe: 'response' })
              .pipe(map(httpResponse => {
                const companyList = httpResponse.body!;
                const companyTotal = Number(httpResponse.headers.get('X-Total-Count'));
                return { companyList, companyTotal };
              }));
          }
          return of({ companyList, companyTotal });
        }))
        .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
          this._nzNotificationService.error('获取公司列表失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
          return of({ companyList: [], companyTotal: 0 });
        }))
        .subscribe(({ companyList, companyTotal }) => {
          completeGetCompanyListFn();
          const companyExtras: any = {};
          companyList.forEach(company => {
            companyExtras[company.id] = {
              checked: false,
              tagList: company.tags ? JSON.parse(company.tags) : []
            };
          });
          this._companyList = companyList;
          this._companyTotal = companyTotal;
          this._companyExtras = companyExtras;
          this._companyAllChecked = false;
          this._companyIndeterminate = false;
        });
      this._cancelGetCompanyListFn = () => {
        getCompanyListSubscription.unsubscribe();
        completeGetCompanyListFn();
      };
    } else {
      this._companyList = [];
      this._companyTotal = 0;
      this._companyExtras = {};
      this._companyAllChecked = false;
      this._companyIndeterminate = false;
    }
  }

}
