<template>
  <q-page class="users-page">
    <div class="users-shell">
      <header class="users-header">
        <div>
          <p class="eyebrow">Admin</p>
          <h1>Users</h1>
          <p class="subtitle">
            Gestione completa degli utenti con profilo, dettagli anagrafici e preferenze.
          </p>
        </div>

        <div class="header-actions">
          <q-btn
            flat
            color="primary"
            icon="refresh"
            label="Aggiorna"
            :loading="loading"
            @click="loadUsers"
          />
          <q-btn color="primary" icon="person_add" label="Nuovo utente" @click="openCreateDialog" />
        </div>
      </header>

      <q-card flat bordered class="users-card">
        <q-card-section class="toolbar">
          <q-input
            v-model="filter"
            outlined
            dense
            clearable
            debounce="200"
            placeholder="Cerca per nome, email, ruoli, lingua"
            class="toolbar-search"
          >
            <template #prepend>
              <q-icon name="search" />
            </template>
          </q-input>
        </q-card-section>

        <q-separator />

        <q-table
          flat
          :rows="rows"
          :columns="columns"
          row-key="uuid"
          :loading="loading"
          :filter="filter"
          v-model:pagination="pagination"
          :rows-per-page-options="[10, 20, 50, 100]"
          @request="onTableRequest"
          binary-state-sort
          wrap-cells
        >
          <template #body-cell-name="props">
            <q-td :props="props">
              <div class="user-cell">
                <div class="user-avatar-thumb">
                  <img
                    v-if="props.row.avatar"
                    :src="props.row.avatar"
                    :alt="props.row.name"
                  />
                  <span v-else>{{ avatarInitials(props.row) }}</span>
                </div>
                <div class="user-meta">
                  <div class="text-weight-medium">{{ props.row.name }}</div>
                  <div class="text-caption text-grey-7">{{ props.row.email }}</div>
                </div>
              </div>
            </q-td>
          </template>

          <template #body-cell-status="props">
            <q-td :props="props">
              <q-badge :color="statusColor(props.row.status)" text-color="white" :label="props.row.status" />
            </q-td>
          </template>

          <template #body-cell-roles="props">
            <q-td :props="props">
              <div class="badge-row">
                <q-badge
                  v-for="role in props.row.roles"
                  :key="`${props.row.uuid}-${role}`"
                  color="blue-8"
                  text-color="white"
                  :label="role"
                />
              </div>
            </q-td>
          </template>

          <template #body-cell-details="props">
            <q-td :props="props">
              <div>{{ fullName(props.row) }}</div>
              <div class="text-caption text-grey-7">
                {{ props.row.details?.city || 'Nessuna citta' }}
              </div>
            </q-td>
          </template>

          <template #body-cell-preferences="props">
            <q-td :props="props">
              <div>{{ props.row.preferences?.language || 'n/a' }}</div>
              <div class="text-caption text-grey-7">
                Idle: {{ props.row.preferences?.useIdle ? 'on' : 'off' }}
              </div>
            </q-td>
          </template>

          <template #body-cell-actions="props">
            <q-td :props="props" class="actions-cell">
              <q-btn flat round dense icon="more_vert" color="grey-8">
                <q-menu anchor="bottom right" self="top right">
                  <q-list dense class="user-action-menu">
                    <q-item clickable v-close-popup @click="openViewDialog(props.row.uuid)">
                      <q-item-section avatar>
                        <q-icon name="visibility" />
                      </q-item-section>
                      <q-item-section>Show</q-item-section>
                    </q-item>
                    <q-item clickable v-close-popup @click="openEditDialog(props.row.uuid)">
                      <q-item-section avatar>
                        <q-icon name="edit" />
                      </q-item-section>
                      <q-item-section>Edit</q-item-section>
                    </q-item>
                    <q-item clickable v-close-popup @click="openAvatarDialog(props.row.uuid)">
                      <q-item-section avatar>
                        <q-icon name="add_a_photo" />
                      </q-item-section>
                      <q-item-section>Edit avatar</q-item-section>
                    </q-item>
                    <q-item clickable v-close-popup @click="openPasswordDialog(props.row.uuid)">
                      <q-item-section avatar>
                        <q-icon name="password" />
                      </q-item-section>
                      <q-item-section>Change password</q-item-section>
                    </q-item>
                    <q-item clickable v-close-popup @click="openBlockDialog(props.row)">
                      <q-item-section avatar>
                        <q-icon
                          :name="props.row.status === EnumUserStatus.UserStatusDisabled ? 'lock_open' : 'block'"
                          :color="props.row.status === EnumUserStatus.UserStatusDisabled ? 'positive' : 'negative'"
                        />
                      </q-item-section>
                      <q-item-section>
                        {{ props.row.status === EnumUserStatus.UserStatusDisabled ? 'Unblock user' : 'Block user' }}
                      </q-item-section>
                    </q-item>
                  </q-list>
                </q-menu>
              </q-btn>
            </q-td>
          </template>

          <template #no-data>
            <div class="full-width row flex-center q-pa-lg text-grey-7">
              Nessun utente disponibile.
            </div>
          </template>
        </q-table>
      </q-card>
    </div>

    <q-dialog v-model="dialogOpen">
      <q-card class="editor-card modal-card">
        <q-form class="form-grid" @submit.prevent="saveUser">
          <q-card-section class="editor-header">
            <div class="editor-toolbar">
              <div class="editor-headline">
                <div class="text-overline">{{ dialogMode === 'create' ? 'Nuovo utente' : dialogMode === 'edit' ? 'Modifica utente' : 'Dettaglio utente' }}</div>
                <div class="text-h5">{{ form.name || 'Profilo utente' }}</div>
                <div class="text-caption">{{ form.email || 'Compila i dati di base' }}</div>
              </div>
            </div>

            <div class="editor-toolbar-actions">
              <q-btn flat color="white" label="Chiudi" v-close-popup />
              <q-btn
                v-if="dialogMode !== 'view'"
                color="white"
                text-color="primary"
                unelevated
                :loading="saving"
                :label="dialogMode === 'create' ? 'Crea utente' : 'Salva modifiche'"
                type="submit"
              />
            </div>

            <q-tabs
              v-model="editorTab"
              dense
              align="left"
              inline-label
              active-color="primary"
              indicator-color="primary"
              class="editor-tabs"
            >
              <q-tab name="account" icon="person" label="Account" />
              <q-tab name="details" icon="badge" label="Details" />
              <q-tab name="preferences" icon="tune" label="Preferences" />
            </q-tabs>
          </q-card-section>

          <q-separator />

          <q-card-section class="editor-body">
            <q-tab-panels v-model="editorTab" animated class="editor-panels">
              <q-tab-panel name="account">
                <section class="form-section">
                  <h2>Account</h2>
                  <div class="section-grid">
                    <q-input v-model="form.name" outlined label="Nome" :readonly="dialogMode === 'view'" />
                    <q-input v-model="form.email" outlined label="Email" type="email" :readonly="dialogMode === 'view'" />
                    <q-input
                      v-if="dialogMode === 'create'"
                      v-model="form.password"
                      outlined
                      label="Password"
                      type="password"
                      hint="Minimo 8 caratteri"
                    />
                    <div v-if="dialogMode !== 'create'" class="avatar-inline-card span-2">
                      <div class="avatar-inline-preview">
                        <img v-if="form.avatar" :src="form.avatar" :alt="form.name" />
                        <span v-else>{{ avatarInitials(form) }}</span>
                      </div>
                      <div class="avatar-inline-meta">
                        <div class="text-subtitle2">Avatar</div>
                        <div class="text-caption text-grey-7">
                          {{ form.avatar ? 'Avatar profilo impostato' : 'Nessun avatar impostato' }}
                        </div>
                      </div>
                      <q-btn
                        v-if="dialogMode === 'edit'"
                        flat
                        color="primary"
                        icon="add_a_photo"
                        label="Modifica"
                        @click="openAvatarDialog(form.uuid)"
                      />
                    </div>
                    <q-input v-else v-model="form.avatar" outlined label="Avatar URL" />
                    <q-select
                      v-model="form.status"
                      outlined
                      label="Status"
                      :options="statusOptions"
                      :readonly="dialogMode === 'view'"
                    />
                    <q-select
                      v-model="form.roles"
                      outlined
                      multiple
                      use-input
                      use-chips
                      new-value-mode="add-unique"
                      label="Roles"
                      :options="roleOptions"
                      :readonly="dialogMode === 'view'"
                    />
                    <q-select
                      v-model="form.types"
                      outlined
                      multiple
                      use-input
                      use-chips
                      new-value-mode="add-unique"
                      label="Types"
                      :options="typeOptions"
                      :readonly="dialogMode === 'view'"
                    />
                  </div>
                </section>
              </q-tab-panel>

              <q-tab-panel name="details">
                <section class="form-section">
                  <div class="section-heading">
                    <h2>Details</h2>
                    <q-toggle
                      v-model="detailsEnabled"
                      label="Abilita details"
                      :disable="dialogMode === 'view'"
                    />
                  </div>
                  <div class="section-grid" :class="{ disabled: !detailsEnabled }">
                    <q-input v-model="form.details.title" outlined label="Title" :disable="!detailsEnabled || dialogMode === 'view'" />
                    <q-input v-model="form.details.firstName" outlined label="First name" :disable="!detailsEnabled || dialogMode === 'view'" />
                    <q-input v-model="form.details.lastName" outlined label="Last name" :disable="!detailsEnabled || dialogMode === 'view'" />
                    <q-input v-model="form.details.phone" outlined label="Phone" :disable="!detailsEnabled || dialogMode === 'view'" />
                    <q-input v-model="form.details.address" outlined label="Address" class="span-2" :disable="!detailsEnabled || dialogMode === 'view'" />
                    <q-input v-model="form.details.city" outlined label="City" :disable="!detailsEnabled || dialogMode === 'view'" />
                    <q-input v-model="form.details.zipCode" outlined label="Zip code" :disable="!detailsEnabled || dialogMode === 'view'" />
                    <q-input v-model="form.details.country" outlined label="Country" :disable="!detailsEnabled || dialogMode === 'view'" />
                  </div>
                </section>
              </q-tab-panel>

              <q-tab-panel name="preferences">
                <section class="form-section">
                  <div class="section-heading">
                    <h2>Preferences</h2>
                    <q-toggle
                      v-model="preferencesEnabled"
                      label="Abilita preferences"
                      :disable="dialogMode === 'view'"
                    />
                  </div>
                  <div class="section-grid" :class="{ disabled: !preferencesEnabled }">
                    <q-input v-model="form.preferences.language" outlined label="Language" :disable="!preferencesEnabled || dialogMode === 'view'" />
                    <q-input
                      v-model.number="form.preferences.idleTimeout"
                      outlined
                      type="number"
                      label="Idle timeout"
                      :disable="!preferencesEnabled || dialogMode === 'view'"
                    />
                    <q-input v-model="form.preferences.idlePin" outlined label="Idle pin" :disable="!preferencesEnabled || dialogMode === 'view'" />
                    <q-toggle v-model="form.preferences.useIdle" label="Use idle" :disable="!preferencesEnabled || dialogMode === 'view'" />
                    <q-toggle v-model="form.preferences.useIdlePassword" label="Use idle password" :disable="!preferencesEnabled || dialogMode === 'view'" />
                    <q-toggle v-model="form.preferences.useDirectLogin" label="Use direct login" :disable="!preferencesEnabled || dialogMode === 'view'" />
                    <q-toggle v-model="form.preferences.useQuadcodeLogin" label="Use quadcode login" :disable="!preferencesEnabled || dialogMode === 'view'" />
                    <q-toggle v-model="form.preferences.sendNoticesMail" label="Send notices mail" :disable="!preferencesEnabled || dialogMode === 'view'" />
                  </div>
                </section>
              </q-tab-panel>
            </q-tab-panels>
          </q-card-section>
        </q-form>
      </q-card>
    </q-dialog>

    <q-dialog v-model="passwordDialogOpen">
      <q-card class="password-card modal-card">
        <q-card-section>
          <div class="text-overline text-primary">Change password</div>
          <div class="text-h6">{{ passwordDialogUserEmail || 'User' }}</div>
        </q-card-section>

        <q-separator />

        <q-card-section class="password-grid">
          <q-input
            v-model="passwordForm.password"
            outlined
            type="password"
            label="New password"
            hint="Minimo 8 caratteri"
          />
          <q-input
            v-model="passwordForm.confirmPassword"
            outlined
            type="password"
            label="Confirm password"
          />
        </q-card-section>

        <q-card-actions align="right">
          <q-btn flat color="grey-7" label="Chiudi" v-close-popup />
          <q-btn
            color="primary"
            label="Salva password"
            :loading="saving"
            @click="savePasswordChange"
          />
        </q-card-actions>
      </q-card>
    </q-dialog>

    <q-dialog v-model="blockDialogOpen">
      <q-card class="password-card modal-card">
        <q-card-section>
          <div class="text-overline text-primary">User access</div>
          <div class="text-h6">{{ blockDialogUser.email || 'User' }}</div>
          <div class="text-caption">
            Stato attuale: {{ blockDialogUser.status || 'n/a' }}
          </div>
        </q-card-section>

        <q-separator />

        <q-card-section class="password-grid">
          <q-toggle
            v-model="blockDialogBlocked"
            checked-icon="block"
            unchecked-icon="lock_open"
            color="negative"
            :label="blockDialogBlocked ? 'Utente bloccato' : 'Utente attivo'"
          />
          <div class="text-body2 text-grey-7">
            {{
              blockDialogBlocked
                ? 'L’utente non potra piu accedere finche non verra sbloccato.'
                : 'L’utente potra accedere normalmente.'
            }}
          </div>
        </q-card-section>

        <q-card-actions align="right">
          <q-btn flat color="grey-7" label="Chiudi" v-close-popup />
          <q-btn
            color="primary"
            :loading="saving"
            :label="blockDialogBlocked ? 'Salva blocco' : 'Salva sblocco'"
            @click="saveBlockState"
          />
        </q-card-actions>
      </q-card>
    </q-dialog>

    <q-dialog v-model="avatarDialogOpen">
      <q-card class="editor-card modal-card">
        <q-card-section class="editor-header">
          <div class="editor-toolbar">
            <div class="editor-headline">
              <div class="text-overline">Avatar editor</div>
              <div class="text-h5">{{ avatarDialogUser.email || 'User avatar' }}</div>
              <div class="text-caption">Ritaglio circolare per il profilo utente</div>
            </div>
          </div>

          <div class="editor-toolbar-actions">
            <q-btn flat color="white" label="Chiudi" v-close-popup />
            <q-btn
              color="white"
              text-color="primary"
              unelevated
              :disable="!avatarSource"
              :loading="saving"
              label="Salva avatar"
              @click="saveAvatar"
            />
          </div>
        </q-card-section>

        <q-separator />

        <q-card-section class="avatar-editor-body">
          <div class="avatar-toolbar">
            <input
              ref="avatarFileInputRef"
              class="visually-hidden"
              type="file"
              accept="image/*"
              @change="onAvatarFileSelected"
            />

            <q-btn
              color="primary"
              icon="upload"
              label="Carica immagine"
              @click="openAvatarFilePicker"
            />

            <div class="avatar-file-name">
              {{ avatarFile?.name || 'Nessun file selezionato' }}
            </div>

            <q-btn
              flat
              color="primary"
              icon="restart_alt"
              label="Reset crop"
              :disable="!avatarSource"
              @click="resetAvatarCrop"
            />
          </div>

          <div class="avatar-editor-grid">
            <div class="avatar-cropper-shell">
              <div v-if="avatarSource" class="avatar-cropper-box">
                <VuePictureCropper
                  ref="avatarCropperRef"
                  :img="avatarSource"
                  :box-style="avatarCropperBoxStyle"
                  :options="avatarCropperOptions"
                  :preset-mode="avatarPresetMode"
                />
              </div>
              <div v-else class="avatar-empty-state">
                Seleziona un’immagine per modificare l’avatar.
              </div>
            </div>

            <div class="avatar-preview-shell">
              <div class="avatar-preview-title">Anteprima</div>
              <div class="avatar-preview-disc">
                <img v-if="avatarPreview" :src="avatarPreview" alt="Avatar preview" />
                <span v-else>No avatar</span>
              </div>
            </div>
          </div>
        </q-card-section>
      </q-card>
    </q-dialog>
  </q-page>
