<template>
  <q-page v-if="canUpdateUser" class="rdp-list-page">
    <div class="rdp-filter-bar">
      <div class="rdp-filter-row">
        <q-input
          v-model="store.filters.search"
          class="rdp-filter-input rdp-search"
          dense
          filled
          clearable
          debounce="300"
          label="Arama (Rol / Departman)"
        >
          <template #append>
            <q-icon name="search" />
          </template>
        </q-input>

        <div class="rdp-filter-actions">
          <q-btn
            label="Temizle"
            icon="clear"
            color="grey-7"
            flat
            :disable="store.loading"
            @click="clearFilters"
          />
          <q-btn
            label="Yenile"
            icon="refresh"
            color="primary"
            :loading="store.loading"
            @click="store.fetchRows"
          />
        </div>

        <div class="rdp-config-menus">
          <q-btn-dropdown
            color="secondary"
            outline
            icon="view_module"
            label="Modüller"
            :auto-close="false"
          >
            <q-list dense class="rdp-menu-list">
              <q-item clickable @click="selectAllModules">
                <q-item-section>Tümünü Seç</q-item-section>
              </q-item>
              <q-item clickable @click="clearAllModules">
                <q-item-section>Tümünü Temizle</q-item-section>
              </q-item>
              <q-separator />
              <q-item
                v-for="m in store.modules"
                :key="m.value"
                clickable
                @click="onModuleRowClick(m.value)"
              >
                <q-item-section avatar>
                  <q-checkbox
                    :model-value="isModuleSelected(m.value)"
                    dense
                    @update:model-value="(v) => toggleModule(m.value, v)"
                    @click.stop
                  />
                </q-item-section>
                <q-item-section>{{ m.label }}</q-item-section>
              </q-item>
            </q-list>
          </q-btn-dropdown>

          <q-btn-dropdown
            color="secondary"
            outline
            icon="tune"
            :label="`Aksiyonlar (${activeModuleLabel})`"
            :disable="!activeModuleCode"
            :auto-close="false"
          >
            <q-list dense class="rdp-menu-list">
              <q-item clickable @click="selectAllActionsForActive">
                <q-item-section>Tümünü Seç</q-item-section>
              </q-item>
              <q-item clickable @click="clearAllActionsForActive">
                <q-item-section>Tümünü Temizle</q-item-section>
              </q-item>
              <q-separator />
              <q-item
                v-for="a in actionsForActiveModule"
                :key="`${activeModuleCode}:${a}`"
                clickable
              >
                <q-item-section avatar>
                  <q-checkbox
                    :model-value="isActionSelected(activeModuleCode, a)"
                    dense
                    @update:model-value="(v) => toggleAction(activeModuleCode, a, v)"
                    @click.stop
                  />
                </q-item-section>
                <q-item-section>{{ actionLabel(a) }}</q-item-section>
              </q-item>
            </q-list>
          </q-btn-dropdown>
        </div>

        <div class="rdp-summary">
          <span>Toplam Kayıt: <strong>{{ store.totalCount }}</strong></span>
        </div>
      </div>
    </div>

    <q-table
      title="Rol + Departman Yetki Setleri"
      class="rdp-table"
      flat
      bordered
      dense
      row-key="row_key"
      :rows="tableRows"
      :columns="columns"
      :loading="store.loading"
      no-data-label="Kayıt bulunamadı"
      :rows-per-page-options="[0]"
      hide-bottom
    >
      <template #body="props">
        <q-tr
          :id="rowDomId(props.row)"
          :props="props"
          class="rdp-data-row"
          @mouseenter="showMembersPopup(props.row)"
          @mouseleave="scheduleHideMembersPopup"
        >
          <q-td
            v-for="col in props.cols"
            :key="col.name"
            :props="props"
            :class="col.classes"
          >
          <template v-if="col.name === 'open'">
            <div class="text-center">
              <q-btn
                icon="open_in_new"
                color="primary"
                flat
                round
                dense
                @click="openEditor(props.row)"
              >
                <q-tooltip>Yetki setini aç</q-tooltip>
              </q-btn>
            </div>
          </template>

          <template v-else-if="isPermissionColumn(col.name)">
            <div class="text-center">
              <q-checkbox
                :model-value="Boolean(col.value)"
                disable
                dense
              />
            </div>
          </template>

          <template v-else>
            {{ col.value }}
          </template>
        </q-td>
        </q-tr>
      </template>
    </q-table>

    <q-menu
      v-model="membersPopupOpen"
      :target="membersPopupTarget"
      no-parent-event
      anchor="center right"
      self="center left"
      :offset="[8, 0]"
      class="rdp-members-popup"
      @mouseenter="cancelHideMembersPopup"
      @mouseleave="scheduleHideMembersPopup"
    >
      <div class="rdp-members-popup__header">
        <div class="text-weight-bold">{{ hoveredRow?.role_title }}</div>
        <div class="text-caption text-grey-7">{{ hoveredRow?.department_title }}</div>
      </div>
      <q-separator />
      <q-list v-if="hoveredMembers.length" dense class="rdp-members-popup__list">
        <q-item v-for="member in hoveredMembers" :key="member.id">
          <q-item-section avatar class="rdp-member-id">{{ member.id }}</q-item-section>
          <q-item-section>
            <q-item-label>{{ member.full_name || member.username }}</q-item-label>
            <q-item-label caption>{{ member.username }}</q-item-label>
          </q-item-section>
        </q-item>
      </q-list>
      <div v-else class="q-pa-sm text-caption text-grey-7">
        Bu grupta aktif kullanici bulunmuyor.
      </div>
    </q-menu>

    <q-banner v-if="store.error" class="bg-red text-white q-mt-sm">
      Hata: {{ store.error }}
    </q-banner>
  </q-page>

  <q-page v-else class="q-pa-md flex flex-center">
    <div class="text-negative text-subtitle1">
      Bu modüle erişim yetkiniz yok.
    </div>
  </q-page>
