<template>
  <div>
    <div class="flex items-center justify-between pb-12">
      <h1 class="text-4xl font-bold text-primary-500">Utilisateurs</h1>
      <button
        type="button"
        class="rounded-lg bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500"
        @click="openCreate"
      >
        Ajouter un utilisateur
      </button>
    </div>

    <div
      v-if="!isLoading && users.length === 0"
      class="rounded-lg border border-neutral-200 bg-white p-6 text-md text-neutral-600"
    >
      Aucun utilisateur pour le moment.
    </div>

    <div v-else class="max-h-[80vh] overflow-auto rounded-lg border border-neutral-200 bg-white">
      <div class="grid grid-cols-[1fr_1fr_140px_1fr_140px] gap-4 border-b border-neutral-200 bg-tertiary-500 px-6 py-3 text-md font-semibold text-neutral-700">
        <span class="text-left">Utilisateur</span>
        <span class="text-left">Employé</span>
        <span class="text-left">Accès</span>
        <span class="text-left">Sites</span>
        <span class="text-right">Actions</span>
      </div>
      <div v-if="isLoading" class="px-6 py-4 text-md text-neutral-500">
        Chargement...
      </div>
      <div v-else>
        <div
          v-for="user in users"
          :key="user.id"
          class="grid grid-cols-[1fr_1fr_140px_1fr_140px] items-center gap-4 border-b border-neutral-100 px-6 py-3 text-md text-neutral-800 last:border-b-0"
        >
          <span class="text-left">{{ user.username }}</span>
          <span class="text-left">
            {{ user.employee ? `${user.employee.firstName} ${user.employee.lastName}` : '-' }}
          </span>
          <span class="text-left text-sm text-neutral-600">
            {{ getAccessLabel(user) }}
          </span>
          <span class="text-left text-sm text-neutral-600">
            {{ getSiteLabels(user) }}
          </span>
          <div class="flex justify-end">
            <button
              type="button"
              class="rounded-md border border-neutral-200 px-2 py-1 text-md font-semibold text-neutral-700 hover:bg-neutral-100"
              @click="openEdit(user)"
            >
              Modifier
            </button>
          </div>
        </div>
      </div>
    </div>

    <AppDrawer
      v-model="isDrawerOpen"
      :title="editingUser ? 'Modifier un utilisateur' : 'Ajouter un utilisateur'"
    >
      <form class="space-y-4" @submit.prevent="handleSubmit">
        <div>
          <label class="text-md font-semibold text-neutral-700" for="username">
            Nom d'utilisateur <span class="text-red-600">*</span>
          </label>
          <input
            id="username"
            v-model="form.username"
            type="text"
            :class="usernameFieldClass"
          />
          <p v-if="showUsernameError" class="mt-1 text-sm text-red-600">
            Le nom d'utilisateur est obligatoire.
          </p>
        </div>

        <div>
          <label class="text-md font-semibold text-neutral-700" for="password">
            Mot de passe
            <span v-if="!editingUser" class="text-red-600">*</span>
          </label>
          <input
            id="password"
            v-model="form.password"
            type="password"
            :class="passwordFieldClass"
          />
          <p v-if="editingUser" class="mt-1 text-sm text-neutral-500">
            Laisse vide pour ne pas changer le mot de passe.
          </p>
          <p v-else-if="showPasswordError" class="mt-1 text-sm text-red-600">
            Le mot de passe est obligatoire.
          </p>
        </div>

        <div>
          <p class="text-md font-semibold text-neutral-700">Accès</p>
          <div class="mt-2 flex flex-wrap gap-2">
            <button
              type="button"
              class="rounded-full border px-3 py-1 text-sm font-semibold"
              :class="form.accessMode === 'admin' ? 'border-primary-500 bg-tertiary-500 text-primary-500' : 'border-neutral-200 text-neutral-700'"
              @click="selectAccessMode('admin')"
            >
              Admin
            </button>
            <button
              type="button"
              class="rounded-full border px-3 py-1 text-sm font-semibold"
              :class="form.accessMode === 'self' ? 'border-primary-500 bg-tertiary-500 text-primary-500' : 'border-neutral-200 text-neutral-700'"
              @click="selectAccessMode('self')"
            >
              Accès personnel
            </button>
            <button
              type="button"
              class="rounded-full border px-3 py-1 text-sm font-semibold"
              :class="form.accessMode === 'sites' ? 'border-primary-500 bg-tertiary-500 text-primary-500' : 'border-neutral-200 text-neutral-700'"
              @click="selectAccessMode('sites')"
            >
              Sites
            </button>
          </div>
          <p class="mt-2 text-sm text-neutral-500">
            {{
              form.accessMode === 'admin'
                ? 'Donne accès à tout.'
                : form.accessMode === 'self'
                  ? "Donne accès uniquement à ses propres données."
                  : 'Donne accès aux employés des sites sélectionnés.'
            }}
          </p>
        </div>

        <div v-if="form.accessMode === 'self'">
          <label class="text-md font-semibold text-neutral-700" for="employee">
            Employé lié
          </label>
          <select
            id="employee"
            v-model="form.employeeId"
            class="mt-2 w-full rounded-md border border-neutral-300 bg-white px-3 py-2 text-md text-neutral-900"
          >
            <option value="">Aucun</option>
            <option v-for="employee in employees" :key="employee.id" :value="employee.id">
              {{ employee.firstName }} {{ employee.lastName }}
            </option>
          </select>
          <p v-if="showSelfEmployeeError" class="mt-1 text-sm text-red-600">
            Sélectionne un employé.
          </p>
        </div>

        <div v-if="form.accessMode === 'sites'">
          <p class="text-md font-semibold text-neutral-700">Sites autorisés</p>
          <div class="mt-2 grid gap-2 sm:grid-cols-2">
            <label
              v-for="site in sites"
              :key="site.id"
              class="flex items-center gap-2 rounded-md border border-neutral-200 px-3 py-2 text-sm text-neutral-700 cursor-pointer"
            >
              <input
                type="checkbox"
                class="cursor-pointer"
                :checked="form.siteIds.includes(site.id)"
                @change="toggleSite(site.id)"
              />
              <span>{{ site.name }}</span>
            </label>
          </div>
          <p v-if="showSitesError" class="mt-1 text-sm text-red-600">
            Sélectionne au moins un site.
          </p>
        </div>

        <div class="flex justify-end gap-3 pt-2">
          <button
            type="button"
            class="rounded-lg border border-neutral-200 px-4 py-2 text-md font-semibold text-neutral-700 hover:bg-neutral-100"
            @click="closeDrawer"
          >
            Annuler
          </button>
          <button
            type="submit"
            class="rounded-lg bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500"
            :class="submitButtonClass"
          >
            Enregistrer
          </button>
        </div>
      </form>
    </AppDrawer>
  </div>