</template>

<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue';
import { useQuasar, type QTableColumn, type QTableProps } from 'quasar';
import VuePictureCropper from 'vue-picture-cropper';

import {
  blockUser,
  createUser,
  getUser,
  listUsers,
  updateUser,
  EnumUserStatus,
  type BlockUserRequest,
  type ListUsersRequest,
  type UpdateUserRequest,
  type UserCreateInput,
  type UserDetailsShort,
  type UserPreferencesShort,
  type UserProfile,
  type UserShort,
  type UserStatus,
} from 'src/api/api';

type DialogMode = 'create' | 'edit' | 'view';

interface UserFormState {
  uuid: string;
  name: string;
  email: string;
  password: string;
  status: UserStatus;
  roles: string[];
  types: string[];
  avatar: string;
  details: UserDetailsShort;
  preferences: UserPreferencesShort;
}

const $q = useQuasar();
const loading = ref(false);
const saving = ref(false);
const dialogOpen = ref(false);
const passwordDialogOpen = ref(false);
const blockDialogOpen = ref(false);
const avatarDialogOpen = ref(false);
const dialogMode = ref<DialogMode>('create');
const editorTab = ref<'account' | 'details' | 'preferences'>('account');
const filter = ref('');
const rows = ref<UserShort[]>([]);
const detailsEnabled = ref(true);
const preferencesEnabled = ref(true);
const passwordDialogUserUuid = ref('');
const passwordDialogUserEmail = ref('');
const blockDialogUser = reactive({
  uuid: '',
  email: '',
  status: '' as UserStatus | '',
});
const blockDialogBlocked = ref(false);
const avatarDialogUser = reactive({
  uuid: '',
  email: '',
});
const avatarFile = ref<File | null>(null);
const avatarFileInputRef = ref<HTMLInputElement | null>(null);
const avatarSource = ref('');
const avatarPreview = ref('');
const avatarCropperRef = ref<{ cropper?: { getDataURL?: (options?: { width?: number; height?: number; rounded?: boolean }) => string; reset?: () => void } } | null>(null);
const pagination = ref<QTableProps['pagination']>({
  sortBy: 'name',
  descending: false,
  page: 1,
  rowsPerPage: 10,
  rowsNumber: 0,
});

