<template>
  <div class="h-full flex flex-col overflow-hidden">
    <div class="flex items-center justify-between pb-6">
      <h1 class="text-2xl font-bold text-primary-500 lg:text-4xl">Utilisateurs</h1>
      <MalioButton
        label="Ajouter"
        icon-name="mdi:plus"
        icon-position="left"
        @click="openCreate"
      />
    </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>

    <!-- Desktop table -->
    <div v-else class="min-h-0 overflow-auto rounded-md bg-white hidden lg:block">
      <div class="grid grid-cols-5 gap-4 border border-black bg-tertiary-500 px-6 py-3 text-[20px] font-semibold text-black rounded-t-md sticky top-0 z-10">
        <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-left">Statut</span>
      </div>
      <div v-if="isLoading" class="px-6 py-4 text-md text-neutral-500">
        Chargement...
      </div>
      <div v-else class="border-x border-b border-primary-500 rounded-b-md">
        <div
          v-for="user in users"
          :key="user.id"
          class="grid grid-cols-5 items-center gap-4 border-b border-primary-500 px-6 py-3 text-md font-bold text-primary-500 last:border-b-0 cursor-pointer hover:bg-tertiary-500"
          @click="openEdit(user)"
        >
          <span>{{ user.username }}</span>
          <span>
            {{ user.employee ? `${user.employee.firstName} ${user.employee.lastName}` : '-' }}
          </span>
          <span>{{ getAccessLabel(user) }}</span>
          <span>{{ getSiteLabels(user) }}</span>
          <span>
            <span
              v-if="user.isLocked"
              class="inline-block rounded-full bg-red-100 px-3 py-1 text-sm font-semibold text-red-700"
            >Verrouillé</span>
            <span
              v-else
              class="inline-block rounded-full bg-green-100 px-3 py-1 text-sm font-semibold text-green-700"
            >Actif</span>
          </span>
        </div>
      </div>
    </div>

    <!-- Mobile cards -->
    <div v-if="isLoading" class="px-6 py-4 text-md text-neutral-500 lg:hidden">
      Chargement...
    </div>
    <div v-else-if="users.length > 0" class="min-h-0 overflow-auto space-y-3 lg:hidden">
      <div
        v-for="user in users"
        :key="'m-' + user.id"
        class="rounded-md border border-primary-500 bg-white p-4 cursor-pointer active:bg-tertiary-500"
        @click="openEdit(user)"
      >
        <div class="flex items-center justify-between gap-2 mb-2">
          <p class="text-md font-bold text-primary-500 truncate">{{ user.username }}</p>
          <span
            v-if="user.isLocked"
            class="shrink-0 inline-block rounded-full bg-red-100 px-3 py-1 text-xs font-semibold text-red-700"
          >Verrouillé</span>
          <span
            v-else
            class="shrink-0 inline-block rounded-full bg-green-100 px-3 py-1 text-xs font-semibold text-green-700"
          >Actif</span>
        </div>
        <div class="space-y-1 text-sm">
          <p v-if="user.employee" class="text-neutral-600">
            {{ user.employee.firstName }} {{ user.employee.lastName }}
          </p>
          <p class="text-neutral-500">
            Accès : <span class="font-semibold text-primary-500">{{ getAccessLabel(user) }}</span>
          </p>
          <p v-if="getSiteLabels(user) !== '-'" class="text-neutral-500 truncate">
            Sites : <span class="font-semibold text-primary-500">{{ getSiteLabels(user) }}</span>
          </p>
        </div>
      </div>
    </div>

    <MalioDrawer
      v-model="isDrawerOpen"
      :title="editingUser ? 'Modifier un utilisateur' : 'Ajouter un utilisateur'"
    >
      <form class="space-y-4" @submit.prevent="handleSubmit">
        <MalioInputText
          v-model="form.username"
          :label="editingUser ? `Nom d'utilisateur` : `Nom d'utilisateur *`"
          group-class="mt-2"
          :error="showUsernameError ? `Le nom d'utilisateur est obligatoire.` : ''"
        />

        <div>
          <MalioInputPassword
            v-model="form.password"
            :label="editingUser ? 'Mot de passe' : 'Mot de passe *'"
            :hint="editingUser ? 'Laisse vide pour ne pas changer le mot de passe.' : ''"
            :error="!editingUser && showPasswordError ? 'Le mot de passe est obligatoire.' : ''"
          />
        </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'">
          <MalioSelect
            :model-value="form.employeeId === '' ? null : form.employeeId"
            :options="employeeOptions"
            label="Employé lié"
            empty-option-label="Aucun"
            min-width=""
            :error="showSelfEmployeeError ? 'Sélectionne un employé.' : ''"
            @update:model-value="onEmployeeChange"
          />
        </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">
            <div
              v-for="site in sites"
              :key="site.id"
              class="flex h-10 items-center rounded-md border border-neutral-200 px-3"
            >
              <MalioCheckbox
                :model-value="form.siteIds.includes(site.id)"
                :label="site.name"
                group-class="flex items-center"
                @update:model-value="toggleSite(site.id)"
              />
            </div>
          </div>
          <p v-if="showSitesError" class="mt-1 text-sm text-red-600">
            Sélectionne au moins un site.
          </p>
        </div>

        <div>
          <MalioCheckbox
            v-model="form.isLocked"
            label="Verrouiller le compte"
            hint="Un compte verrouillé ne peut plus se connecter."
          />
        </div>

        <div>
          <MalioCheckbox
            v-model="form.hasLeaveRecapAccess"
            label="Accès à l'écran Récap. congés"
            hint="Affiche l'onglet dans la sidebar et donne accès au tableau récap."
          />
        </div>

        <div class="flex justify-center pt-2">
          <MalioButton
            type="submit"
            :label="editingUser ? 'Modifier' : 'Valider'"
            button-class="w-[200px]"
            :disabled="isSubmitting || !isFormValid"
          />
        </div>
      </form>
    </MalioDrawer>
  </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'] })
useHead({
    title: 'Utilisateurs'
})

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[],
  isLocked: false,
  hasLeaveRecapAccess: false
})

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 employeeOptions = computed(() =>
  employees.value.map((e) => ({ label: `${e.firstName} ${e.lastName}`, value: e.id }))
)

const onEmployeeChange = (value: string | number | null) => {
  form.employeeId = value === null ? '' : Number(value)
}

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 = []
  form.isLocked = false
  form.hasLeaveRecapAccess = false
  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 ?? ''
  form.isLocked = user.isLocked
  form.hasLeaveRecapAccess = user.hasLeaveRecapAccess ?? false

  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,
        isLocked: form.isLocked,
        hasLeaveRecapAccess: form.hasLeaveRecapAccess
      })

      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,
        isLocked: form.isLocked,
        hasLeaveRecapAccess: form.hasLeaveRecapAccess
      })

      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>
