import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit, OnDestroy } from '@angular/core';
import { Router } from '@angular/router';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { finalize } from 'rxjs/operators';

import { Mute } from '../../../pojo/Mute';
import { SingleAlert } from '../../../pojo/SingleAlert';
import { AlertSoundService } from '../../../service/alert-sound.service';
import { AlertService } from '../../../service/alert.service';
import { GeneralConfigService } from '../../../service/general-config.service';

@Component({
  selector: 'header-notify',
  template: `
    <div style="display: flex; align-items: center;">
      <ng-template #badgeTpl>
        <nz-badge [nzCount]="count" ngClass="alain-default__nav-item" [nzStyle]="{ 'box-shadow': 'none' }">
          <i nz-icon nzType="bell" ngClass="alain-default__nav-item-icon"></i>
        </nz-badge>
      </ng-template>
      @if (data!.length <= 0) {
      <ng-template [ngTemplateOutlet]="badgeTpl" />
      } @else {
      <div
        nz-dropdown
        (nzVisibleChange)="onPopoverVisibleChange($event)"
        [(nzVisible)]="popoverVisible"
        nzTrigger="click"
        nzPlacement="bottomRight"
        nzOverlayClassName="header-dropdown notice-icon"
        [nzDropdownMenu]="noticeMenu"
      >
        <ng-template [ngTemplateOutlet]="badgeTpl" />
      </div>
      }
      <nz-badge ngClass="alain-default__nav-item" [nzStyle]="{ 'box-shadow': 'none' }">
        <i
          nz-icon
          [nzType]="mute.mute ? 'muted' : 'sound'"
          ngClass="alain-default__nav-item-icon"
          (click)="toggleMute($event)"
          nz-tooltip
          nzTooltipPlacement="bottom"
          [nzTooltipTitle]="(mute.mute ? 'common.unmute' : 'common.mute') | i18n"
        ></i>
      </nz-badge>
    </div>
    <nz-dropdown-menu #noticeMenu="nzDropdownMenu">
      @if (data[0].title) {
      <div class="ant-modal-title" style="line-height: 44px; text-align: center;">{{ data[0].title }}</div>
      }
      <nz-spin [nzSpinning]="loading" [nzDelay]="0">
        @if (data[0].list && data[0].list.length > 0) {
        <ng-template [ngTemplateOutlet]="listTpl" />
        } @else {
        <div class="notice-icon__notfound">
          @if (data[0].emptyImage) {
          <img class="notice-icon__notfound-img" [attr.src]="data[0].emptyImage" alt="not found" />
          }
          <p>
            <ng-container *nzStringTemplateOutlet="data[0].emptyText">
              {{ data[0].emptyText }}
            </ng-container>
          </p>
        </div>
        }
      </nz-spin>
      <div style="display: flex; align-items: center; border-top: 1px solid #f0f0f0;">
        <div class="notice-icon__clear" style="flex: 1; border-top: none;" (click)="gotoAlertCenter()">{{ data[0].enterText }}</div>
      </div>
    </nz-dropdown-menu>
    <ng-template #listTpl>
      <nz-list [nzDataSource]="data[0].list" [nzRenderItem]="item">
        <ng-template #item let-item>
          <nz-list-item [class.notice-icon__item-read]="item.read">
            <nz-list-item-meta [nzTitle]="nzTitle" [nzDescription]="nzDescription" [nzAvatar]="item.avatar">
              <ng-template #nzTitle>
                <ng-container *nzStringTemplateOutlet="item.title; context: { $implicit: item }">
                  <a (click)="gotoDetail(item.id)">{{ item.title }}</a>
                </ng-container>
                @if (item.extra) {
                <div class="notice-icon__item-extra">
                  <nz-tag [nzColor]="item.color">{{ item.extra }}</nz-tag>
                </div>
                }
              </ng-template>
              <ng-template #nzDescription>
                @if (item.description) {
                <div class="notice-icon__item-desc">
                  <ng-container *nzStringTemplateOutlet="item.description; context: { $implicit: item }">
                    {{ item.description }}
                  </ng-container>
                </div>
                } @if (item.datetime) {
                <div class="notice-icon__item-time">{{ item.datetime }}</div>
                }
              </ng-template>
            </nz-list-item-meta>
          </nz-list-item>
        </ng-template>
      </nz-list>
    </ng-template>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class HeaderNotifyComponent implements OnInit, OnDestroy {
  data: any[] = [
    {
      title: this.i18nSvc.fanyi('dashboard.alerts.title-no'),
      list: [],
      emptyText: this.i18nSvc.fanyi('dashboard.alerts.no'),
      emptyImage: '/assets/img/empty-full.svg',
      enterText: this.i18nSvc.fanyi('dashboard.alerts.enter'),
      clearText: this.i18nSvc.fanyi('alert.center.clear')
    }
  ];
  notifiedAlert: any[] = [];
  count = 0;
  loading = false;
  popoverVisible = false;
  refreshInterval: any;
  private previousCount = 0;
  // default to mute status
  mute: Mute = { mute: true };
  private eventSource!: EventSource;
  constructor(
    private router: Router,
    @Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService,
    private notifySvc: NzNotificationService,
    private configSvc: GeneralConfigService,
    private alertSvc: AlertService,
    private modal: NzModalService,
    private cdr: ChangeDetectorRef,
    private alertSound: AlertSoundService
  ) {}

  ngOnInit(): void {
    let muteInit$ = this.configSvc
      .getGeneralConfig('mute')
      .pipe(
        finalize(() => {
          muteInit$.unsubscribe();
        })
      )
      .subscribe(
        message => {
          if (message.code === 0) {
            this.mute = message.data;
          } else {
            console.warn(message.msg);
          }
        },
        error => {
          console.error(error);
        }
      );
    this.loadData();
    this.initAlertSSEConnection();
    this.initManagerSSEConnection();
  }

  ngOnDestroy() {
    if (this.refreshInterval) {
      clearInterval(this.refreshInterval);
    }
    if (this.eventSource) {
      this.eventSource.close();
    }
  }

  onPopoverVisibleChange(visible: boolean): void {
    if (visible) {
      this.loadData();
    }
  }

  updateNoticeData(notices: any[]): any[] {
    const data = this.data.slice();
    data.forEach(i => (i.list = []));

    notices.forEach(item => {
      data[0].list.push({ ...item });
    });
    return data;
  }

  loadData(): void {
    if (this.loading) {
      return;
    }
    this.loading = true;
    let loadAlerts$ = this.alertSvc
      .loadAlerts('firing', undefined, 0, 5)
      .pipe(
        finalize(() => {
          loadAlerts$.unsubscribe();
          this.loading = false;
        })
      )
      .subscribe(
        message => {
          if (message.code === 0) {
            let page = message.data;
            let alerts = page.content;
            if (alerts == undefined) {
              return;
            }
            let list: any[] = [];
            alerts.forEach(alert => {
              let item = {
                id: alert.id,
                avatar: '/assets/img/notification.svg',
                title: alert.content,
                datetime: new Date(alert.activeAt).toLocaleString(),
                color: 'blue',
                status: alert.status,
                type: this.i18nSvc.fanyi('dashboard.alerts.title-no')
              };
              list.push(item);
            });
            this.data = this.updateNoticeData(list);
            this.count = page.totalElements;
          } else {
            console.warn(message.msg);
          }
          this.cdr.detectChanges();
        },
        error => {
          console.error(error);
        }
      );
  }

  gotoAlertCenter(): void {
    this.popoverVisible = false;
    this.router.navigateByUrl(`/alert/center`);
  }

  gotoDetail(id: number): void {
    this.popoverVisible = false;
    // todo goto this alert detail pop page
    // this.router.navigateByUrl(`/alarm/center/detail/${id}`);
  }

  toggleMute(event: MouseEvent): void {
    event.stopPropagation();
    const updatedMuteState = !this.mute.mute;
    const updatedMuteConfig = { ...this.mute, mute: updatedMuteState };
    // request notification permission
    debugger;
    if (!updatedMuteState) {
      Notification.requestPermission().then(permission => {
        if (permission !== 'granted') {
          console.log('Notification permission denied.');
        }
      });
    }

    let saveConfig$ = this.configSvc
      .saveGeneralConfig(updatedMuteConfig, 'mute')
      .pipe(
        finalize(() => {
          saveConfig$.unsubscribe();
        })
      )
      .subscribe({
        next: response => {
          if (response.code === 0) {
            this.mute = updatedMuteConfig;
            console.log('Config saved successfully', response);
          } else {
            console.warn('Error saving config', response.msg);
          }
        },
        error: error => {
          console.error('Error saving config', error);
        },
        complete: () => {
          this.cdr.markForCheck();
        }
      });
  }

  private initAlertSSEConnection(): void {
    const sseUrl = '/api/alert/sse/subscribe';

    this.eventSource = new EventSource(sseUrl);

    this.eventSource.addEventListener('ALERT_EVENT', (evt: MessageEvent) => {
      let list: any[] = [];
      let alert: SingleAlert = JSON.parse(evt.data);
      let item = {
        id: alert.id,
        avatar: '/assets/img/notification.svg',
        // title: `${alert.tags?.monitorName}--${this.i18nSvc.fanyi(`alert.severity.${alert.severity}`)}`,
        title: alert.content,
        datetime: new Date(alert.activeAt).toLocaleString(),
        color: 'blue',
        status: alert.status,
        type: this.i18nSvc.fanyi('dashboard.alerts.title-no')
      };
      console.log('alert:', alert);
      list.push(item);
      this.data = this.updateNoticeData(list);
      if (!this.mute.mute && !this.notifiedAlert.includes(alert.id)) {
        this.notifiedAlert.push(alert.id);
        this.alertSound.playAlertSound(this.i18nSvc.currentLang);
        const notification = new Notification(this.i18nSvc.fanyi('alert.notify.title'), {
          body: this.i18nSvc.fanyi('alert.notify.body'),
          icon: 'assets/logo.svg'
        });
        notification.onclick = () => {
          window.focus();
          this.router.navigateByUrl(`/alert/center`);
          notification.close();
        };
      }
      this.cdr.detectChanges();
    });
    this.eventSource.onerror = error => {
      console.error('SSE connection error:', error);
      this.eventSource.close();
    };
  }

  private initManagerSSEConnection(): void {
    const sseUrl = '/api/manager/sse/subscribe';
    this.eventSource = new EventSource(sseUrl);
    this.eventSource.addEventListener('IMPORT_TASK_EVENT', (evt: MessageEvent) => {
      let msg = JSON.parse(evt.data);
      if (msg.notifyLevel === 'SUCCESS') {
        this.notifySvc.success(
          this.i18nSvc.fanyi('common.notice'),
          this.i18nSvc.fanyi('common.notify.import-success-detail', { taskName: msg.taskName })
        );
      } else if (msg.notifyLevel === 'ERROR') {
        this.notifySvc.error(
          this.i18nSvc.fanyi('common.notice'),
          this.i18nSvc.fanyi('common.notify.import-fail-detail', { taskName: msg.taskName, errMsg: msg.errMsg })
        );
      } else if (msg.notifyLevel === 'INFO') {
        this.notifySvc.info(
          this.i18nSvc.fanyi('common.notice'),
          this.i18nSvc.fanyi('common.notify.import-progress', { taskName: msg.taskName, progress: msg.progress })
        );
      } else {
        console.error('Parse message error, msg:', evt.data);
      }
    });
    this.eventSource.onerror = error => {
      console.error('Manager SSE connection error:', error);
      this.eventSource.close();
    };
  }
}
