<script setup lang="ts">
import { computed } from "vue";
import { useTranslations } from "../composables/useTranslations";
import { formatDateTime } from "../utils/formatDate";

type DiffEntry = { old: unknown; new: unknown };
type TranslationDiff = Record<string, Record<string, DiffEntry>>;
type MediaDiff = Record<string, { old: number[]; new: number[] }>;

type BlockGranularEntry =
  | {
      action: "added" | "removed";
      position: number;
      key: string;
      data: Record<string, unknown>;
      media: Record<string, number[]>;
    }
  | {
      action: "modified";
      position: number;
      key: string;
      data_diff: Record<string, DiffEntry>;
      media_diff: Record<string, { old: number[]; new: number[] }>;
    };

type BlockGranularDiff = Record<string, BlockGranularEntry[]>;
type TranslationBlockGranularDiff = Record<string, BlockGranularDiff>;

const props = defineProps<{
  diff: Record<string, DiffEntry>;
  translationDiff?: TranslationDiff;
  blockGranularDiff?: BlockGranularDiff;
  translationBlockGranularDiff?: TranslationBlockGranularDiff;
  mediaDiff?: MediaDiff;
  fieldLabels?: Record<string, string>;
  mediaNames?: Record<number, string>;
  blockLabels?: Record<string, string>;
  blockFieldLabels?: Record<string, Record<string, string>>;
}>();

const { t } = useTranslations();

function formatValue(value: unknown): string {
  if (value === null || value === undefined) {
    return "—";
  }
  if (typeof value === "boolean") {
    return value ? "true" : "false";
  }
  if (typeof value === "object") {
    const str = JSON.stringify(value);
    return str.length > 200 ? str.slice(0, 200) + "…" : str;
  }
  const str = String(value);
  const formatted = formatDateTime(str);
  if (formatted !== str) {
    return formatted;
  }
  return str.length > 200 ? str.slice(0, 200) + "…" : str;
}

function fieldLabel(key: string): string {
  if (props.fieldLabels?.[key]) {
    return props.fieldLabels[key];
  }
  return key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
}

function blockLabel(key: string): string {
  return props.blockLabels?.[key] ?? fieldLabel(key);
}

function blockFieldLabel(blockKey: string, fieldKey: string): string {
  return props.blockFieldLabels?.[blockKey]?.[fieldKey] ?? fieldLabel(fieldKey);
}

function mediaName(id: number): string {
  return props.mediaNames?.[id] ?? String(id);
}

function formatMediaIds(ids: number[]): string {
  if (ids.length === 0) {
    return "—";
  }
  return ids.map(mediaName).join(", ");
}

function summariseBlockData(data: Record<string, unknown>): string {
  const values = Object.values(data).filter(
    (v): v is string => typeof v === "string" && v.length > 0,
  );
  const first = values[0];
  if (!first) {
    return "—";
  }
  return first.length > 80 ? first.slice(0, 80) + "…" : first;
}

function actionBadgeClass(action: "added" | "removed" | "modified"): string {
  const map: Record<string, string> = {
    added:
      "bg-green-500/10 text-green-700 dark:text-green-400 border-green-200 dark:border-green-800",
    removed: "bg-destructive/10 text-destructive border-destructive/20",
    modified:
      "bg-amber-500/10 text-amber-700 dark:text-amber-400 border-amber-200 dark:border-amber-800",
  };
  return map[action] ?? "";
}

function actionBorderClass(action: "added" | "removed" | "modified"): string {
  const map: Record<string, string> = {
    added: "border-green-400 dark:border-green-600",
    removed: "border-destructive/60",
    modified: "border-amber-400 dark:border-amber-600",
  };
  return map[action] ?? "";
}