const statusOptions = Object.values(EnumUserStatus);
const roleOptions = ['admin', 'manager', 'user'];
const typeOptions = ['internal', 'external'];
const avatarCropperBoxStyle = {
  width: '100%',
  height: '100%',
  backgroundColor: '#f3f7fb',
  margin: '0 auto',
};
const avatarPresetMode = {
  mode: 'round',
  width: 320,
  height: 320,
} as const;

const columns: QTableColumn<UserShort>[] = [
  { name: 'name', label: 'Utente', field: 'name', align: 'left', sortable: true },
  { name: 'status', label: 'Status', field: 'status', align: 'left', sortable: true },
  { name: 'roles', label: 'Roles', field: (row) => row.roles.join(', '), align: 'left' },
  { name: 'details', label: 'Details', field: (row) => fullName(row), align: 'left' },
  { name: 'preferences', label: 'Preferences', field: (row) => row.preferences?.language ?? '', align: 'left' },
  { name: 'actions', label: '', field: 'uuid', align: 'right' },
];

const form = reactive<UserFormState>(emptyForm());
const passwordForm = reactive({
  password: '',
  confirmPassword: '',
});

const payload = computed<UserCreateInput | UpdateUserRequest>(() => ({
  name: form.name.trim(),
  email: form.email.trim(),
  password: dialogMode.value === 'create' ? form.password : '',
  status: form.status,
  roles: sanitizeList(form.roles),
  types: sanitizeList(form.types),
  avatar: normalizeNullableString(form.avatar),
  details: detailsEnabled.value ? sanitizeDetails(form.details) : null,
  preferences: preferencesEnabled.value ? sanitizePreferences(form.preferences) : null,
}));

