<script setup lang="ts">
/**
 * Props-driven `info-card` composition. Renders a read-only summary
 * tile: optional icon header, title, subtitle, and a list of
 * `{ label, value, icon? }` rows resolved from the data model.
 *
 * Self-contained — directly mountable in any Vue app:
 *
 *   <InfoCard
 *     title="Account summary"
 *     icon="user"
 *     :fields="[{ label: 'Name', value: 'user.name' }]"
 *     :item="{ user: { name: 'Jane' } }"
 *   />
 *
 * `field.value` is treated as a dot-path into `item`. When the path
 * resolves to `undefined` / `null` the row still renders so the label
 * remains visible — this matches v2 behaviour for info tiles.
 */
import { computed } from "vue"
import type { InfoCardField } from "@/definitions/cards/InfoCard"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"

export interface InfoCardProps {
  title?: string
  subtitle?: string
  showCard?: boolean
  icon?: string
  iconColor?: string
  headerImage?: string
  defaultHeaderImage?: string
  headerRatio?: string
  fields?: InfoCardField[]
  bodyClassList?: string[] | string
  lessPadding?: boolean
  /** Page-level data model used to resolve `field.value` dot-paths. */
  item?: Record<string, unknown>
}

const props = withDefaults(defineProps<InfoCardProps>(), {
  showCard: true,
  fields: () => [],
  lessPadding: false,
  item: () => ({}),
})

const showChrome = computed<boolean>(() => props.showCard !== false)

const hasHeader = computed<boolean>(
  () =>
    Boolean(props.title) ||
    Boolean(props.subtitle) ||
    Boolean(props.icon),
)

const fieldList = computed<InfoCardField[]>(() => props.fields ?? [])

const bodyClass = computed(() => {
  const list = props.bodyClassList
  if (!list) {
    return ""
  }
  return Array.isArray(list) ? list.join(" ") : list
})

function resolvePath(item: Record<string, unknown>, path: string): unknown {
  if (!path) {
    return undefined
  }
  const segments = path.split(".")
  let cursor: unknown = item
  for (const seg of segments) {
    if (cursor === null || cursor === undefined) {
      return undefined
    }
    if (typeof cursor !== "object") {
      return undefined
    }
    cursor = (cursor as Record<string, unknown>)[seg]
  }
  return cursor
}

function fieldClass(field: InfoCardField): string {
  const list = field.classList
  if (!list) {
    return ""
  }
  return Array.isArray(list) ? list.join(" ") : list
}

function formatValue(field: InfoCardField, raw: unknown): string {
  if (raw === undefined || raw === null || raw === "") {
    return ""
  }
  const text = typeof raw === "string" ? raw : String(raw)
  return `${field.prepend ?? ""}${text}${field.append ?? ""}`
}

function valueFor(field: InfoCardField): string {
  return formatValue(field, resolvePath(props.item, field.value))
}
</script>

<template>
  <Card v-if="showChrome" class="flex flex-col">
    <CardHeader v-if="hasHeader" class="flex flex-row items-start gap-3">
      <span
        v-if="icon"
        class="text-2xl leading-none"
        :style="{ color: iconColor ?? undefined }"
        :data-testid="`info-card-icon-${icon}`"
        aria-hidden="true"
      >
        {{ icon }}
      </span>
      <div class="flex flex-col gap-1.5">
        <CardTitle v-if="title">{{ title }}</CardTitle>
        <CardDescription v-if="subtitle">
          {{ subtitle }}
        </CardDescription>
      </div>
    </CardHeader>
    <CardContent
      :class="[
        bodyClass,
        lessPadding ? 'p-3' : '',
        hasHeader ? '' : 'pt-6',
      ]"
    >
      <dl
        v-if="fieldList.length"
        class="flex flex-col gap-2"
        data-testid="info-card-fields"
      >
        <div
          v-for="(field, index) in fieldList"
          :key="`${field.value}-${index}`"
          class="flex items-baseline justify-between gap-3"
          data-testid="info-card-field"
        >
          <dt class="flex items-center gap-1.5 text-sm text-muted-foreground">
            <span
              v-if="field.icon"
              class="text-base leading-none"
              :data-testid="`info-card-field-icon-${field.icon}`"
              aria-hidden="true"
            >
              {{ field.icon }}
            </span>
            <span v-if="field.label">{{ field.label }}</span>
          </dt>
          <dd
            class="text-sm font-medium text-foreground"
            :class="fieldClass(field)"
            data-testid="info-card-field-value"
          >
            {{ valueFor(field) }}
          </dd>
        </div>
      </dl>
    </CardContent>
  </Card>
  <section
    v-else
    class="flex flex-col gap-2"
    data-testid="info-card-bare"
  >
    <header v-if="hasHeader" class="flex flex-row items-start gap-3">
      <span
        v-if="icon"
        class="text-2xl leading-none"
        :style="{ color: iconColor ?? undefined }"
        :data-testid="`info-card-icon-${icon}`"
        aria-hidden="true"
      >
        {{ icon }}
      </span>
      <div class="flex flex-col gap-0.5">
        <h3 v-if="title" class="text-base font-semibold">
          {{ title }}
        </h3>
        <p v-if="subtitle" class="text-sm text-muted-foreground">
          {{ subtitle }}
        </p>
      </div>
    </header>
    <dl
      v-if="fieldList.length"
      class="flex flex-col gap-2"
      data-testid="info-card-fields"
    >
      <div
        v-for="(field, index) in fieldList"
        :key="`${field.value}-${index}`"
        class="flex items-baseline justify-between gap-3"
        data-testid="info-card-field"
      >
        <dt class="flex items-center gap-1.5 text-sm text-muted-foreground">
          <span
            v-if="field.icon"
            class="text-base leading-none"
            :data-testid="`info-card-field-icon-${field.icon}`"
            aria-hidden="true"
          >
            {{ field.icon }}
          </span>
          <span v-if="field.label">{{ field.label }}</span>
        </dt>
        <dd
          class="text-sm font-medium text-foreground"
          :class="fieldClass(field)"
          data-testid="info-card-field-value"
        >
          {{ valueFor(field) }}
        </dd>
      </div>
    </dl>
  </section>
</template>
