<template>
  <v-alert
    v-if="error"
    type="error"
    variant="tonal"
  >
    Error loading data
  </v-alert>

  <template v-else>
    <v-data-table
      :loading="isLoading"
      :items="users"
      :headers="headers"
      :hide-default-footer="hideFooter"
    >
      <template #top>
        <v-toolbar flat>
          <v-toolbar-title>
            <v-icon
              color="medium-emphasis"
              icon="mdi-account-multiple"
              size="x-small"
              start
            />
            Users
          </v-toolbar-title>

          <v-btn
            class="me-2"
            prepend-icon="mdi-plus"
            rounded="lg"
            text="Add a User"
            border
            @click="showDialog(ACTION.ADD)"
            @mouseenter="activator = $event.currentTarget"
          />
        </v-toolbar>
      </template>

      <template #[`item.roles`]="{ value }">
        <div class="d-flex ga-1">
          <v-chip
            v-for="role in value"
            :key="role"
            :color="getRoleColor(role)"
            :text="role"
            size="x-small"
            rounded
          />
        </div>
      </template>

      <template #[`item.actions`]="{ item : user }">
        <div class="d-flex ga-1 justify-end">
          <v-icon-btn
            v-tooltip:bottom="'Change password'"
            icon="mdi-lock-reset"
            @click="showDialog(ACTION.PASSWORD, user)"
            @mouseenter="activator = $event.currentTarget"
          />
          <v-icon-btn
            v-tooltip:bottom="'Edit user'"
            icon="mdi-pencil"
            :disabled="me?.id == user.id"
            @click="showDialog(ACTION.EDIT, user)"
            @mouseenter="activator = $event.currentTarget"
          />
          <v-icon-btn
            v-tooltip:bottom="'Delete user'"
            icon="mdi-delete"
            :disabled="me?.id == user.id"
            @click="showDialog(ACTION.DELETE, user)"
            @mouseenter="activatorDelete = $event.currentTarget"
          />
        </div>
      </template>
    </v-data-table>

    <DialogConfirmEdit
      v-model:record="dialogRecord"
      :activator="activator"
      :title="dialogTitle"
      :subtitle="userRecord?.email"
      :max-width="currentAction === ACTION.PASSWORD ? 400 : 600"
      @update:record="handleDialogConfirmation()"
    >
      <template #text="{proxyModel}">
        <component
          :is="dialogComponent"
          v-model="proxyModel.value"
        />
      </template>
    </DialogConfirmEdit>

    <DialogConfirm
      :activator="activatorDelete"
      :title="dialogTitle"
      :subtitle="userRecord?.email"
      ok-text="Delete"
      :validate-text="userRecord?.email"
      max-width="600"
      @confirm="handleDialogConfirmation()"
    >
      <template #warning>
        <v-alert
          type="warning"
          variant="tonal"
          class="mb-4"
        >
          <div>The user account will be deleted from this server.</div>
          <ul class="ps-8">
            <li>The read progress for this user account will be permanently deleted.</li>
            <li>Authentication activity for this user will be permanently deleted.</li>
          </ul>
          <div class="font-weight-bold mt-4">
            This action cannot be undone.
          </div>
        </v-alert>
      </template>
    </DialogConfirm>
  </template>
</template>

<script lang="ts" setup>
import {useUsers} from '@/colada/queries/users.ts'
import {komgaClient} from '@/api/komga-client.ts'
import type {components} from '@/generated/openapi/komga'
import {useCurrentUser} from '@/colada/queries/current-user.ts'
import {UserRoles} from '@/types/UserRoles.ts'
import {useCreateUser, useDeleteUser, useUpdateUser, useUpdateUserPassword} from '@/colada/mutations/update-user.ts'
import FormUserChangePassword from '@/components/forms/user/FormUserChangePassword.vue'
import FormUserEdit from '@/components/forms/user/FormUserEdit.vue'
import type {Component} from 'vue'
import {useLibraries} from '@/colada/queries/libraries.ts'

// API data
const {data: users, error, isLoading, refetch: refetchUsers} = useUsers()
const {data: me} = useCurrentUser()


// Table
const hideFooter = computed(() => users.value && users.value.length < 11)
const headers = [
  {title: 'Email', key: 'email'},
  {title: 'Latest Activity', key: 'activity', value: (item: components["schemas"]["UserDto"]) => latestActivity[item.id]},
  {title: 'Roles', value: 'roles', sortable: false},
  {title: 'Actions', key: 'actions', align: 'end', sortable: false},
] as const // workaround for https://github.com/vuetifyjs/vuetify/issues/18901