onMounted(async () => {
  await loadUsers();
});

function emptyForm(): UserFormState {
  return {
    uuid: '',
    name: '',
    email: '',
    password: '',
    status: EnumUserStatus.UserStatusPending,
    roles: ['user'],
    types: ['internal'],
    avatar: '',
    details: {
      title: '',
      firstName: '',
      lastName: '',
      address: '',
      city: '',
      zipCode: '',
      country: '',
      phone: '',
    },
    preferences: {
      useIdle: false,
      idleTimeout: 0,
      useIdlePassword: false,
      idlePin: '',
      useDirectLogin: false,
      useQuadcodeLogin: false,
      sendNoticesMail: false,
      language: 'it',
    },
  };
}

function resetForm(user?: UserProfile): void {
  const next = user ? mapUserToForm(user) : emptyForm();
  Object.assign(form, next);
  detailsEnabled.value = !!user?.details || !user;
  preferencesEnabled.value = !!user?.preferences || !user;
}

function mapUserToForm(user: UserProfile): UserFormState {
  return {
    uuid: user.uuid,
    name: user.name,
    email: user.email,
    password: '',
    status: user.status,
    roles: [...user.roles],
    types: [...user.types],
    avatar: user.avatar ?? '',
    details: {
      title: user.details?.title ?? '',
      firstName: user.details?.firstName ?? '',
      lastName: user.details?.lastName ?? '',
      address: user.details?.address ?? '',
      city: user.details?.city ?? '',
      zipCode: user.details?.zipCode ?? '',
      country: user.details?.country ?? '',
      phone: user.details?.phone ?? '',
    },
    preferences: {
      useIdle: user.preferences?.useIdle ?? false,
      idleTimeout: user.preferences?.idleTimeout ?? 0,
      useIdlePassword: user.preferences?.useIdlePassword ?? false,
      idlePin: user.preferences?.idlePin ?? '',
      useDirectLogin: user.preferences?.useDirectLogin ?? false,
      useQuadcodeLogin: user.preferences?.useQuadcodeLogin ?? false,
      sendNoticesMail: user.preferences?.sendNoticesMail ?? false,
      language: user.preferences?.language ?? 'it',
    },
  };
}

