<script setup>
import { ref, computed } from "vue";
import Dropdown from "@/Components/Dropdown.vue";

const props = defineProps({
  events: Array,
  loading: Boolean,
  limit: Number,
});
const emits = defineEmits(["update:limit", "refresh"]);
function onLimit(e) {
  emits("update:limit", Number(e.target.value));
  emits("refresh");
}

// Level filter (all | error | warning | info/other)
const levelFilter = ref("all");
const levelOptions = [
  { value: "all", label: "All" },
  { value: "error", label: "Error" },
  { value: "warning", label: "Warning" },
  { value: "info", label: "Info / Other" },
];

const filteredEvents = computed(() => {
  if (levelFilter.value === "all") return props.events || [];
  if (levelFilter.value === "info") {
    return (props.events || []).filter(
      (e) => e.level !== "error" && e.level !== "warning"
    );
  }
  return (props.events || []).filter((e) => e.level === levelFilter.value);
});

// Expanded state per event id
const expanded = ref(new Set());
function isExpanded(id) {
  return expanded.value.has(id);
}
function toggleExpand(id) {
  if (expanded.value.has(id)) {
    expanded.value.delete(id);
  } else {
    expanded.value.add(id);
  }
  expanded.value = new Set(expanded.value);
}

function isLong(msg) {
  return msg && String(msg).length > 160;
}
function shortMsg(msg) {
  if (!msg) return "";
  const s = String(msg);
  return s.length <= 160 ? s : s.slice(0, 160) + "…";
}

function tryJson(val) {
  if (val == null) return null;
  if (typeof val === "object") return val;
  if (typeof val === "string") {
    const t = val.trim();
    if (
      (t.startsWith("{") && t.endsWith("}")) ||
      (t.startsWith("[") && t.endsWith("]"))
    ) {
      try {
        return JSON.parse(t);
      } catch {
        return null;
      }
    }
  }
  return null;
}

function contextPreview(ctx) {
  if (!ctx) return "";
  const obj = tryJson(ctx) || ctx;
  let str = typeof obj === "string" ? obj : JSON.stringify(obj);
  if (str.length > 60) str = str.slice(0, 60) + "…";
  return str;
}

// JSON formatting & lightweight syntax highlight
function htmlEscape(s) {
  return s
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;");
}

function prettyJson(val) {
  const obj = tryJson(val);
  if (!obj) {
    return htmlEscape(typeof val === "string" ? val : String(val ?? ""));
  }
  try {
    return htmlEscape(JSON.stringify(obj, null, 2));
  } catch {
    return htmlEscape(String(val ?? ""));
  }
}

function highlightJson(val) {
  const src = prettyJson(val);
  return src.replace(
    /(\"([^"\\]|\\.)*\"\s*:)|(\"([^"\\]|\\.)*\")|\b(true|false|null)\b|-?\b\d+(?:\.\d+)?(?:[eE][+\-]?\d+)?/g,
    (match) => {
      if (/^\"([^"\\]|\\.)*\"\s*:/.test(match)) {
        return `<span class=\"text-indigo-600\">${match}</span>`; // key
      }
      if (/^\"/.test(match)) {
        return `<span class=\"text-emerald-700\">${match}</span>`; // string
      }
      if (/true|false/.test(match)) {
        return `<span class=\"text-orange-600 font-medium\">${match}</span>`; // boolean
      }
      if (/null/.test(match)) {
        return `<span class=\"text-gray-500 italic\">${match}</span>`; // null
      }
      if (/^-?\d/.test(match)) {
        return `<span class=\"text-fuchsia-700\">${match}</span>`; // number
      }
      return match;
    }
  );
}

function formattedContext(ctx) {
  return highlightJson(ctx);
}
</script>

