<template>
    <MalioDrawer v-model="isOpen">
        <template #header>
            <h2 class="text-xl font-bold">
                {{ isEditing ? $t('admin.roles.editRole') : $t('admin.roles.addRole') }}
            </h2>
        </template>
        <form class="flex flex-col gap-3" @submit.prevent="handleSubmit">
            <MalioInputText
                v-model="form.code"
                :label="$t('admin.roles.code')"
                input-class="w-full"
                :disabled="isEditing"
                :hint="isEditing ? $t('admin.roles.codeImmutable') : $t('admin.roles.codeHint')"
                :error="touched.code && !codeValid ? $t('admin.roles.codeInvalid') : ''"
                @blur="touched.code = true"
            />
            <MalioInputText
                v-model="form.label"
                :label="$t('admin.roles.label')"
                input-class="w-full"
                :error="touched.label && !form.label.trim() ? $t('admin.roles.labelRequired') : ''"
                @blur="touched.label = true"
            />
            <MalioInputTextArea
                v-model="form.description"
                :label="$t('admin.roles.description')"
                input-class="w-full"
            />

            <div class="mt-2">
                <label class="text-sm font-semibold text-neutral-700">
                    {{ $t('admin.roles.permissions') }}
                </label>
                <p v-if="permissions.length === 0" class="mt-2 text-xs text-neutral-400">
                    {{ $t('admin.roles.noPermissions') }}
                </p>
                <div
                    v-for="group in groupedPermissions"
                    :key="group.module"
                    class="mt-3 rounded-lg border border-neutral-200 p-3"
                >
                    <p class="mb-2 text-xs font-bold uppercase tracking-wide text-neutral-500">
                        {{ group.module }}
                    </p>
                    <div class="flex flex-col gap-2">
                        <label
                            v-for="perm in group.permissions"
                            :key="perm.id"
                            class="flex items-start gap-2 text-sm text-neutral-700"
                        >
                            <input
                                v-model="form.permissions"
                                type="checkbox"
                                :value="perm['@id']"
                                class="mt-0.5 rounded border-neutral-300"
                            />
                            <span>
                                {{ perm.label }}
                                <span class="block text-xs text-neutral-400">{{ perm.code }}</span>
                            </span>
                        </label>
                    </div>
                </div>
            </div>

            <div class="mt-4 flex justify-end">
                <MalioButton
                    :label="$t('common.save')"
                    button-class="w-auto px-6"
                    :disabled="isSubmitting"
                    @click="handleSubmit"
                />
            </div>
        </form>
    </MalioDrawer>
</template>

<script setup lang="ts">
import type { Role, RoleWrite } from '~/modules/core/services/roles'
import { useRoleService } from '~/modules/core/services/roles'
import type { Permission } from '~/modules/core/services/permissions'

const props = defineProps<{
    modelValue: boolean
    item: Role | null
    permissions: Permission[]
}>()

const emit = defineEmits<{
    (e: 'update:modelValue', value: boolean): void
    (e: 'saved'): void
}>()

const isOpen = computed({
    get: () => props.modelValue,
    set: (v) => emit('update:modelValue', v),
})

const isEditing = computed(() => !!props.item)
const isSubmitting = ref(false)

const form = reactive({
    code: '',
    label: '',
    description: '',
    permissions: [] as string[],
})

const touched = reactive({
    code: false,
    label: false,
})

const codeValid = computed(() => /^[a-z][a-z0-9_]*$/.test(form.code))

const groupedPermissions = computed(() => {
    const byModule = new Map<string, Permission[]>()
    for (const perm of props.permissions) {
        const list = byModule.get(perm.module) ?? []
        list.push(perm)
        byModule.set(perm.module, list)
    }
    return [...byModule.entries()]
        .map(([module, permissions]) => ({ module, permissions }))
        .sort((a, b) => a.module.localeCompare(b.module))
})

watch(() => props.modelValue, (open) => {
    if (open) {
        if (props.item) {
            form.code = props.item.code
            form.label = props.item.label
            form.description = props.item.description ?? ''
            form.permissions = props.item.permissions
                .map((p) => p['@id'])
                .filter((iri): iri is string => !!iri)
        } else {
            form.code = ''
            form.label = ''
            form.description = ''
            form.permissions = []
        }
        touched.code = false
        touched.label = false
    }
})

const { create, update } = useRoleService()

async function handleSubmit() {
    touched.code = true
    touched.label = true
    if (!form.label.trim()) {
        return
    }
    if (!isEditing.value && !codeValid.value) {
        return
    }

    isSubmitting.value = true
    try {
        if (isEditing.value && props.item) {
            const payload: Partial<RoleWrite> = {
                label: form.label.trim(),
                description: form.description.trim() || null,
                permissions: form.permissions,
            }
            await update(props.item.id, payload)
        } else {
            const payload: RoleWrite = {
                code: form.code.trim(),
                label: form.label.trim(),
                description: form.description.trim() || null,
                permissions: form.permissions,
            }
            await create(payload)
        }

        emit('saved')
        isOpen.value = false
    } finally {
        isSubmitting.value = false
    }
}
</script>