</template>

<script setup>
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useQuasar } from 'quasar'
import { usePermission } from 'src/composables/usePermission'
import { useRoleDeptPermissionListStore } from 'src/stores/RoleDeptPermissionListStore'

const router = useRouter()
const $q = useQuasar()
const store = useRoleDeptPermissionListStore()
const { canUpdate } = usePermission()
const canUpdateUser = canUpdate('user')

const selectedModules = ref([])
const selectedActionsByModule = ref({})
const activeModuleCode = ref('')
const allowEmptySelection = ref(false)
const membersPopupOpen = ref(false)
const membersPopupTarget = ref(false)
const hoveredRow = ref(null)
let membersPopupHideTimer = null

const actionLabelMap = {
  update: 'Güncelleme',
  view: 'Görüntüleme',
  insert: 'Ekleme',
  export: 'Çıktı',
  write: 'Yazma',
  read: 'Okuma',
  delete: 'Silme',
  login: 'Giriş',
  refresh: 'Yenileme',
  'user.update': 'Kullanıcı Güncelle'
}

const fixedColumns = [
  {
    name: 'open',
    label: '',
    field: 'open',
    align: 'center',
    sortable: false,
    classes: 'freeze-col freeze-1',
    headerClasses: 'freeze-col freeze-1',
    style: 'width:56px; min-width:56px; max-width:56px',
    headerStyle: 'width:56px; min-width:56px; max-width:56px'
  },
  {
    name: 'role_title',
    label: 'Rol',
    field: 'role_title',
    align: 'left',
    sortable: true,
    classes: 'freeze-col freeze-2',
    headerClasses: 'freeze-col freeze-2',
    style: 'width:220px; min-width:220px; max-width:220px',
    headerStyle: 'width:220px; min-width:220px; max-width:220px'
  },
  {
    name: 'department_title',
    label: 'Departman',
    field: 'department_title',
    align: 'left',
    sortable: true,
    classes: 'freeze-col freeze-3',
    headerClasses: 'freeze-col freeze-3',
    style: 'width:220px; min-width:220px; max-width:220px',
    headerStyle: 'width:220px; min-width:220px; max-width:220px'
  },
  {
    name: 'department_code',
    label: 'Departman Kodu',
    field: 'department_code',
    align: 'left',
    sortable: true,
    style: 'width:140px; min-width:140px; max-width:140px',
    headerStyle: 'width:140px; min-width:140px; max-width:140px'
  }
]

const moduleLabelMap = computed(() => {
  const map = {}
  ;(store.modules || []).forEach((m) => {
    map[m.value] = m.label || m.value
  })
  return map
})

const actionsByModule = computed(() => {
  const map = {}
  ;(store.moduleActions || []).forEach((x) => {
    if (!map[x.module_code]) map[x.module_code] = []
    if (!map[x.module_code].includes(x.action)) {
      map[x.module_code].push(x.action)
    }
  })
  Object.keys(map).forEach((k) => map[k].sort())
  return map
})

const activeModuleLabel = computed(() => {
  if (!activeModuleCode.value) return 'Seçim'
  return moduleLabelMap.value[activeModuleCode.value] || activeModuleCode.value
})

const actionsForActiveModule = computed(() => {
  if (!activeModuleCode.value) return []
  return actionsByModule.value[activeModuleCode.value] || []
})

function actionLabel (action) {
  const key = String(action || '').toLowerCase().trim()
  return actionLabelMap[key] || key
}

