<template>
  <section class="page">
    <AppLoadingState v-if="areasStore.isLoading || areasStore.isLoadingAreaDetail" text="Loading area" />

    <AppErrorState
      v-else-if="areasStore.error && !areasStore.areas.length"
      title="Areas loading failed"
      :error="areasStore.error"
      :retry="init"
    />

    <AppErrorState
      v-else-if="areasStore.errorAreaDetail"
      title="Area loading failed"
      :error="areasStore.errorAreaDetail"
      :retry="init"
    />

    <div v-else-if="area">
      <GnPageHeader :title="area.display_name" kicker="Area">
        <template #actions>
          <PageActionsDropdown :items="areaActions" />
        </template>
      </GnPageHeader>

      <div class="area-meta">
        <GnBadge variant="secondary">{{ area.type }}</GnBadge>
        <code>{{ area.alias }}</code>
        <AreaBadgeLink :area="parentArea" :areaId="area.parent_id" />
      </div>

      <div class="actions-panel">
        <div class="block-title">Actions ({{ areaActionScripts.length }})</div>
        <AppEmptyState
          v-if="areaActionScripts.length === 0"
          title="No actions"
          message="No action scripts assigned to this area."
        />
        <ActionScriptsGrid v-else :scripts="areaActionScripts" @run-success="refreshDeviceStates" />
      </div>

      <div class="devices-panel">
        <div class="block-title">Devices ({{ areasStore.currentAreaDevices.length }})</div>
        <AppEmptyState
          v-if="areasStore.currentAreaDevices.length === 0"
          title="No devices"
          message="No devices assigned to this area."
        />
        <DeviceTable v-else :devices="areasStore.currentAreaDevices" caption="Area devices" />
      </div>

      <AreaAssignSection
        :areaId="area.parent_id > 0 ? area.parent_id : null"
        title="Parent area"
        emptyMessage="This area is not assigned to any parent area."
        @assign="openAssign"
      >
        <template #action>
          <GnButton
            v-if="perm.has('areas.manage')"
            variant="primary"
            icon="ph-map-pin"
            @click="openAssign"
          >
            {{ area.parent_id > 0 ? 'Change parent area' : 'Assign to area' }}
          </GnButton>
        </template>
      </AreaAssignSection>

      <div class="scripts-panel">
        <div class="block-title">Regular scripts ({{ areaRegularScripts.length }})</div>
        <AppEmptyState
          v-if="areaRegularScripts.length === 0"
          title="No regular scripts"
          message="No regular scripts assigned to this area."
        />
        <ScriptTable
          v-else
          :scripts="areaRegularScripts"
          scriptType="regular"
          :showArea="false"
          :showActions="false"
          :showFilename="false"
          caption="Area regular scripts"
        />
      </div>
    </div>

    <AppEmptyState
      v-else
      title="Area not found"
      message="The requested area does not exist."
    />

    <GnModal :open="showRenameModal" title="Rename area" @update:open="showRenameModal = $event">
      <div class="form-group">
        <GnInput v-model="renameForm.display_name" label="Display name" />
      </div>
      <div v-if="renameError" class="form-group">
        <GnAlert variant="danger">{{ renameError }}</GnAlert>
      </div>
      <template #footer>
        <GnButton variant="secondary" @click="showRenameModal = false">Cancel</GnButton>
        <GnButton variant="primary" icon="ph-check" :loading="renameLoading" @click="submitRename">Rename</GnButton>
      </template>
    </GnModal>

    <GnModal
      :open="showAssignModal"
      title="Assign to parent area"
      @update:open="showAssignModal = $event"
    >
      <GnSelect
        v-if="!isLastRoot"
        v-model="selectedAreaId"
        label="Parent area"
        :options="parentAreaOptions"
        icon="ph-map-trifold"
      />
      <div v-if="isLastRoot" class="form-group">
        <GnAlert variant="warning">
          This is the last root area and cannot be assigned as a child.
          At least one root area must remain.
        </GnAlert>
      </div>
      <div v-if="assignError" class="form-group">
        <GnAlert variant="danger">{{ assignError }}</GnAlert>
      </div>
      <template #footer>
        <GnButton variant="secondary" @click="showAssignModal = false">Cancel</GnButton>
        <GnButton
          v-if="!isLastRoot"
          variant="primary"
          icon="ph-check"
          :loading="assignLoading"
          @click="handleAssignSubmit"
        >
          Assign
        </GnButton>
      </template>
    </GnModal>

    <GnModal
      :open="showUnassignDialog"
      title="Unassign from parent"
      @update:open="showUnassignDialog = $event"
    >
      <p>{{ unassignDialogMessage }}</p>
      <div v-if="unassignError" class="form-group">
        <GnAlert variant="danger">{{ unassignError }}</GnAlert>
      </div>
      <template #footer>
        <GnButton variant="secondary" @click="showUnassignDialog = false">Cancel</GnButton>
        <GnButton variant="warning" icon="ph-x-circle" :loading="unassignLoading" @click="submitUnassign">
          Unassign
        </GnButton>
      </template>
    </GnModal>

    <GnModal
      :open="showRemoveDialog"
      title="Remove area"
      @update:open="showRemoveDialog = $event"
    >
      <p>{{ removeDialogMessage }}</p>
      <div v-if="removeError" class="form-group">
        <GnAlert variant="danger">{{ removeError }}</GnAlert>
      </div>
      <template #footer>
        <GnButton variant="secondary" @click="showRemoveDialog = false">Cancel</GnButton>
        <GnButton variant="danger" icon="ph-trash" :loading="removeLoading" @click="submitRemove">
          Remove
        </GnButton>
      </template>
    </GnModal>
  </section>