</template>

<script setup lang="ts">
import type { Employee } from '~/services/dto/employee'
import type { Site } from '~/services/dto/site'
import type { User } from '~/services/dto/user'
import type { UserSiteRole } from '~/services/user-site-roles'
import { listEmployees } from '~/services/employees'
import { listSites } from '~/services/sites'
import { createUser, listUsers, updateUser } from '~/services/users'
import { createUserSiteRole, deleteUserSiteRole, listUserSiteRoles } from '~/services/user-site-roles'

definePageMeta({ middleware: ['admin'] })

const users = ref<User[]>([])
const employees = ref<Employee[]>([])
const sites = ref<Site[]>([])
const userSiteRoles = ref<UserSiteRole[]>([])
const isLoading = ref(false)
const isDrawerOpen = ref(false)
const isSubmitting = ref(false)
const editingUser = ref<User | null>(null)

const form = reactive({
  username: '',
  password: '',
  accessMode: 'admin' as 'admin' | 'self' | 'sites',
  employeeId: '' as number | '',
  siteIds: [] as number[]
})

const validationTouched = reactive({
  username: false,
  password: false,
  sites: false,
  selfEmployee: false
})

const isUsernameValid = computed(() => form.username.trim() !== '')
const isPasswordValid = computed(() =>
  editingUser.value ? true : form.password.trim() !== ''
)
const isFormValid = computed(() => isUsernameValid.value && isPasswordValid.value)
const isSitesValid = computed(() => form.siteIds.length > 0)
const isSelfEmployeeValid = computed(() => form.employeeId !== '')

const showUsernameError = computed(
  () => validationTouched.username && !isUsernameValid.value
)
const showPasswordError = computed(
  () => validationTouched.password && !isPasswordValid.value
)
const showSitesError = computed(
  () => validationTouched.sites && form.accessMode === 'sites' && !isSitesValid.value
)
const showSelfEmployeeError = computed(
  () =>
    validationTouched.selfEmployee &&
    form.accessMode === 'self' &&
    !isSelfEmployeeValid.value
)

const userAccessById = computed(() => {
  const rolesByUser = new Map<number, UserSiteRole[]>()
  for (const role of userSiteRoles.value) {
    const userId = role.user?.id
    if (!userId) continue
    const list = rolesByUser.get(userId) ?? []
    list.push(role)
    rolesByUser.set(userId, list)
  }

  return rolesByUser
})

const getAccessLabel = (user: User) => {
  if (user.roles.includes('ROLE_ADMIN')) return 'Admin'
  if (user.roles.includes('ROLE_SELF')) return 'Self'
  const siteRoles = userAccessById.value.get(user.id) ?? []
  return siteRoles.length > 0 ? 'Sites' : 'Aucun'
}