<template>
  <div class="pt-4">
    <div class="flex items-center justify-between mb-2">
      <h3 class="font-semibold">Logs</h3>
      <div class="flex items-center flex-wrap gap-2 text-sm">
        <label class="text-gray-600">Show</label>
        <select :value="limit" class="border rounded p-1" @change="onLimit">
          <option :value="50">50</option>
          <option :value="100">100</option>
          <option :value="200">200</option>
          <option :value="500">500</option>
        </select>
        <label class="text-gray-600 ml-2">Level</label>
        <select v-model="levelFilter" class="border rounded p-1">
          <option v-for="opt in levelOptions" :key="opt.value" :value="opt.value">
            {{ opt.label }}
          </option>
        </select>
        <button
          @click.prevent="$emit('refresh')"
          class="px-2 py-1 border rounded text-sm"
          :disabled="loading"
        >
          {{ loading ? "Refreshing…" : "Refresh" }}
        </button>
      </div>
    </div>
    <div class="overflow-x-auto max-h-[30rem] overflow-y-auto rounded border">
      <table class="min-w-full bg-white text-sm table-fixed">
        <colgroup>
          <col class="w-40" />
          <col class="w-20" />
          <col class="w-40" />
          <col />
          <col class="w-16" />
        </colgroup>
        <thead class="bg-gray-50 sticky top-0 z-10 shadow">
          <tr class="text-left text-xs uppercase text-gray-600">
            <th class="p-2 border">Time</th>
            <th class="p-2 border">Level</th>
            <th class="p-2 border">Event</th>
            <th class="p-2 border">Message</th>
            <th class="p-2 border">Row</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="ev in filteredEvents" :key="ev.id" class="border-t align-top">
            <td class="p-2 border whitespace-nowrap">
              {{ new Date(ev.created_at).toLocaleString() }}
            </td>
            <td class="p-2 border">
              <span
                :class="[
                  'px-2 py-0.5 rounded text-xs',
                  ev.level === 'error'
                    ? 'bg-red-100 text-red-800'
                    : ev.level === 'warning'
                    ? 'bg-amber-100 text-amber-800'
                    : 'bg-gray-100 text-gray-700',
                ]"
                >{{ ev.level }}</span
              >
            </td>
            <td class="p-2 border break-words max-w-[9rem]">
              <span class="block truncate" :title="ev.event">{{ ev.event }}</span>
            </td>
            <td class="p-2 border align-top max-w-[28rem]">
              <div class="space-y-1 break-words">
                <div class="leading-snug whitespace-pre-wrap">
                  <span v-if="!isLong(ev.message)">{{ ev.message }}</span>
                  <span v-else>
                    <span v-if="!isExpanded(ev.id)">{{ shortMsg(ev.message) }}</span>
                    <span v-else>{{ ev.message }}</span>
                    <button
                      type="button"
                      class="ml-2 inline-flex items-center gap-0.5 text-xs text-indigo-600 hover:underline"
                      @click="toggleExpand(ev.id)"
                    >
                      {{ isExpanded(ev.id) ? "Show less" : "Read more" }}
                    </button>
                  </span>
                </div>
                <div v-if="ev.context" class="text-xs text-gray-600">
                  <Dropdown
                    align="left"
                    width="wide"
                    :content-classes="[
                      'p-3',
                      'bg-white',
                      'text-xs',
                      'break-words',
                      'space-y-2',
                      'max-h-[28rem]',
                      'overflow-auto',
                      'max-w-[34rem]',
                    ]"
                    :close-on-content-click="false"
                  >
                    <template #trigger>
                      <button
                        type="button"
                        class="px-1.5 py-0.5 rounded border border-gray-300 bg-gray-50 hover:bg-gray-100 text-gray-700 transition text-[11px] font-medium"
                      >
                        Context: {{ contextPreview(ev.context) }}
                      </button>
                    </template>
                    <template #content>
                      <div
                        class="font-medium text-gray-700 mb-1 flex items-center justify-between"
                      >
                        <span>Context JSON</span>
                        <span class="text-[10px] text-gray-400">ID: {{ ev.id }}</span>
                      </div>
                      <pre
                        class="whitespace-pre break-words text-gray-800 text-[11px] leading-snug"
                      >
                        <code v-html="formattedContext(ev.context)"></code>
                      </pre>
                    </template>
                  </Dropdown>
                </div>
              </div>
            </td>
            <td class="p-2 border">{{ ev.import_row_id ?? "—" }}</td>
          </tr>
          <tr v-if="!filteredEvents.length">
            <td class="p-3 text-center text-gray-500" colspan="5">No events yet</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>