</template>

<script setup>
import { ref, reactive, computed, onMounted, onUnmounted, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useAreasStore } from "../../../stores/areas";
import { useDevicesStore } from "../../../stores/devices";
import { useFavoritesStore } from "../../../stores/favorites";
import { useScriptsStore } from "../../../stores/scripts";
import { usePermission } from "../../../composables/usePermission.js";
import { useAreaAssign } from "../../../composables/useAreaAssign";
import {
  GnPageHeader,
  GnButton,
  GnBadge,
  GnModal,
  GnInput,
  GnAlert,
  GnSelect,
  useToast,
} from "gnexus-ui-kit/vue";
import AppLoadingState from "../../../components/feedback/AppLoadingState.vue";
import AppErrorState from "../../../components/feedback/AppErrorState.vue";
import AppEmptyState from "../../../components/feedback/AppEmptyState.vue";
import AreaBadgeLink from "../../../components/area/AreaBadgeLink.vue";
import AreaAssignSection from "../../../components/area/AreaAssignSection.vue";
import DeviceTable from "../../../components/device/DeviceTable.vue";
import ScriptTable from "../../../components/script/ScriptTable.vue";
import PageActionsDropdown from "../../../components/layout/PageActionsDropdown.vue";
import ActionScriptsGrid from "../../../components/script/ActionScriptsGrid.vue";

const route = useRoute();
const router = useRouter();
const areasStore = useAreasStore();
const devicesStore = useDevicesStore();
const favoritesStore = useFavoritesStore();
const scriptsStore = useScriptsStore();
const toast = useToast();
const perm = usePermission();

const {
  showAssignModal,
  selectedAreaId,
  assignLoading,
  assignError,
  openAssign: openAssignModal,
  submitAssignCore,
} = useAreaAssign();

const area = computed(() => areasStore.areasById[String(route.params.id)] || null);
const isFavorite = computed(() => (area.value ? favoritesStore.has(area.value.id) : false));

const areaActions = computed(() => {
  const actions = [];

  if (perm.has('areas.manage')) {
    actions.push({ label: "Rename", icon: "ph-pencil", onSelect: openRename });

    if (area.value?.parent_id > 0) {
      actions.push(
        { label: "Change parent area", icon: "ph-map-pin", onSelect: openAssign },
        { label: "Unassign from parent", icon: "ph-x-circle", onSelect: openUnassign }
      );
    } else {
      actions.push({
        label: "Assign to area",
        icon: "ph-map-pin",
        onSelect: openAssign,
      });
    }
  }

  actions.push({
    label: isFavorite.value ? "Remove bookmark" : "Bookmark",
    icon: isFavorite.value ? "ph-fill ph-bookmark-simple" : "ph-bookmark-simple",
    onSelect: () => favoritesStore.toggle(area.value?.id),
  });

  if (perm.has('areas.manage')) {
    actions.push({ label: "Remove", icon: "ph-trash", danger: true, onSelect: openRemove });
  }

  return actions;
});

const parentArea = computed(() => {
  if (!area.value || area.value.parent_id <= 0) return null;
  return areasStore.areasById[String(area.value.parent_id)] || null;
});

const areaActionScripts = computed(() =>
  areasStore.currentAreaScripts.filter((s) => s.type === "action")
);

const areaRegularScripts = computed(() =>
  areasStore.currentAreaScripts.filter((s) => s.type !== "action")
);

const isLastRoot = computed(() => {
  if (!area.value) return false;
  const isRoot = !area.value.parent_id || area.value.parent_id <= 0;
  const rootCount = areasStore.areas.filter((a) => !a.parent_id || a.parent_id <= 0).length;
  return isRoot && rootCount === 1;
});

