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 { Router } from '@angular/router';
import { isValid, validateForm } from '@ng-cortex/utils';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { Observable, of } from 'rxjs';
import { catchError, map, mergeMap, tap } from 'rxjs/operators';
import { environment } from '../../../../../environments/environment';

/** 字段接口 */
interface Field {
  /** 名称 */
  name: string;
  /** 描述 */
  description?: string;
  /** 可见状态 */
  visible?: boolean;
  /** 宽度 */
  width?: string;
  /** 对齐 */
  align?: 'left' | 'right' | 'center';
  /** 排序键 */
  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-system-message',
  templateUrl: './nc-system-message.page.html',
  styleUrls: ['./nc-system-message.page.scss']
})
export class NcSystemMessagePage implements OnInit, AfterViewInit {

  /** 是否已读内容模板 */
  @ViewChild('readTitleTemplate') _readTitleTemplate!: TemplateRef<any>;
  /** 是否已读内容模板 */
  @ViewChild('readContentTemplate') _readContentTemplate!: TemplateRef<{ $implicit: boolean; }>;
  /** 标题内容模板 */
  @ViewChild('titleContentTemplate') _titleContentTemplate!: TemplateRef<{ $implicit: any; source: any; }>;
  /** 内容内容模板 */
  @ViewChild('contentContentTemplate') _contentContentTemplate!: TemplateRef<{ $implicit: any; }>;
  /** 发送人内容模板 */
  @ViewChild('senderContentTemplate') _senderContentTemplate!: TemplateRef<{ extra: any; }>;
  /** 时间内容模板 */
  @ViewChild('timeContentTemplate') _timeContentTemplate!: TemplateRef<{ $implicit: string; }>;

  /** 系统消息明细路由 */
  _systemMessageDetailRoute!: string;
  /** 系统消息列表 */
  _systemMessageList: any[] = [];
  /** 系统消息额外属性 */
  _systemMessageExtras: any = {};
  /** 系统消息总数 */
  _systemMessageTotal: number = 0;
  /** 系统消息搜索表单 */
  _systemMessageSearchForm!: FormGroup;
  /** 系统消息参数 */
  _systemMessageParams = {
    page: 1,
    size: 20,
    sort: 'id,desc'
  };
  /** 系统消息加载状态 */
  _systemMessageLoading: boolean = false;
  /** 系统消息全部选中状态 */
  _systemMessageAllChecked: boolean = false;
  /** 系统消息模糊选中状态 */
  _systemMessageIndeterminate: boolean = false;
  /** 系统消息字段列表 */
  _systemMessageFieldList: Field[] = [
    { name: 'read', visible: true, width: '40px', align: 'center' },
    { name: 'title', description: '标题', visible: true, width: '320px', sortKey: 'title' },
    { name: 'content', description: '内容', visible: true, width: '560px', sortKey: 'content' },
    { name: 'sender', description: '发送人', visible: true, width: '200px', sortKey: 'sender' },
    { name: 'sendTime', description: '发送时间', visible: true, width: '200px', sortKey: 'sendTime' }
  ];
  /** 标记系统消息已读提示 */
  _markSystemMessageAsReadHint: string | null = null;
  /** 标记系统消息已读加载状态 */
  _markSystemMessageAsReadLoading: boolean = false;

  /** 取消获取系统消息列表 */
  private _cancelGetSystemMessageListFn = () => { };

  constructor(
    private _formBuilder: FormBuilder,
    private _httpClient: HttpClient,
    private _router: Router,
    private _nzNotificationService: NzNotificationService) { }

  /** 初始化后 */
  ngOnInit(): void {
    this._systemMessageDetailRoute = this._router.url.replace(/\?.*$/, '') + '-detail';
    this._systemMessageFieldList.forEach((field, index) => {
      field.defaultSequence = index + 1;
      field.defaultVisible = field.visible;
      field.defaultWidth = field.width;
    });
    this._systemMessageSearchForm = this._formBuilder.group({
      keywords: [null],
      sendTime: [null],
      read: [null]
    });
    validateForm(this._systemMessageSearchForm, true).subscribe(() => this._getSystemMessageList().subscribe());
    this._updateSystemMessageHandleHints();
  }