function syncSelections () {
  const availableModules = (store.modules || []).map((m) => m.value)
  if (!availableModules.length) {
    selectedModules.value = []
    selectedActionsByModule.value = {}
    activeModuleCode.value = ''
    return
  }

  const selected = selectedModules.value.filter((m) => availableModules.includes(m))
  if (selected.length) {
    selectedModules.value = selected
  } else {
    selectedModules.value = allowEmptySelection.value ? [] : [...availableModules]
  }

  if (!selectedModules.value.length) {
    activeModuleCode.value = ''
  } else if (!selectedModules.value.includes(activeModuleCode.value)) {
    activeModuleCode.value = selectedModules.value[0]
  }

  const next = {}
  selectedModules.value.forEach((m) => {
    const allActions = actionsByModule.value[m] || []
    const prev = selectedActionsByModule.value[m] || []
    const filtered = prev.filter((a) => allActions.includes(a))
    next[m] = filtered.length ? filtered : (allowEmptySelection.value ? [] : [...allActions])
  })
  selectedActionsByModule.value = next
}

watch(
  () => [store.modules, store.moduleActions],
  () => {
    syncSelections()
  },
  { deep: true }
)

function isModuleSelected (moduleCode) {
  return selectedModules.value.includes(moduleCode)
}

function toggleModule (moduleCode, checked) {
  allowEmptySelection.value = false
  const set = new Set(selectedModules.value)
  if (checked) {
    set.add(moduleCode)
  } else {
    set.delete(moduleCode)
  }
  selectedModules.value = [...set]
  if (!selectedModules.value.length) {
    activeModuleCode.value = ''
  } else if (!selectedModules.value.includes(activeModuleCode.value)) {
    activeModuleCode.value = selectedModules.value[0]
  }
  syncSelections()
}

function onModuleRowClick (moduleCode) {
  activeModuleCode.value = moduleCode
}

function selectAllModules () {
  allowEmptySelection.value = false
  selectedModules.value = (store.modules || []).map((m) => m.value)
  syncSelections()
}

function clearAllModules () {
  allowEmptySelection.value = true
  selectedModules.value = []
  selectedActionsByModule.value = {}
  activeModuleCode.value = ''
  syncSelections()
}

function isActionSelected (moduleCode, action) {
  return (selectedActionsByModule.value[moduleCode] || []).includes(action)
}

function toggleAction (moduleCode, action, checked) {
  allowEmptySelection.value = false
  const current = new Set(selectedActionsByModule.value[moduleCode] || [])
  if (checked) {
    current.add(action)
  } else {
    current.delete(action)
  }
  selectedActionsByModule.value = {
    ...selectedActionsByModule.value,
    [moduleCode]: [...current]
  }
}

function selectAllActionsForActive () {
  allowEmptySelection.value = false
  if (!activeModuleCode.value) return
  selectedActionsByModule.value = {
    ...selectedActionsByModule.value,
    [activeModuleCode.value]: [...actionsForActiveModule.value]
  }
}

function clearAllActionsForActive () {
  allowEmptySelection.value = true
  if (!activeModuleCode.value) return
  selectedActionsByModule.value = {
    ...selectedActionsByModule.value,
    [activeModuleCode.value]: []
  }
}

const permissionColumns = computed(() => {
  const cols = []
  selectedModules.value.forEach((m) => {
    const actions = selectedActionsByModule.value[m] || []
    actions.forEach((a) => {
      const key = `${m}|${a}`
      cols.push({
        name: `perm_${key}`,
        label: `${moduleLabelMap.value[m] || m}\n${actionLabel(a)}`,
        field: (row) => Boolean(row.module_flags?.[key]),
        align: 'center',
        sortable: true,
        style: 'width:150px; min-width:150px; max-width:150px',
        headerStyle: 'width:150px; min-width:150px; max-width:150px; white-space:pre-line; line-height:1.15'
      })
    })
  })
  return cols
})

const columns = computed(() => [
  ...fixedColumns,
  ...permissionColumns.value
])

const tableRows = computed(() =>
  (store.rows || []).map((r) => ({
    ...r,
    row_key: `${r.role_id}:${r.department_code}`
  }))
)

const hoveredMembers = computed(() => hoveredRow.value?.members || [])

function rowDomId (row) {
  const roleID = String(row?.role_id || '0').replace(/[^a-zA-Z0-9_-]/g, '-')
  const departmentCode = String(row?.department_code || '').replace(/[^a-zA-Z0-9_-]/g, '-')
  return `rdp-row-${roleID}-${departmentCode}`
}

function cancelHideMembersPopup () {
  if (!membersPopupHideTimer) return
  clearTimeout(membersPopupHideTimer)
  membersPopupHideTimer = null
}