function sanitizeList(values: string[]): string[] {
  return values.map((value) => value.trim()).filter(Boolean);
}

function normalizeNullableString(value: string): string | null {
  const normalized = value.trim();
  return normalized === '' ? null : normalized;
}

function sanitizeDetails(value: UserDetailsShort): UserDetailsShort | null {
  const normalized: UserDetailsShort = {
    title: value.title.trim(),
    firstName: value.firstName.trim(),
    lastName: value.lastName.trim(),
    address: value.address.trim(),
    city: value.city.trim(),
    zipCode: value.zipCode.trim(),
    country: value.country.trim(),
    phone: value.phone.trim(),
  };

  return Object.values(normalized).some(Boolean) ? normalized : null;
}

function sanitizePreferences(value: UserPreferencesShort): UserPreferencesShort | null {
  const normalized: UserPreferencesShort = {
    useIdle: value.useIdle,
    idleTimeout: Number(value.idleTimeout) || 0,
    useIdlePassword: value.useIdlePassword,
    idlePin: value.idlePin.trim(),
    useDirectLogin: value.useDirectLogin,
    useQuadcodeLogin: value.useQuadcodeLogin,
    sendNoticesMail: value.sendNoticesMail,
    language: value.language.trim(),
  };

  const hasData =
    normalized.useIdle ||
    normalized.idleTimeout > 0 ||
    normalized.useIdlePassword ||
    normalized.idlePin !== '' ||
    normalized.useDirectLogin ||
    normalized.useQuadcodeLogin ||
    normalized.sendNoticesMail ||
    normalized.language !== '';

  return hasData ? normalized : null;
}

function syncAvatarPreview(): void {
  avatarPreview.value =
    avatarCropperRef.value?.cropper?.getDataURL?.({
      width: 220,
      height: 220,
      rounded: true,
    }) || avatarSource.value;
}

const avatarCropperOptions = {
  viewMode: 1 as const,
  dragMode: 'move' as const,
  aspectRatio: 1,
  autoCropArea: 0.9,
  background: false,
  movable: true,
  zoomable: true,
  scalable: false,
  guides: false,
  ready: () => {
    syncAvatarPreview();
  },
  crop: () => {
    syncAvatarPreview();
  },
};