  /** 初始次渲染后 */
  ngAfterViewInit(): void {
    requestAnimationFrame(() => {
      this._systemMessageFieldList.forEach(field => {
        if (/^(read)$/.test(field.name)) {
          field.titleTemplate = this._readTitleTemplate;
          field.contentTemplate = this._readContentTemplate;
        }
        if (/^title$/.test(field.name)) {
          field.contentTemplate = this._titleContentTemplate;
        }
        if (/^content$/.test(field.name)) {
          field.contentTemplate = this._contentContentTemplate;
        }
        if (/^sender$/.test(field.name)) {
          field.contentTemplate = this._senderContentTemplate;
        }
        if (/^(sendTime)$/.test(field.name)) {
          field.contentTemplate = this._timeContentTemplate;
        }
      });
    });
  }

  /** 查询系统消息列表 */
  _querySystemMessageList(): void {
    validateForm(this._systemMessageSearchForm).subscribe(() => this._getSystemMessageList().subscribe());
  }

  /** 重新查询系统消息列表 */
  _requerySystemMessageList(): void {
    this._systemMessageParams.page = 1;
    this._querySystemMessageList();
  }

  /** 重置系统消息搜索表单 */
  _resetSystemMessageSearchForm(): void {
    this._systemMessageSearchForm.reset();
    this._querySystemMessageList();
  }

  /**
   * 拖拽系统消息字段列表
   * @param event 拖拽事件
   */
  _dropSystemMessageFieldList(event: CdkDragDrop<string[]>): void {
    moveItemInArray(this._systemMessageFieldList, event.previousIndex, event.currentIndex);
  }

  /** 重置系统消息字段列表 */
  _resetSystemMessageFieldList(): void {
    this._systemMessageFieldList = this._systemMessageFieldList
      .map(field => {
        field.visible = field.defaultVisible!;
        field.width = field.defaultWidth;
        return field;
      })
      .sort((fieldA, fieldB) => fieldA.defaultSequence! - fieldB.defaultSequence!);
  }

  /**
   * 改变系统消息字段排序
   * @param field 字段
   */
  _changeSystemMessageFieldSort(field: Field): void {
    const targetField = field;
    this._systemMessageFieldList
      .filter(field => field !== targetField && field.sortOrder)
      .forEach(field => field.sortOrder = null);
    if (field.sortOrder) {
      this._systemMessageParams.sort = field.sortKey + ',' + field.sortOrder.slice(0, -3);
    } else {
      this._systemMessageParams.sort = 'id,desc';
    }
    this._requerySystemMessageList();
  }

  /**
   * 选中所有系统消息列表
   * @param checked 选中状态
   */
  _checkAllSystemMessageList(checked: boolean): void {
    for (const id in this._systemMessageExtras) {
      this._systemMessageExtras[id].checked = checked;
    }
    this._systemMessageAllChecked = checked;
    this._systemMessageIndeterminate = false;
    this._updateSystemMessageHandleHints();
  }

  /** 更新系统消息选中状态 */
  _updateSystemMessageCheckStatus(): void {
    const checkedSystemMessageList = this._systemMessageList.filter(systemMessage => this._systemMessageExtras[systemMessage.id].checked);
    switch (checkedSystemMessageList.length) {
      case 0:
        this._systemMessageAllChecked = false;
        this._systemMessageIndeterminate = false;
        break;
      case this._systemMessageList.length:
        this._systemMessageAllChecked = true;
        this._systemMessageIndeterminate = false;
        break;
      default:
        this._systemMessageAllChecked = false;
        this._systemMessageIndeterminate = true;
    }
    this._updateSystemMessageHandleHints();
  }