function getDescendantIds(areaId) {
  const result = new Set();
  const queue = [areaId];
  while (queue.length) {
    const current = queue.shift();
    const children = areasStore.areas.filter((a) => a.parent_id === current);
    for (const child of children) {
      result.add(child.id);
      queue.push(child.id);
    }
  }
  return result;
}

const parentAreaOptions = computed(() => {
  if (!area.value) return [];
  const excluded = new Set([area.value.id, ...getDescendantIds(area.value.id)]);
  return areasStore.areas
    .filter((a) => !excluded.has(a.id))
    .map((a) => ({
      value: String(a.id),
      label: `${a.display_name} (${a.type})`,
    }));
});

const showRenameModal = ref(false);
const renameLoading = ref(false);
const renameError = ref("");
const renameForm = reactive({ areaId: null, display_name: "" });

const showRemoveDialog = ref(false);
const removeDialogMessage = ref("");
const removeLoading = ref(false);
const removeError = ref("");

const showUnassignDialog = ref(false);
const unassignDialogMessage = ref("");
const unassignLoading = ref(false);
const unassignError = ref("");

function openRename() {
  if (!area.value) return;
  renameForm.areaId = area.value.id;
  renameForm.display_name = area.value.display_name;
  renameError.value = "";
  showRenameModal.value = true;
}

async function submitRename() {
  renameLoading.value = true;
  renameError.value = "";

  const result = await areasStore.renameArea(renameForm.areaId, renameForm.display_name);
  renameLoading.value = false;

  if (!result.ok) {
    renameError.value = result.error?.message || "Failed to rename area";
    return;
  }

  showRenameModal.value = false;
  toast.success({ title: "Renamed", text: "Area renamed successfully" });
}

function openRemove() {
  if (!area.value) return;
  removeDialogMessage.value = `Are you sure you want to remove area "${area.value.display_name}"?`;
  removeError.value = "";
  showRemoveDialog.value = true;
}

async function submitRemove() {
  if (!area.value) return;
  removeLoading.value = true;
  removeError.value = "";

  const result = await areasStore.removeArea(area.value.id);
  removeLoading.value = false;

  if (!result.ok) {
    removeError.value = result.error?.message || "Failed to remove area";
    return;
  }

  showRemoveDialog.value = false;
  toast.success({ title: "Removed", text: "Area removed successfully" });
  router.push({ name: "areas-tree" });
}

function openAssign() {
  openAssignModal(area.value?.parent_id > 0 ? area.value.parent_id : "");
}

async function handleAssignSubmit() {
  const id = area.value?.id;
  const result = await submitAssignCore(id, (itemId, parentId) => areasStore.assignToArea(itemId, parentId));
  if (result?.ok) {
    toast.success({ title: "Assigned", text: "Area assigned successfully" });
  }
}

function openUnassign() {
  if (!area.value) return;
  unassignDialogMessage.value = `Are you sure you want to unassign area "${area.value.display_name}" from its parent?`;
  unassignError.value = "";
  showUnassignDialog.value = true;
}

async function submitUnassign() {
  if (!area.value) return;
  unassignLoading.value = true;
  unassignError.value = "";

  const result = await areasStore.unassignArea(area.value.id);
  unassignLoading.value = false;

  if (!result.ok) {
    unassignError.value = result.error?.message || "Failed to unassign area";
    return;
  }

  showUnassignDialog.value = false;
  toast.success({ title: "Unassigned", text: "Area unassigned from parent successfully" });
}

async function refreshDeviceStates() {
  if (areasStore.currentAreaDevices.length > 0) {
    await devicesStore.loadStatesFor(areasStore.currentAreaDevices);
  }
}

async function init() {
  const id = route.params.id;
  if (!id) return;

  if (areasStore.areas.length === 0) {
    await areasStore.loadAreas();
  }

  if (areasStore.areasById[String(id)]) {
    await areasStore.loadAreaDetail(id);
    await refreshDeviceStates();
  }
}

// Watch for route changes (e.g., navigating from one area to another)
watch(
  () => route.params.id,
  async (newId, oldId) => {
    if (newId && newId !== oldId) {
      await init();
    }
  },
  { immediate: false }
);

onMounted(() => {
  init();
});

onUnmounted(() => {
  areasStore.clearAreaDetail();
});
</script>

<style scoped>
.area-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-bottom: 24px;
}

.area-parent {
  color: var(--color-muted);
}

.actions-panel,
.devices-panel,
.scripts-panel {
  margin-bottom: 24px;
}

.block-title {
  font-weight: 700;
  text-transform: uppercase;
  margin-bottom: 12px;
  color: var(--color-primary);
}

.form-group {
  margin-bottom: 16px;
}
</style>
