<!--
  Compact, expandable maintenance/cleanup action tile. Collapsed it shows just an
  icon + short title + one-line purpose, so a section of these tiles in a grid is
  scannable at a glance; clicking the header expands the full controls / preview /
  result UI inline (the operator opted for "compact tiles in a grid, detail on
  expand", 2026-06-18, replacing the old long stack of full-width cards).

  Usage: wrap a card's action body in the default slot; pass icon/title/blurb.
  `destructive` tints the icon error-red for delete actions. `open` can be forced
  (e.g. keep a running task's tile expanded). Manual expand/collapse persists per
  tile in localStorage, so the page reloads the way the operator left it.
  Keyboard accessible: the header is a real <button> with aria-expanded + focus
  ring.
-->
<template>
  <v-card class="fc-tile" :class="{ 'fc-tile--open': isOpen }">
    <button
      type="button"
      class="fc-tile__head"
      :aria-expanded="isOpen"
      @click="toggle"
    >
      <v-icon
        :icon="icon"
        :color="destructive ? 'error' : 'accent'"
        class="fc-tile__icon"
      />
      <span class="fc-tile__text">
        <span class="fc-tile__title">{{ title }}</span>
        <span class="fc-tile__blurb">{{ blurb }}</span>
      </span>
      <v-icon
        :icon="isOpen ? 'mdi-chevron-up' : 'mdi-chevron-down'"
        class="fc-tile__chev"
      />
    </button>
    <v-expand-transition>
      <div v-show="isOpen" class="fc-tile__body">
        <slot />
      </div>
    </v-expand-transition>
  </v-card>
</template>

<script setup>
import { computed, ref, watch } from 'vue'

const props = defineProps({
  icon: { type: String, required: true },
  title: { type: String, required: true },
  blurb: { type: String, default: '' },
  destructive: { type: Boolean, default: false },
  // Force-open (e.g. a tile whose task is mid-run). When set, the operator can
  // still collapse it locally, but a change to `open` re-applies.
  open: { type: Boolean, default: false },
})

// Only MANUAL toggles are saved (keyed by tile title): a forced `open` while a
// task is mid-run is transient state, not a preference — persisting it would
// resurrect the "several tiles open by default" bug this replaces. When the
// force clears, the tile falls back to the operator's saved choice.
const storeKey = `fc.tile.${props.title}`
function savedOpen() {
  try { return localStorage.getItem(storeKey) === '1' } catch { return false }
}
const local = ref(props.open || savedOpen())
watch(() => props.open, (v) => { local.value = v || savedOpen() })
const isOpen = computed(() => local.value)

function toggle() {
  local.value = !local.value
  try { localStorage.setItem(storeKey, local.value ? '1' : '0') } catch { /* non-fatal */ }
}
</script>

<style scoped>
.fc-tile {
  border-radius: 8px;
  overflow: hidden;
}
.fc-tile__head {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  background: transparent;
  border: none;
  text-align: left;
  cursor: pointer;
  color: inherit;
}
.fc-tile__head:hover {
  background: rgba(var(--v-theme-on-surface), 0.04);
}
.fc-tile__head:focus-visible {
  outline: 2px solid rgb(var(--v-theme-accent));
  outline-offset: -2px;
}
.fc-tile__icon {
  flex: 0 0 auto;
}
.fc-tile__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1 1 auto;
}
.fc-tile__title {
  font-weight: 600;
  font-size: 0.95rem;
  line-height: 1.2;
}
.fc-tile__blurb {
  font-size: 0.8rem;
  line-height: 1.25;
  color: rgb(var(--v-theme-on-surface-variant));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fc-tile--open .fc-tile__blurb {
  white-space: normal;
}
.fc-tile__chev {
  flex: 0 0 auto;
  color: rgb(var(--v-theme-on-surface-variant));
}
.fc-tile__body {
  padding: 0 14px 14px;
}
</style>
