import { NgTemplateOutlet, SlicePipe } from '@angular/common'
import { Component, inject, OnDestroy, OnInit } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router'
import {
  NgbCollapseModule,
  NgbDropdownModule,
  NgbModal,
  NgbNavModule,
  NgbPaginationModule,
  NgbPopoverModule,
} from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import {
  debounceTime,
  distinctUntilChanged,
  filter,
  first,
  Subject,
  takeUntil,
  timer,
} from 'rxjs'
import { PaperlessTask } from 'src/app/data/paperless-task'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { TasksService } from 'src/app/services/tasks.service'
import { ToastService } from 'src/app/services/toast.service'
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
import { PageHeaderComponent } from '../../common/page-header/page-header.component'
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'

export enum TaskTab {
  Queued = 'queued',
  Started = 'started',
  Completed = 'completed',
  Failed = 'failed',
}

enum TaskFilterTargetID {
  Name,
  Result,
}

const FILTER_TARGETS = [
  { id: TaskFilterTargetID.Name, name: $localize`Name` },
  { id: TaskFilterTargetID.Result, name: $localize`Result` },
]

@Component({
  selector: 'pngx-tasks',
  templateUrl: './tasks.component.html',
  styleUrls: ['./tasks.component.scss'],
  imports: [
    PageHeaderComponent,
    IfPermissionsDirective,
    CustomDatePipe,
    SlicePipe,
    FormsModule,
    ReactiveFormsModule,
    NgTemplateOutlet,
    NgbCollapseModule,
    NgbDropdownModule,
    NgbNavModule,
    NgbPaginationModule,
    NgbPopoverModule,
    NgxBootstrapIconsModule,
  ],
})
export class TasksComponent
  extends LoadingComponentWithPermissions
  implements OnInit, OnDestroy
{
  tasksService = inject(TasksService)
  private modalService = inject(NgbModal)
  private readonly router = inject(Router)
  private readonly toastService = inject(ToastService)

  public activeTab: TaskTab
  public selectedTasks: Set<number> = new Set()
  public togggleAll: boolean = false
  public expandedTask: number

  public pageSize: number = 25
  public page: number = 1

  public autoRefreshEnabled: boolean = true

  private _filterText: string = ''
  get filterText() {
    return this._filterText
  }
  set filterText(value: string) {
    this.filterDebounce.next(value)
  }

  public filterTargetID: TaskFilterTargetID = TaskFilterTargetID.Name
  public get filterTargetName(): string {
    return this.filterTargets.find((t) => t.id == this.filterTargetID).name
  }
  private filterDebounce: Subject<string> = new Subject<string>()

  public get filterTargets(): Array<{ id: number; name: string }> {
    return [TaskTab.Failed, TaskTab.Completed].includes(this.activeTab)
      ? FILTER_TARGETS
      : FILTER_TARGETS.slice(0, 1)
  }

  get dismissButtonText(): string {
    return this.selectedTasks.size > 0
      ? $localize`Dismiss selected`
      : $localize`Dismiss all`
  }

  ngOnInit() {
    this.tasksService.reload()
    timer(5000, 5000)
      .pipe(
        filter(() => this.autoRefreshEnabled),
        takeUntil(this.unsubscribeNotifier)
      )
      .subscribe(() => {
        this.tasksService.reload()
      })

    this.filterDebounce
      .pipe(
        takeUntil(this.unsubscribeNotifier),
        debounceTime(100),
        distinctUntilChanged(),
        filter((query) => !query.length || query.length > 2)
      )
      .subscribe((query) => (this._filterText = query))
  }

  ngOnDestroy() {
    super.ngOnDestroy()
    this.tasksService.cancelPending()
  }

  dismissTask(task: PaperlessTask) {
    this.dismissTasks(task)
  }

  dismissTasks(task: PaperlessTask = undefined) {
    let tasks = task ? new Set([task.id]) : new Set(this.selectedTasks.values())
    if (!task && tasks.size == 0)
      tasks = new Set(this.tasksService.allFileTasks.map((t) => t.id))
    if (tasks.size > 1) {
      let modal = this.modalService.open(ConfirmDialogComponent, {
        backdrop: 'static',
      })
      modal.componentInstance.title = $localize`Confirm Dismiss All`
      modal.componentInstance.messageBold = $localize`Dismiss all ${tasks.size} tasks?`
      modal.componentInstance.btnClass = 'btn-warning'
      modal.componentInstance.btnCaption = $localize`Dismiss`
      modal.componentInstance.confirmClicked.pipe(first()).subscribe(() => {
        modal.componentInstance.buttonsEnabled = false
        modal.close()
        this.tasksService.dismissTasks(tasks).subscribe({
          error: (e) => {
            this.toastService.showError($localize`Error dismissing tasks`, e)
            modal.componentInstance.buttonsEnabled = true
          },
        })
        this.clearSelection()
      })
    } else {
      this.tasksService.dismissTasks(tasks).subscribe({
        error: (e) =>
          this.toastService.showError($localize`Error dismissing task`, e),
      })
      this.clearSelection()
    }
  }

  dismissAndGo(task: PaperlessTask) {
    this.dismissTask(task)
    this.router.navigate(['documents', task.related_document])
  }

  expandTask(task: PaperlessTask) {
    this.expandedTask = this.expandedTask == task.id ? undefined : task.id
  }

  toggleSelected(task: PaperlessTask) {
    this.selectedTasks.has(task.id)
      ? this.selectedTasks.delete(task.id)
      : this.selectedTasks.add(task.id)
  }

  get currentTasks(): PaperlessTask[] {
    let tasks: PaperlessTask[] = []
    switch (this.activeTab) {
      case TaskTab.Queued:
        tasks = this.tasksService.queuedFileTasks
        break
      case TaskTab.Started:
        tasks = this.tasksService.startedFileTasks
        break
      case TaskTab.Completed:
        tasks = this.tasksService.completedFileTasks
        break
      case TaskTab.Failed:
        tasks = this.tasksService.failedFileTasks
        break
    }
    if (this._filterText.length) {
      tasks = tasks.filter((t) => {
        if (this.filterTargetID == TaskFilterTargetID.Name) {
          return t.task_file_name
            .toLowerCase()
            .includes(this._filterText.toLowerCase())
        } else if (this.filterTargetID == TaskFilterTargetID.Result) {
          return t.result.toLowerCase().includes(this._filterText.toLowerCase())
        }
      })
    }
    return tasks
  }

  toggleAll(event: PointerEvent) {
    if ((event.target as HTMLInputElement).checked) {
      this.selectedTasks = new Set(this.currentTasks.map((t) => t.id))
    } else {
      this.clearSelection()
    }
  }

  clearSelection() {
    this.togggleAll = false
    this.selectedTasks.clear()
  }

  duringTabChange() {
    this.page = 1
  }

  beforeTabChange() {
    this.resetFilter()
    this.filterTargetID = TaskFilterTargetID.Name
  }

  get activeTabLocalized(): string {
    switch (this.activeTab) {
      case TaskTab.Queued:
        return $localize`queued`
      case TaskTab.Started:
        return $localize`started`
      case TaskTab.Completed:
        return $localize`completed`
      case TaskTab.Failed:
        return $localize`failed`
    }
  }

  public resetFilter() {
    this._filterText = ''
  }

  filterInputKeyup(event: KeyboardEvent) {
    if (event.key == 'Enter') {
      this._filterText = (event.target as HTMLInputElement).value
    } else if (event.key === 'Escape') {
      this.resetFilter()
    }
  }
}