function getRoleColor(role: UserRoles) {
  if(role === UserRoles.ADMIN) return 'error'
}


// store each user's latest activity in a map
// when the 'users' change, we call the API for each user
const latestActivity: Record<string, Date | undefined> = reactive({})

function getLatestActivity(userId: string) {
  komgaClient.GET('/api/v2/users/{id}/authentication-activity/latest', {
    params: {
      path: { id: userId }
    }
  })
    // unwrap the openapi-fetch structure on success
    .then((res) => latestActivity[userId] = res.data?.dateTime)
    .catch(() => {})
}

watch(users, (users) => {
  if(users) for (const user of users) {
    getLatestActivity(user.id)
  }
})

onMounted(() => refetchUsers())


// Dialogs handling
// stores the user being actioned upon
const userRecord = ref<components["schemas"]["UserDto"]>()
// stores the ongoing action, so we can handle the action when the dialog is closed with changes
const currentAction = ref<ACTION>()
// the record passed to the dialog's form's model
const dialogRecord = ref<unknown>()
const activator = ref<Element>()
const activatorDelete = ref<Element>()
const dialogTitle = ref<string>()
// dynamic component for the dialog's inner form
const dialogComponent = shallowRef<Component>()

const {mutate: mutateCreateUser} = useCreateUser()
const {mutate: mutateUser} = useUpdateUser()
const {mutate: mutateUserPassword} = useUpdateUserPassword()
const {mutate: mutateDeleteUser} = useDeleteUser()
const {data: libraries} = useLibraries()

enum ACTION {
  ADD, EDIT, DELETE, PASSWORD
}

function showDialog(action: ACTION, user?: components["schemas"]["UserDto"]) {
  currentAction.value = action
  switch (action) {
    case ACTION.ADD:
      dialogTitle.value = 'Add User'
      dialogComponent.value = FormUserEdit
      dialogRecord.value = {
        email: '',
        password: '',
        roles: [UserRoles.PAGE_STREAMING, UserRoles.FILE_DOWNLOAD],
        sharedLibraries: {
          all: true,
          // we fill the array with all libraries for a nicer display in the edit dialog
          libraryIds: libraries.value?.map(x => x.id) || [],
        },
        ageRestriction: {
          age: 0,
          restriction: 'NONE',
        }
      } as components["schemas"]["UserCreationDto"]
      break;
    case ACTION.EDIT:
      dialogTitle.value = 'Edit User'
      dialogComponent.value = FormUserEdit
      dialogRecord.value = {
        ...user,
        roles: user?.roles.filter(x => x !== 'USER'),
        sharedLibraries: {
          all: user?.sharedAllLibraries,
          // we fill the array with all libraries for a nicer display in the edit dialog
          libraryIds: user?.sharedAllLibraries ? libraries.value?.map(x => x.id) || [] : user?.sharedLibrariesIds,
        },
        ageRestriction: user?.ageRestriction || {
          age: 0,
          restriction: 'NONE',
        }
      } as components["schemas"]["UserUpdateDto"]
      break;
    case ACTION.DELETE:
      dialogTitle.value = 'Delete User'
      dialogComponent.value = FormUserEdit
      dialogRecord.value = user
      break;
    case ACTION.PASSWORD:
      dialogTitle.value = 'Change Password'
      dialogComponent.value = FormUserChangePassword
      // password change initiated with an empty string
      dialogRecord.value = ''
  }
  userRecord.value = user
}

function handleDialogConfirmation() {
  switch (currentAction.value) {
    case ACTION.ADD:
      mutateCreateUser(dialogRecord.value as components["schemas"]["UserCreationDto"])
      break;
    case ACTION.EDIT:
      mutateUser(dialogRecord.value as components["schemas"]["UserDto"])
      break;
    case ACTION.DELETE:
      mutateDeleteUser(userRecord.value!.id)
      break;
    case ACTION.PASSWORD:
      mutateUserPassword({
        userId: userRecord.value!.id,
        newPassword: dialogRecord.value as string,
      })
      break;
  }
}
</script>

<route lang="yaml">
meta:
  requiresRole: ADMIN
</route>