  /** 标记系统消息已读 */
  _markSystemMessageAsRead(): void {
    this._markSystemMessageAsReadLoading = true;
    const checkedSystemMessageList = this._systemMessageList.filter(systemMessage => this._systemMessageExtras[systemMessage.id].checked);
    const url = '@' + environment.coreService + '/api/system-message-deliveries/mark-as-read';
    const params: any = { ids: checkedSystemMessageList.map(systemMessage => systemMessage.id) };
    this._httpClient.put(url, null, { params: params, responseType: 'text' })
      .pipe(tap(() => this._querySystemMessageList()))
      .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
        this._nzNotificationService.error('标记已读失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
        return of(undefined);
      }))
      .subscribe(() => {
        this._markSystemMessageAsReadLoading = false;
      });
  }

  /** 更新系统消息已读状态 */
  _updateSystemMessageReadStatus(systemMessage: any): void {
    systemMessage.read = true;
  }

  /** 获取系统消息列表 */
  private _getSystemMessageList(): Observable<HttpErrorResponse | Error | null> {
    this._cancelGetSystemMessageListFn();
    return new Observable(subscriber => {
      if (this._systemMessageSearchForm.valid) {
        this._systemMessageLoading = true;
        const completeGetSystemMessageListFn = () => {
          this._cancelGetSystemMessageListFn = () => { };
          this._systemMessageLoading = false;
        };
        const url = '@' + environment.coreService + '/api/system-message-deliveries';
        const params: any = {
          ...this._systemMessageSearchForm.getRawValue(),
          ...this._systemMessageParams
        };
        for (const key in params) {
          if (!isValid(params[key])) {
            delete params[key];
          }
        }
        if (params.sendTime) {
          params.sendTimeFrom = params.sendTime[0].toISOString();
          params.sendTimeTo = params.sendTime[1].toISOString();
          delete params.sendTime;
        }
        params.page--;
        const getSystemMessageListSubscription = this._httpClient.get<any[]>(url, { params: params, observe: 'response' })
          .pipe(mergeMap(httpResponse => {
            const systemMessageList = httpResponse.body!;
            const systemMessageTotal = Number(httpResponse.headers.get('X-Total-Count'));
            if (systemMessageList.length === 0 && systemMessageTotal > 0) {
              this._systemMessageParams.page = Math.ceil(systemMessageTotal / params.size);
              params.page = this._systemMessageParams.page - 1;
              return this._httpClient.get<any[]>(url, { params: params, observe: 'response' })
                .pipe(map(httpResponse => {
                  const systemMessageList = httpResponse.body!;
                  const systemMessageTotal = Number(httpResponse.headers.get('X-Total-Count'));
                  return { systemMessageList, systemMessageTotal };
                }));
            }
            return of({ systemMessageList, systemMessageTotal });
          }))
          .pipe(tap(() => subscriber.next(null)))
          .pipe(catchError((httpErrorResponse: HttpErrorResponse) => {
            this._nzNotificationService.error('获取系统消息列表失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
            subscriber.next(httpErrorResponse);
            return of({ systemMessageList: [], systemMessageTotal: 0 });
          }))
          .subscribe(({ systemMessageList, systemMessageTotal }) => {
            completeGetSystemMessageListFn();
            const systemMessageExtras: any = {};
            systemMessageList.forEach(systemMessage => {
              systemMessageExtras[systemMessage.id] = {
                checked: false,
                sender: systemMessage.sender && JSON.parse(systemMessage.sender).name
              };
            });
            this._systemMessageList = systemMessageList;
            this._systemMessageTotal = systemMessageTotal;
            this._systemMessageExtras = systemMessageExtras;
            this._systemMessageAllChecked = false;
            this._systemMessageIndeterminate = false;
            this._updateSystemMessageHandleHints();
            subscriber.complete();
          });
        this._cancelGetSystemMessageListFn = () => {
          getSystemMessageListSubscription.unsubscribe();
          completeGetSystemMessageListFn();
          subscriber.next(new Error('取消获取系统消息列表'));
          subscriber.complete();
        };
      } else {
        subscriber.next(new Error('筛选系统消息不合法'));
        subscriber.complete();
      }
    });
  }

  /** 更新系统消息操作提示 */
  private _updateSystemMessageHandleHints(): void {
    const checkedSystemMessageList = this._systemMessageList.filter(systemMessage => this._systemMessageExtras[systemMessage.id].checked);
    if (checkedSystemMessageList.length > 0) {
      this._markSystemMessageAsReadHint = null;
    } else {
      this._markSystemMessageAsReadHint = '未选中系统消息';
    }
  }

}