function buildUpdatePayload(user: UserProfile, password = ''): UpdateUserRequest {
  return {
    name: user.name,
    email: user.email,
    password,
    status: user.status,
    roles: [...user.roles],
    types: [...user.types],
    avatar: user.avatar ?? null,
    details: user.details
      ? {
          title: user.details.title,
          firstName: user.details.firstName,
          lastName: user.details.lastName,
          address: user.details.address,
          city: user.details.city,
          zipCode: user.details.zipCode,
          country: user.details.country,
          phone: user.details.phone,
        }
      : null,
    preferences: user.preferences
      ? {
          useIdle: user.preferences.useIdle,
          idleTimeout: user.preferences.idleTimeout,
          useIdlePassword: user.preferences.useIdlePassword,
          idlePin: user.preferences.idlePin,
          useDirectLogin: user.preferences.useDirectLogin,
          useQuadcodeLogin: user.preferences.useQuadcodeLogin,
          sendNoticesMail: user.preferences.sendNoticesMail,
          language: user.preferences.language,
        }
      : null,
  };
}

function fullName(user: Pick<UserShort, 'details'>): string {
  const parts = [user.details?.title, user.details?.firstName, user.details?.lastName].filter(Boolean);
  return parts.length > 0 ? parts.join(' ') : 'Nessun dettaglio';
}

function avatarInitials(user: Pick<UserShort, 'name' | 'email'>): string {
  const source = user.name.trim() || user.email.trim();
  const parts = source.split(/\s+/).filter(Boolean);
  const first = parts[0] ?? '';
  const second = parts[1] ?? '';
  if (parts.length === 0) {
    return '?';
  }
  if (parts.length === 1) {
    return first.slice(0, 2).toUpperCase();
  }
  return `${first.charAt(0)}${second.charAt(0)}`.toUpperCase();
}

function statusColor(status: UserStatus): string {
  switch (status) {
    case EnumUserStatus.UserStatusActive:
      return 'positive';
    case EnumUserStatus.UserStatusDisabled:
      return 'negative';
    default:
      return 'warning';
  }
}

async function loadUsers(): Promise<void> {
  loading.value = true;
  try {
    const request: ListUsersRequest = {
      page: Number(pagination.value?.page) || 1,
      pageSize: Number(pagination.value?.rowsPerPage) || 10,
    };
    const response = await listUsers(request);
    if (response.error) {
      throw new Error(response.error);
    }
    rows.value = Array.isArray(response.data?.items) ? response.data.items : [];
    pagination.value = {
      ...pagination.value,
      page: response.data?.page ?? request.page,
      rowsPerPage: response.data?.pageSize ?? request.pageSize,
      rowsNumber: rows.value.length < request.pageSize
        ? ((request.page - 1) * request.pageSize) + rows.value.length
        : (request.page * request.pageSize) + 1,
    };
  } catch (error) {
    notifyError(error);
  } finally {
    loading.value = false;
  }
}

async function onTableRequest(props: { pagination: NonNullable<QTableProps['pagination']> }): Promise<void> {
  pagination.value = {
    ...pagination.value,
    ...props.pagination,
  };
  await loadUsers();
}

function openCreateDialog(): void {
  dialogMode.value = 'create';
  editorTab.value = 'account';
  resetForm();
  dialogOpen.value = true;
}

async function openEditDialog(uuid: string): Promise<void> {
  await openUserDialog('edit', uuid);
}

async function openViewDialog(uuid: string): Promise<void> {
  await openUserDialog('view', uuid);
}

async function openPasswordDialog(uuid: string): Promise<void> {
  loading.value = true;
  try {
    const profile = await resolveUserProfile(uuid);
    passwordDialogUserUuid.value = profile.uuid;
    passwordDialogUserEmail.value = profile.email;
    passwordForm.password = '';
    passwordForm.confirmPassword = '';
    passwordDialogOpen.value = true;
  } catch (error) {
    notifyError(error);
  } finally {
    loading.value = false;
  }
}

async function openAvatarDialog(uuid: string): Promise<void> {
  loading.value = true;
  try {
    const profile = await resolveUserProfile(uuid);
    avatarDialogUser.uuid = profile.uuid;
    avatarDialogUser.email = profile.email;
    avatarFile.value = null;
    avatarSource.value = profile.avatar ?? '';
    avatarPreview.value = profile.avatar ?? '';
    avatarDialogOpen.value = true;
  } catch (error) {
    notifyError(error);
  } finally {
    loading.value = false;
  }
}

async function openUserDialog(mode: DialogMode, uuid: string): Promise<void> {
  loading.value = true;
  try {
    const profile = await resolveUserProfile(uuid);
    dialogMode.value = mode;
    editorTab.value = 'account';
    resetForm(profile);
    dialogOpen.value = true;
  } catch (error) {
    notifyError(error);
  } finally {
    loading.value = false;
  }
}

async function saveUser(): Promise<void> {
  if (dialogMode.value === 'view') {
    return;
  }

  if (!form.name.trim() || !form.email.trim()) {
    $q.notify({ type: 'negative', message: 'Nome ed email sono obbligatori.' });
    return;
  }

  if (dialogMode.value === 'create' && form.password.trim().length < 8) {
    $q.notify({ type: 'negative', message: 'La password deve contenere almeno 8 caratteri.' });
    return;
  }

  saving.value = true;
  try {
    if (dialogMode.value === 'create') {
      const response = await createUser(payload.value as UserCreateInput);
      if (response.error) {
        throw new Error(response.error);
      }
      $q.notify({ type: 'positive', message: `Utente ${response.data.email} creato.` });
    } else if (form.uuid) {
      const response = await updateUser(form.uuid, payload.value as UpdateUserRequest);
      if (response.error) {
        throw new Error(response.error);
      }
      $q.notify({ type: 'positive', message: `Utente ${response.data.email} aggiornato.` });
    }

    dialogOpen.value = false;
    await loadUsers();
  } catch (error) {
    notifyError(error);
  } finally {
    saving.value = false;
  }
}