const getSiteLabels = (user: User) => {
  const siteRoles = userAccessById.value.get(user.id) ?? []
  if (siteRoles.length === 0) return '-'
  const names = siteRoles
    .map((role) => role.site?.name)
    .filter((name): name is string => Boolean(name))
  return names.length > 0 ? names.join(', ') : 'Sites sélectionnés'
}

const baseInputClass =
  'mt-2 w-full rounded-md border px-3 py-2 text-base text-neutral-900 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-secondary-500/20'
const usernameFieldClass = computed(() => {
  if (showUsernameError.value) {
    return `${baseInputClass} border-red-500`
  }
  return `${baseInputClass} border-neutral-300`
})
const passwordFieldClass = computed(() => {
  if (showPasswordError.value) {
    return `${baseInputClass} border-red-500`
  }
  return `${baseInputClass} border-neutral-300`
})

const submitButtonClass = computed(() => {
  if (isSubmitting.value || !isFormValid.value) {
    return 'opacity-50 cursor-not-allowed'
  }
  return ''
})

const loadData = async () => {
  isLoading.value = true
  try {
  const [usersData, employeesData, sitesData, userSiteRolesData] = await Promise.all([
    listUsers(),
    listEmployees(),
    listSites(),
    listUserSiteRoles()
  ])
  users.value = usersData
  employees.value = employeesData
  sites.value = sitesData
  userSiteRoles.value = userSiteRolesData
} finally {
    isLoading.value = false
  }
}

onMounted(loadData)

const resetForm = () => {
  form.username = ''
  form.password = ''
  form.employeeId = ''
  form.accessMode = 'admin'
  form.siteIds = []
  editingUser.value = null
  validationTouched.username = false
  validationTouched.password = false
  validationTouched.sites = false
  validationTouched.selfEmployee = false
}

const openCreate = () => {
  resetForm()
  isDrawerOpen.value = true
}

const openEdit = (user: User) => {
  resetForm()
  editingUser.value = user
  form.username = user.username
  form.password = ''

  if (user.roles.includes('ROLE_ADMIN')) {
    selectAccessMode('admin')
  } else if (user.roles.includes('ROLE_SELF')) {
    selectAccessMode('self')
  } else {
    selectAccessMode('sites')
  }

  form.employeeId = user.employee?.id ?? ''

  const siteRoles = userAccessById.value.get(user.id) ?? []
  form.siteIds = siteRoles.map((role) => role.site?.id).filter((id): id is number => typeof id === 'number')
  isDrawerOpen.value = true
}

const closeDrawer = () => {
  isDrawerOpen.value = false
  resetForm()
}

const selectAccessMode = (mode: 'admin' | 'self' | 'sites') => {
  form.accessMode = mode
  if (mode !== 'sites') {
    form.siteIds = []
  }
}

const toggleSite = (siteId: number) => {
  if (form.siteIds.includes(siteId)) {
    form.siteIds = form.siteIds.filter((existing) => existing !== siteId)
  } else {
    form.siteIds = [...form.siteIds, siteId]
  }
}

const handleSubmit = async () => {
  if (isSubmitting.value) return
  validationTouched.username = true
  validationTouched.password = true
  validationTouched.sites = true
  validationTouched.selfEmployee = true
  if (!isFormValid.value) return
  if (form.accessMode === 'sites' && !isSitesValid.value) return
  if (form.accessMode === 'self' && !isSelfEmployeeValid.value) return

  isSubmitting.value = true
  try {
    const roles =
      form.accessMode === 'admin'
        ? ['ROLE_ADMIN']
        : form.accessMode === 'self'
          ? ['ROLE_SELF']
          : []

    const employeeId =
      form.accessMode === 'self' ? (form.employeeId === '' ? null : Number(form.employeeId)) : null

    if (editingUser.value) {
      await updateUser(editingUser.value.id, {
        username: form.username,
        plainPassword: form.password.trim() ? form.password : undefined,
        roles,
        employeeId
      })

      const existingSiteRoles = userAccessById.value.get(editingUser.value.id) ?? []
      if (existingSiteRoles.length > 0) {
        await Promise.all(existingSiteRoles.map((role) => deleteUserSiteRole(role.id)))
      }

      if (form.accessMode === 'sites' && form.siteIds.length > 0) {
        await Promise.all(
          form.siteIds.map((siteId) =>
            createUserSiteRole({
              userId: editingUser.value!.id,
              siteId,
              role: 'SITE_ACCESS'
            })
          )
        )
      }
    } else {
      const created = await createUser({
        username: form.username,
        plainPassword: form.password,
        roles,
        employeeId
      })

      if (form.accessMode === 'sites' && form.siteIds.length > 0) {
        await Promise.all(
          form.siteIds.map((siteId) =>
            createUserSiteRole({
              userId: created.id,
              siteId,
              role: 'SITE_ACCESS'
            })
          )
        )
      }
    }

    closeDrawer()
    await loadData()
  } finally {
    isSubmitting.value = false
  }
}
</script>
