import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'

import { ApiRequestError, api } from '../../lib/api'
import type { AdminTeamMember, AdminTeamPermission, AdminTeamRole } from '../../types/awards'

export interface TeamMemberForm {
  login: string
  displayName: string
  role: string
  isActive: boolean
}

const emptyMemberForm = (): TeamMemberForm => ({
  login: '',
  displayName: '',
  role: 'member',
  isActive: true,
})

const TEAM_PRESENCE_REFRESH_MS = 30_000

export function useAdminTeamManager() {
  const loading = ref(true)
  const saving = ref(false)
  const refreshingPresence = ref(false)
  const lastPresenceRefreshAt = ref<Date | null>(null)
  const errorMessage = ref('')
  const successMessage = ref('')
  const generatedPassword = ref('')
  const generatedPasswordLogin = ref('')
  const confirmDeleteMemberId = ref<number | null>(null)
  const members = ref<AdminTeamMember[]>([])
  const roles = ref<AdminTeamRole[]>([])
  const permissions = ref<AdminTeamPermission[]>([])
  const editingMemberId = ref<number | null>(null)
  const rolePermissionDrafts = ref<Record<string, string[]>>({})
  const savedRoleSnapshot = ref('')

  const memberForm = reactive<TeamMemberForm>(emptyMemberForm())

  const activeMembers = computed(() => members.value.filter((member) => member.isActive).length)
  const pendingPasswordChanges = computed(() => members.value.filter((member) => member.mustChangePassword).length)
  const roleOptions = computed(() => roles.value.map((role) => ({ value: role.key, label: role.label })))
  const permissionGroups = computed(() => {
    const grouped = new Map<string, AdminTeamPermission[]>()
    for (const permission of permissions.value) {
      const key = permission.groupLabel || 'Sonstiges'
      const current = grouped.get(key)
      if (current) current.push(permission)
      else grouped.set(key, [permission])
    }

    return [...grouped.entries()].map(([label, items]) => ({
      label,
      items,
    }))
  })
  const selectedMember = computed(() => members.value.find((member) => member.id === editingMemberId.value) ?? null)
  const assignableRoleOptions = computed(() => roleOptions.value.filter((role) =>
    role.value !== 'creator' || selectedMember.value?.role === 'creator',
  ))
  const hasRoleChanges = computed(() =>
    Boolean(savedRoleSnapshot.value) && JSON.stringify(rolePermissionDrafts.value) !== savedRoleSnapshot.value,
  )

  function resetMessages() {
    errorMessage.value = ''
    successMessage.value = ''
  }

  function applyTeamResponse(response: { members: AdminTeamMember[]; roles: AdminTeamRole[]; permissions: AdminTeamPermission[] }) {
    members.value = response.members
    roles.value = response.roles
    permissions.value = response.permissions
    rolePermissionDrafts.value = Object.fromEntries(
      response.roles.map((role) => [role.key, [...role.permissionKeys]]),
    )
    savedRoleSnapshot.value = JSON.stringify(rolePermissionDrafts.value)
  }

  async function loadTeam(options: { silent?: boolean } = {}) {
    const silent = options.silent === true
    const showLoading = !silent || members.value.length === 0

    if (showLoading) {
      loading.value = true
    } else {
      refreshingPresence.value = true
    }

    if (!silent) {
      resetMessages()
    }

    try {
      applyTeamResponse(await api.getAdminTeam())
      lastPresenceRefreshAt.value = new Date()
    } catch (error) {
      if (!silent) {
        errorMessage.value = error instanceof ApiRequestError
          ? error.message
          : 'Team-Daten konnten nicht geladen werden.'
      }
    } finally {
      if (showLoading) {
        loading.value = false
      }
      refreshingPresence.value = false
    }
  }

  function startCreateMember() {
    editingMemberId.value = null
    Object.assign(memberForm, emptyMemberForm())
    generatedPassword.value = ''
    generatedPasswordLogin.value = ''
    resetMessages()
  }

  function startEditMember(member: AdminTeamMember) {
    editingMemberId.value = member.id
    memberForm.login = member.login
    memberForm.displayName = member.displayName
    memberForm.role = member.role
    memberForm.isActive = member.isActive
    generatedPassword.value = ''
    generatedPasswordLogin.value = ''
    resetMessages()
  }

  function validateMemberForm() {
    if (!memberForm.login.trim() && editingMemberId.value === null) {
      errorMessage.value = 'Bitte gib einen Login an.'
      return false
    }

    if (!memberForm.displayName.trim()) {
      errorMessage.value = 'Bitte gib einen Anzeigenamen an.'
      return false
    }

    return true
  }

  async function saveMember() {
    resetMessages()
    generatedPassword.value = ''
    generatedPasswordLogin.value = ''

    if (!validateMemberForm()) return false

    saving.value = true
    try {
      if (editingMemberId.value === null) {
        const result = await api.createAdminTeamMember({
          login: memberForm.login,
          displayName: memberForm.displayName,
          role: memberForm.role,
        })
        await loadTeam({ silent: true })
        generatedPassword.value = result.generatedPassword
        generatedPasswordLogin.value = memberForm.login
        successMessage.value = 'Team-Login wurde erstellt. Das temporäre Passwort ist nur jetzt sichtbar.'
      } else {
        await api.updateAdminTeamMember(editingMemberId.value, {
          login: memberForm.login,
          displayName: memberForm.displayName,
          role: memberForm.role,
          isActive: memberForm.isActive,
        })
        await loadTeam({ silent: true })
        successMessage.value = 'Team-Mitglied wurde gespeichert.'
      }
      return true
    } catch (error) {
      errorMessage.value = error instanceof ApiRequestError
        ? error.message
        : 'Team-Mitglied konnte nicht gespeichert werden.'
      return false
    } finally {
      saving.value = false
    }
  }

  async function resetMemberPassword(member: AdminTeamMember) {
    resetMessages()
    generatedPassword.value = ''
    generatedPasswordLogin.value = ''
    saving.value = true

    try {
      const result = await api.resetAdminTeamMemberPassword(member.id)
      await loadTeam({ silent: true })
      generatedPassword.value = result.generatedPassword
      generatedPasswordLogin.value = member.login
      successMessage.value = 'Passwort wurde zurückgesetzt. Das Mitglied muss es beim nächsten Login ändern.'
    } catch (error) {
      errorMessage.value = error instanceof ApiRequestError
        ? error.message
        : 'Passwort konnte nicht zurückgesetzt werden.'
    } finally {
      saving.value = false
    }
  }

  function requestDeleteMember(member: AdminTeamMember) {
    confirmDeleteMemberId.value = member.id
    resetMessages()
  }

  function cancelDeleteMember() {
    confirmDeleteMemberId.value = null
  }

  async function deleteMember(member: AdminTeamMember) {
    resetMessages()
    generatedPassword.value = ''
    generatedPasswordLogin.value = ''
    saving.value = true

    try {
      await api.deleteAdminTeamMember(member.id)
      confirmDeleteMemberId.value = null
      if (editingMemberId.value === member.id) {
        startCreateMember()
      }
      await loadTeam({ silent: true })
      successMessage.value = 'Team-Mitglied wurde gelöscht.'
    } catch (error) {
      errorMessage.value = error instanceof ApiRequestError
        ? error.message
        : 'Team-Mitglied konnte nicht gelöscht werden.'
    } finally {
      saving.value = false
    }
  }

  function roleHasPermission(roleKey: string, permissionKey: string) {
    return rolePermissionDrafts.value[roleKey]?.includes(permissionKey) ?? false
  }

  function setRolePermission(roleKey: string, permissionKey: string, checked: boolean) {
    if (roleKey === 'owner') return

    const current = new Set(rolePermissionDrafts.value[roleKey] ?? [])
    if (checked) {
      current.add(permissionKey)
    } else {
      current.delete(permissionKey)
    }

    rolePermissionDrafts.value = {
      ...rolePermissionDrafts.value,
      [roleKey]: [...current].sort(),
    }
  }

  async function saveRolePermissions() {
    resetMessages()
    saving.value = true

    try {
      const result = await api.updateAdminTeamRoles({
        roles: roles.value.map((role) => ({
          key: role.key,
          permissionKeys: rolePermissionDrafts.value[role.key] ?? [],
        })),
      })
      roles.value = result.roles
      savedRoleSnapshot.value = JSON.stringify(rolePermissionDrafts.value)
      successMessage.value = 'Rollen und Berechtigungen wurden gespeichert.'
    } catch (error) {
      errorMessage.value = error instanceof ApiRequestError
        ? error.message
        : 'Berechtigungen konnten nicht gespeichert werden.'
    } finally {
      saving.value = false
    }
  }

  let presenceRefreshTimer: ReturnType<typeof window.setInterval> | null = null

  onMounted(() => {
    void loadTeam()
    presenceRefreshTimer = window.setInterval(() => {
      if (!saving.value) {
        void loadTeam({ silent: true })
      }
    }, TEAM_PRESENCE_REFRESH_MS)
  })

  onBeforeUnmount(() => {
    if (presenceRefreshTimer) {
      window.clearInterval(presenceRefreshTimer)
      presenceRefreshTimer = null
    }
  })

  return {
    loading,
    saving,
    refreshingPresence,
    lastPresenceRefreshAt,
    errorMessage,
    successMessage,
    generatedPassword,
    generatedPasswordLogin,
    confirmDeleteMemberId,
    members,
    roles,
    permissions,
    permissionGroups,
    memberForm,
    editingMemberId,
    selectedMember,
    activeMembers,
    pendingPasswordChanges,
    roleOptions,
    assignableRoleOptions,
    hasRoleChanges,
    loadTeam,
    startCreateMember,
    startEditMember,
    saveMember,
    resetMemberPassword,
    requestDeleteMember,
    cancelDeleteMember,
    deleteMember,
    roleHasPermission,
    setRolePermission,
    saveRolePermissions,
  }
}