async function savePasswordChange(): Promise<void> {
  if (passwordForm.password.trim().length < 8) {
    $q.notify({ type: 'negative', message: 'La password deve contenere almeno 8 caratteri.' });
    return;
  }

  if (passwordForm.password !== passwordForm.confirmPassword) {
    $q.notify({ type: 'negative', message: 'Le password non coincidono.' });
    return;
  }

  saving.value = true;
  try {
    const profile = await resolveUserProfile(passwordDialogUserUuid.value);
    const response = await updateUser(
      profile.uuid,
      buildUpdatePayload(profile, passwordForm.password),
    );
    if (response.error) {
      throw new Error(response.error);
    }
    passwordDialogOpen.value = false;
    $q.notify({ type: 'positive', message: `Password aggiornata per ${response.data.email}.` });
  } catch (error) {
    notifyError(error);
  } finally {
    saving.value = false;
  }
}

function openAvatarFilePicker(): void {
  avatarFileInputRef.value?.click();
}

function onAvatarFileSelected(event: Event): void {
  const target = event.target as HTMLInputElement | null;
  const selected = target?.files?.[0] ?? null;
  if (!selected) {
    return;
  }

  avatarFile.value = selected;

  const reader = new FileReader();
  reader.onload = () => {
    avatarSource.value = typeof reader.result === 'string' ? reader.result : '';
    avatarPreview.value = avatarSource.value;
  };
  reader.readAsDataURL(selected);
}

function resetAvatarCrop(): void {
  avatarCropperRef.value?.cropper?.reset?.();
}

async function saveAvatar(): Promise<void> {
  if (!avatarSource.value) {
    $q.notify({ type: 'negative', message: 'Seleziona un’immagine prima di salvare.' });
    return;
  }

  saving.value = true;
  try {
    const profile = await resolveUserProfile(avatarDialogUser.uuid);
    const avatarDataUrl =
      avatarCropperRef.value?.cropper?.getDataURL?.({
        width: 256,
        height: 256,
        rounded: true,
      }) || avatarSource.value;

    const response = await updateUser(
      profile.uuid,
      {
        ...buildUpdatePayload(profile),
        avatar: avatarDataUrl,
      },
    );
    if (response.error) {
      throw new Error(response.error);
    }
    avatarPreview.value = avatarDataUrl;
    avatarDialogOpen.value = false;
    $q.notify({ type: 'positive', message: `Avatar aggiornato per ${response.data.email}.` });
    await loadUsers();
  } catch (error) {
    notifyError(error);
  } finally {
    saving.value = false;
  }
}

function openBlockDialog(user: UserShort): void {
  blockDialogUser.uuid = user.uuid;
  blockDialogUser.email = user.email;
  blockDialogUser.status = user.status;
  blockDialogBlocked.value = user.status === EnumUserStatus.UserStatusDisabled;
  blockDialogOpen.value = true;
}

async function saveBlockState(): Promise<void> {
  saving.value = true;
  try {
    const payload: BlockUserRequest = {
      action: blockDialogBlocked.value ? 'block' : 'unblock',
    };
    const response = await blockUser(blockDialogUser.uuid, payload);
    if (response.error) {
      throw new Error(response.error);
    }
    blockDialogOpen.value = false;
    $q.notify({
      type: 'positive',
      message: blockDialogBlocked.value
        ? `Utente ${response.data.email} bloccato.`
        : `Utente ${response.data.email} sbloccato.`,
    });
    await loadUsers();
  } catch (error) {
    notifyError(error);
  } finally {
    saving.value = false;
  }
}

async function resolveUserProfile(uuid: string): Promise<UserProfile> {
  const response = await getUser(uuid);
  if (response.error) {
    throw new Error(response.error);
  }

  return response.data;
}

function notifyError(error: unknown): void {
  $q.notify({
    type: 'negative',
    message: error instanceof Error ? error.message : String(error),
  });
}
</script>

<style scoped>
.users-page {
  background:
    radial-gradient(circle at top left, rgba(13, 71, 161, 0.12), transparent 28%),
    radial-gradient(circle at right top, rgba(0, 150, 136, 0.1), transparent 22%),
    linear-gradient(180deg, #f6f9fc 0%, #edf2f7 100%);
}

.users-shell {
  max-width: 1440px;
  margin: 0 auto;
  padding: 28px 18px 42px;
}

.users-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
}