function showMembersPopup (row) {
  cancelHideMembersPopup()
  hoveredRow.value = row
  membersPopupTarget.value = `#${rowDomId(row)}`
  membersPopupOpen.value = true
}

function scheduleHideMembersPopup () {
  cancelHideMembersPopup()
  membersPopupHideTimer = setTimeout(() => {
    membersPopupOpen.value = false
    hoveredRow.value = null
    membersPopupTarget.value = false
    membersPopupHideTimer = null
  }, 180)
}

function isPermissionColumn (name) {
  return String(name || '').startsWith('perm_')
}

let searchTimer = null
watch(
  () => store.filters.search,
  () => {
    clearTimeout(searchTimer)
    searchTimer = setTimeout(() => {
      if (canUpdateUser.value) {
        store.fetchRows()
      }
    }, 350)
  }
)

function openEditor (row) {
  if (!row?.role_id || !row?.department_code) {
    $q.notify({ type: 'warning', message: 'Kayıt bilgisi eksik' })
    return
  }

  router.push({
    name: 'role-dept-permissions-editor',
    query: {
      mode: 'edit',
      roleId: String(row.role_id),
      deptCode: String(row.department_code)
    }
  })
}

function clearFilters () {
  store.filters.search = ''
  store.fetchRows()
}

onMounted(async () => {
  if (canUpdateUser.value) {
    await store.fetchRows()
    syncSelections()
  }
})

onBeforeUnmount(() => {
  cancelHideMembersPopup()
})
</script>

<style scoped>
.rdp-list-page {
  --rdp-header-h: 56px;
  --rdp-filter-h: 96px;
  height: calc(100vh - var(--rdp-header-h));
  overflow: auto;
  background: #fff;
  display: flex;
  flex-direction: column;
  padding: 10px;
}

.rdp-filter-bar {
  position: sticky;
  top: 0;
  z-index: 600;
  background: #fff;
  border-bottom: 1px solid #ddd;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
  min-height: var(--rdp-filter-h);
  display: flex;
  align-items: center;
  padding: 10px 12px;
  margin-bottom: 8px;
}

.rdp-filter-row {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  flex-wrap: nowrap;
}

.rdp-filter-input {
  min-width: 180px;
  max-width: 300px;
}

.rdp-search {
  min-width: 300px;
  max-width: 520px;
  flex: 1 1 360px;
}

.rdp-filter-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  white-space: nowrap;
  flex: 0 0 auto;
}

.rdp-config-menus {
  display: flex;
  gap: 8px;
  align-items: center;
  white-space: nowrap;
  flex: 0 0 auto;
}

.rdp-menu-list {
  min-width: 260px;
  max-height: 420px;
}

.rdp-summary {
  margin-left: auto;
  background: #f9fafb;
  border: 1px solid #e0e0e0;
  border-radius: 6px;
  padding: 8px 12px;
  white-space: nowrap;
  font-size: 12px;
  color: #4b5563;
  align-self: center;
}

.rdp-table :deep(.q-table__middle) {
  overflow: visible !important;
  max-height: none !important;
}

.rdp-table :deep(.q-table thead th) {
  position: sticky;
  top: var(--rdp-filter-h);
  z-index: 500;
  background: #fff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
  font-size: 11px;
  white-space: nowrap;
}

.rdp-table :deep(.q-table tbody td) {
  font-size: 11px;
  padding: 3px 6px;
}

.rdp-data-row {
  cursor: default;
}

.rdp-members-popup {
  min-width: 280px;
  max-width: 380px;
}

.rdp-members-popup__header {
  padding: 10px 12px 8px;
}

.rdp-members-popup__list {
  max-height: 360px;
  overflow: auto;
}

.rdp-member-id {
  min-width: 48px;
  color: #1976d2;
  font-weight: 700;
}

.rdp-table :deep(.q-checkbox__inner) {
  pointer-events: none;
}

.rdp-table :deep(.freeze-col) {
  position: sticky;
  background: #fff;
  z-index: 510;
}

.rdp-table :deep(thead .freeze-col) {
  z-index: 520;
  background: #fff;
}

.rdp-table :deep(.freeze-1) {
  left: 0;
}

.rdp-table :deep(.freeze-2) {
  left: 56px;
}

.rdp-table :deep(.freeze-3) {
  left: 276px;
}

@media (max-width: 1400px) {
  .rdp-filter-row {
    flex-wrap: wrap;
    align-items: flex-start;
  }

  .rdp-filter-actions {
    flex-wrap: wrap;
  }

  .rdp-config-menus {
    flex-wrap: wrap;
  }

  .rdp-summary {
    min-width: 100%;
    margin-left: 0;
    margin-top: 6px;
  }
}
</style>