const hasDiff = computed(() => Object.keys(props.diff).length > 0);
const hasTranslationDiff = computed(
  () =>
    props.translationDiff !== undefined &&
    Object.keys(props.translationDiff).length > 0,
);
const hasBlockGranularDiff = computed(
  () =>
    props.blockGranularDiff !== undefined &&
    Object.keys(props.blockGranularDiff).length > 0,
);
const hasTranslationBlockGranularDiff = computed(
  () =>
    props.translationBlockGranularDiff !== undefined &&
    Object.keys(props.translationBlockGranularDiff).length > 0,
);
const hasMediaDiff = computed(
  () =>
    props.mediaDiff !== undefined && Object.keys(props.mediaDiff).length > 0,
);
</script>

<template>
  <div class="space-y-4">
    <!-- Base field diff -->
    <template v-if="hasDiff">
      <table class="w-full text-sm border-collapse">
        <thead>
          <tr class="border-b text-left text-muted-foreground">
            <th class="pb-2 pr-4 font-medium w-1/4">
              {{ t("builder.revisions.field") }}
            </th>
            <th class="pb-2 pr-4 font-medium w-[37.5%]">
              {{ t("builder.revisions.was") }}
            </th>
            <th class="pb-2 font-medium w-[37.5%]">
              {{ t("builder.revisions.now") }}
            </th>
          </tr>
        </thead>
        <tbody>
          <tr
            v-for="(entry, key) in diff"
            :key="key"
            class="border-b last:border-0"
          >
            <td class="py-2 pr-4 text-muted-foreground align-top">
              {{ fieldLabel(String(key)) }}
            </td>
            <td class="py-2 pr-4 align-top">
              <span
                class="font-mono text-xs bg-destructive/10 text-destructive px-1 py-0.5 rounded"
              >
                {{ formatValue(entry.old) }}
              </span>
            </td>
            <td class="py-2 align-top">
              <span
                class="font-mono text-xs bg-green-500/10 text-green-700 dark:text-green-400 px-1 py-0.5 rounded"
              >
                {{ formatValue(entry.new) }}
              </span>
            </td>
          </tr>
        </tbody>
      </table>
    </template>

    <!-- Translation field diff -->
    <template v-if="hasTranslationDiff">
      <div
        v-for="(localeDiff, locale) in translationDiff"
        :key="locale"
        class="space-y-2"
      >
        <p
          class="text-xs font-semibold uppercase tracking-wide text-muted-foreground"
        >
          {{ t("builder.revisions.translations") }} ({{ locale }})
        </p>
        <table class="w-full text-sm border-collapse">
          <tbody>
            <tr
              v-for="(entry, key) in localeDiff"
              :key="key"
              class="border-b last:border-0"
            >
              <td class="py-2 pr-4 text-muted-foreground align-top w-1/4">
                {{ fieldLabel(String(key)) }}
              </td>
              <td class="py-2 pr-4 align-top w-[37.5%]">
                <span
                  class="font-mono text-xs bg-destructive/10 text-destructive px-1 py-0.5 rounded"
                >
                  {{ formatValue(entry.old) }}
                </span>
              </td>
              <td class="py-2 align-top w-[37.5%]">
                <span
                  class="font-mono text-xs bg-green-500/10 text-green-700 dark:text-green-400 px-1 py-0.5 rounded"
                >
                  {{ formatValue(entry.new) }}
                </span>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </template>

    <!-- Granular block diff (non-translatable) -->
    <template v-if="hasBlockGranularDiff">
      <div class="space-y-3">
        <p
          class="text-xs font-semibold uppercase tracking-wide text-muted-foreground"
        >
          {{ t("builder.revisions.blocks") }}
        </p>
        <div
          v-for="(entries, collection) in blockGranularDiff"
          :key="collection"
          class="space-y-2"
        >
          <p class="text-xs text-muted-foreground font-medium">
            {{ String(collection) }}
          </p>
          <div
            v-for="entry in entries"
            :key="entry.position"
            class="ml-2 border-l-2 pl-3 py-1 space-y-1"
            :class="actionBorderClass(entry.action)"
          >
            <div class="flex items-center gap-2 text-xs">
              <span class="font-medium">{{ blockLabel(entry.key) }}</span>
              <span
                :class="[
                  'inline-flex items-center rounded border px-1.5 py-0.5 text-[10px] font-semibold',
                  actionBadgeClass(entry.action),
                ]"
              >
                {{ t(`builder.revisions.block_action_${entry.action}`) }}
              </span>
            </div>
            <template v-if="entry.action === 'modified'">
              <table
                v-if="Object.keys(entry.data_diff).length > 0"
                class="w-full text-xs border-collapse ml-2"
              >
                <tr
                  v-for="(fieldEntry, fieldKey) in entry.data_diff"
                  :key="fieldKey"
                  class="border-b last:border-0"
                >
                  <td class="py-1 pr-3 text-muted-foreground w-1/4 align-top">
                    {{ blockFieldLabel(entry.key, String(fieldKey)) }}
                  </td>
                  <td class="py-1 pr-3 align-top w-[37.5%]">
                    <span
                      class="font-mono bg-destructive/10 text-destructive px-1 rounded"
                    >
                      {{ formatValue(fieldEntry.old) }}
                    </span>
                  </td>
                  <td class="py-1 align-top w-[37.5%]">
                    <span
                      class="font-mono bg-green-500/10 text-green-700 dark:text-green-400 px-1 rounded"
                    >
                      {{ formatValue(fieldEntry.new) }}
                    </span>
                  </td>
                </tr>
              </table>
              <table
                v-if="Object.keys(entry.media_diff).length > 0"
                class="w-full text-xs border-collapse ml-2"
              >
                <tr
                  v-for="(mediaEntry, mediaKey) in entry.media_diff"
                  :key="mediaKey"
                  class="border-b last:border-0"
                >
                  <td class="py-1 pr-3 text-muted-foreground w-1/4 align-top">
                    {{ String(mediaKey) }}
                  </td>
                  <td class="py-1 pr-3 align-top w-[37.5%]">
                    <span
                      class="font-mono bg-destructive/10 text-destructive px-1 rounded"
                    >
                      {{ formatMediaIds(mediaEntry.old) }}
                    </span>
                  </td>
                  <td class="py-1 align-top w-[37.5%]">
                    <span
                      class="font-mono bg-green-500/10 text-green-700 dark:text-green-400 px-1 rounded"
                    >
                      {{ formatMediaIds(mediaEntry.new) }}
                    </span>
                  </td>
                </tr>
              </table>
            </template>
            <p
              v-else
              class="text-xs text-muted-foreground ml-2 italic truncate"
            >
              {{ summariseBlockData(entry.data) }}
            </p>
          </div>
        </div>
      </div>
    </template>

    <!-- Granular translation block diff -->
    <template v-if="hasTranslationBlockGranularDiff">
      <div
        v-for="(localeDiff, locale) in translationBlockGranularDiff"
        :key="locale"
        class="space-y-3"
      >
        <p
          class="text-xs font-semibold uppercase tracking-wide text-muted-foreground"
        >
          {{ t("builder.revisions.blocks") }} ({{ locale }})
        </p>
        <div
          v-for="(entries, collection) in localeDiff"
          :key="collection"
          class="space-y-2"
        >
          <p class="text-xs text-muted-foreground font-medium">
            {{ String(collection) }}
          </p>
          <div
            v-for="entry in entries"
            :key="entry.position"
            class="ml-2 border-l-2 pl-3 py-1 space-y-1"
            :class="actionBorderClass(entry.action)"
          >
            <div class="flex items-center gap-2 text-xs">
              <span class="font-medium">{{ blockLabel(entry.key) }}</span>
              <span
                :class="[
                  'inline-flex items-center rounded border px-1.5 py-0.5 text-[10px] font-semibold',
                  actionBadgeClass(entry.action),
                ]"
              >
                {{ t(`builder.revisions.block_action_${entry.action}`) }}
              </span>
            </div>
            <template v-if="entry.action === 'modified'">
              <table
                v-if="Object.keys(entry.data_diff).length > 0"
                class="w-full text-xs border-collapse ml-2"
              >
                <tr
                  v-for="(fieldEntry, fieldKey) in entry.data_diff"
                  :key="fieldKey"
                  class="border-b last:border-0"
                >
                  <td class="py-1 pr-3 text-muted-foreground w-1/4 align-top">
                    {{ blockFieldLabel(entry.key, String(fieldKey)) }}
                  </td>
                  <td class="py-1 pr-3 align-top w-[37.5%]">
                    <span
                      class="font-mono bg-destructive/10 text-destructive px-1 rounded"
                    >
                      {{ formatValue(fieldEntry.old) }}
                    </span>
                  </td>
                  <td class="py-1 align-top w-[37.5%]">
                    <span
                      class="font-mono bg-green-500/10 text-green-700 dark:text-green-400 px-1 rounded"
                    >
                      {{ formatValue(fieldEntry.new) }}
                    </span>
                  </td>
                </tr>
              </table>
              <table
                v-if="Object.keys(entry.media_diff).length > 0"
                class="w-full text-xs border-collapse ml-2"
              >
                <tr
                  v-for="(mediaEntry, mediaKey) in entry.media_diff"
                  :key="mediaKey"
                  class="border-b last:border-0"
                >
                  <td class="py-1 pr-3 text-muted-foreground w-1/4 align-top">
                    {{ String(mediaKey) }}
                  </td>
                  <td class="py-1 pr-3 align-top w-[37.5%]">
                    <span
                      class="font-mono bg-destructive/10 text-destructive px-1 rounded"
                    >
                      {{ formatMediaIds(mediaEntry.old) }}
                    </span>
                  </td>
                  <td class="py-1 align-top w-[37.5%]">
                    <span
                      class="font-mono bg-green-500/10 text-green-700 dark:text-green-400 px-1 rounded"
                    >
                      {{ formatMediaIds(mediaEntry.new) }}
                    </span>
                  </td>
                </tr>
              </table>
            </template>
            <p
              v-else
              class="text-xs text-muted-foreground ml-2 italic truncate"
            >
              {{ summariseBlockData(entry.data) }}
            </p>
          </div>
        </div>
      </div>
    </template>

    <!-- Media diff -->
    <template v-if="hasMediaDiff">
      <div class="space-y-2">
        <p
          class="text-xs font-semibold uppercase tracking-wide text-muted-foreground"
        >
          {{ t("builder.revisions.media") }}
        </p>
        <table class="w-full text-sm border-collapse">
          <tbody>
            <tr
              v-for="(entry, collection) in mediaDiff"
              :key="collection"
              class="border-b last:border-0"
            >
              <td class="py-2 pr-4 text-muted-foreground align-top w-1/4">
                {{ String(collection) }}
              </td>
              <td class="py-2 pr-4 align-top w-[37.5%]">
                <span
                  class="font-mono text-xs bg-destructive/10 text-destructive px-1 py-0.5 rounded"
                >
                  {{ formatMediaIds(entry.old) }}
                </span>
              </td>
              <td class="py-2 align-top w-[37.5%]">
                <span
                  class="font-mono text-xs bg-green-500/10 text-green-700 dark:text-green-400 px-1 py-0.5 rounded"
                >
                  {{ formatMediaIds(entry.new) }}
                </span>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </template>

    <p
      v-if="
        !hasDiff &&
        !hasTranslationDiff &&
        !hasBlockGranularDiff &&
        !hasTranslationBlockGranularDiff &&
        !hasMediaDiff
      "
      class="text-sm text-muted-foreground"
    >
      {{ t("builder.revisions.no_changes") }}
    </p>
  </div>
</template>