.eyebrow {
  margin: 0 0 10px;
  color: #0d47a1;
  font-size: 0.8rem;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

h1 {
  margin: 0;
  font-size: clamp(2rem, 4vw, 3.4rem);
  line-height: 0.95;
}

.subtitle {
  max-width: 720px;
  margin: 12px 0 0;
  color: #526273;
  font-size: 1rem;
}

.header-actions {
  display: flex;
  gap: 10px;
}

.users-card,
.editor-card {
  border-radius: 24px;
  background: rgba(255, 255, 255, 0.86);
  backdrop-filter: blur(14px);
}

.modal-card {
  width: min(96vw, 800px);
  max-width: 800px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
}

.toolbar {
  display: flex;
  justify-content: flex-end;
}

.toolbar-search {
  width: min(100%, 420px);
}

.badge-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.user-cell {
  display: flex;
  align-items: center;
  gap: 12px;
}

.user-avatar-thumb {
  width: 40px;
  height: 40px;
  border-radius: 999px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  background: linear-gradient(135deg, #0d47a1, #26a69a);
  color: white;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}

.user-avatar-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.user-meta {
  min-width: 0;
}

.actions-cell {
  white-space: nowrap;
}

.user-action-menu {
  min-width: 190px;
}

.editor-header {
  background: linear-gradient(135deg, #0d47a1, #00897b);
  color: white;
  position: sticky;
  top: 0;
  z-index: 5;
  padding-top: 20px;
  padding-right: 24px;
  padding-left: 24px;
}

.editor-toolbar {
  display: block;
  margin-bottom: 16px;
  padding-right: 260px;
}

.editor-headline {
  min-width: 0;
}

.editor-toolbar-actions {
  position: absolute;
  top: 20px;
  right: 24px;
  display: inline-flex;
  align-items: flex-start;
  gap: 10px;
  z-index: 2;
}

.editor-body {
  padding: 24px;
  overflow: auto;
}

.password-card {
  border-radius: 20px;
}

.password-grid {
  display: grid;
  gap: 14px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.avatar-editor-body {
  padding: 24px;
  overflow: auto;
}

.avatar-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
}

.avatar-editor-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) 280px;
  gap: 24px;
  align-items: start;
}

.avatar-file-name {
  min-width: 0;
  flex: 1 1 auto;
  color: #617487;
  font-size: 0.92rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.avatar-cropper-shell,
.avatar-preview-shell {
  border-radius: 24px;
  background: linear-gradient(180deg, #f7fafd 0%, #edf3f9 100%);
  border: 1px solid rgba(13, 71, 161, 0.08);
}

.avatar-cropper-shell {
  min-height: 520px;
  padding: 18px;
}

.avatar-cropper-box {
  width: 100%;
  height: 480px;
  overflow: hidden;
  border-radius: 20px;
}

.avatar-empty-state {
  min-height: 480px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #617487;
  text-align: center;
  padding: 24px;
}

.avatar-preview-shell {
  padding: 20px;
  position: sticky;
  top: 112px;
}

.avatar-preview-title {
  margin-bottom: 14px;
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #0d47a1;
}

.avatar-preview-disc {
  width: 220px;
  height: 220px;
  margin: 0 auto;
  border-radius: 999px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at 30% 30%, #ffffff 0%, #dce6f1 100%);
  color: #617487;
  text-align: center;
}

.avatar-preview-disc img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.form-grid {
  display: grid;
  gap: 24px;
}

.editor-tabs {
  border-radius: 16px;
  background: rgba(13, 71, 161, 0.06);
  padding: 6px;
}

.editor-panels {
  background: transparent;
}

.form-section {
  display: grid;
  gap: 14px;
}

.form-section h2 {
  margin: 0;
  font-size: 1.1rem;
}

.section-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.section-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.section-grid.disabled {
  opacity: 0.55;
}

.avatar-inline-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border-radius: 18px;
  border: 1px solid rgba(13, 71, 161, 0.12);
  background: linear-gradient(180deg, #f8fbff 0%, #eef4fa 100%);
}

.avatar-inline-preview {
  width: 72px;
  height: 72px;
  border-radius: 999px;
  overflow: hidden;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, #0d47a1, #26a69a);
  color: white;
  font-size: 1rem;
  font-weight: 700;
}

.avatar-inline-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.avatar-inline-meta {
  min-width: 0;
  flex: 1 1 auto;
}

.span-2 {
  grid-column: span 2;
}

@media (max-width: 900px) {
  .users-header {
    flex-direction: column;
    align-items: stretch;
  }

  .header-actions {
    justify-content: stretch;
  }

  .header-actions > * {
    flex: 1 1 auto;
  }

  .section-grid {
    grid-template-columns: 1fr;
  }

  .span-2 {
    grid-column: auto;
  }

  .editor-toolbar {
    padding-right: 0;
  }

  .editor-toolbar-actions {
    position: static;
    margin-bottom: 12px;
  }

  .avatar-toolbar {
    flex-direction: column;
    align-items: stretch;
  }

  .avatar-editor-grid {
    grid-template-columns: 1fr;
  }

  .avatar-cropper-shell {
    min-height: 420px;
  }

  .avatar-cropper-box,
  .avatar-empty-state {
    height: 380px;
    min-height: 380px;
  }

  .avatar-preview-shell {
    position: static;
  }
}
</style>
