import { Action, Module, Mutation, VuexModule } from 'vuex-module-decorators'
import { NotifyHelper } from '@/helpers'
import { Task } from '@/widgets/tasks/types/Task'
import { CreateTaskDto } from '@/widgets/tasks/http/dto/CreateTaskDto'
import { CreateNoteDto } from '@/widgets/tasks/http/dto/CreateNoteDto'
import { UpdateTaskDto } from '@/widgets/tasks/http/dto/UpdateTaskDto'
import { AddCommentDto } from '@/widgets/tasks/http/dto/AddCommentDto'
import { LoadTasksPayload } from '@/widgets/tasks/http/dto/LoadTasksPayload'
import { Manager } from '@/types/Manager'
import TaskService from '@/widgets/tasks/http/services/TaskService'
import WebsocketService from '@/widgets/tasks/http/services/WebsocketService'
import AuthService from '@/widgets/tasks/http/services/AuthService'

@Module({
  name: 'TaskModule',
  namespaced: true,
})
export class TaskModule extends VuexModule {
  tasks: Task[] = []

  totalCount = 0
  orderName: string | null = null
  isInitialisedWebsocket = false

  @Mutation
  setInitializeWebsocket() {
    this.isInitialisedWebsocket = true
  }

  @Mutation
  public addTaskToList(task: Task) {
    this.tasks.unshift(task)
  }

  @Mutation
  public updateTaskInList(changedModel: Task) {
    const index = this.tasks.findIndex(task => task.id === changedModel.id)

    this.tasks.splice(index, 1, changedModel)
  }

  @Mutation
  public removeTaskFromList(taskId: number) {
    this.tasks.splice(
      this.tasks.findIndex(task => {
        return task.id === taskId
      }),
      1
    )
  }

  @Mutation
  setOrderName(value: string | null) {
    this.orderName = value
  }

  @Mutation
  setTotalCount(value: number) {
    this.totalCount = value
  }

  @Mutation
  setTasks(tasks: Task[]) {
    this.tasks = tasks
  }

  @Action
  infinityLoadTasks(payload: LoadTasksPayload) {
    const ids = this.tasks.map(task => task.id)

    return TaskService.loadTasks({ ...payload, ids }).then(response => {
      this.setTasks([...this.tasks, ...response.tasks])
      this.setTotalCount(response.totalCount)

      return response.tasks
    })
  }

  @Action
  loadTasks(payload: LoadTasksPayload) {
    return TaskService.loadTasks(payload).then(response => {
      this.setTasks(response.tasks)
      this.setTotalCount(response.totalCount)

      return response.tasks
    })
  }

  @Action
  createTask(dto: CreateTaskDto | CreateNoteDto) {
    return TaskService.createTask(dto)
  }

  @Action
  updateTask(dto: UpdateTaskDto) {
    return TaskService.updateTaskDto(dto).then(task =>
      this.updateTaskInList(task)
    )
  }

  @Action
  removeTask(taskId: number) {
    return TaskService.removeTask(taskId)
      .then(() => this.removeTaskFromList(taskId))
      .catch(() => NotifyHelper.serverError())
  }

  @Action
  toggleStatus(taskId: number) {
    return TaskService.toggleStatus(taskId)
  }

  @Action
  addComment(payload: AddCommentDto) {
    return TaskService.addComment(payload)
      .then(task => this.updateTaskInList(task))
      .catch(() => NotifyHelper.serverError())
  }

  @Action
  async initWebsocket(user: Manager) {
    if (this.isInitialisedWebsocket) {
      return
    }

    this.setInitializeWebsocket()

    try {
      const token = await AuthService.getAuthToken()

      WebsocketService.init(token, user)

      WebsocketService.onCreateTask(payload => {
        this.addTaskToList(payload.task)
      })
      WebsocketService.onUpdateTask(payload => {
        this.updateTaskInList(payload.task)
      })
      WebsocketService.onDeleteTask(payload => {
        this.removeTaskFromList(payload.task.id)
      })
    } catch (e) {
      NotifyHelper.error('Ошибка подключения к сокетам')
    }
  }
}
