<script setup>
import AdminLayout from "@/Layouts/AdminLayout.vue";
import { Head, Link, useForm, router, usePage } from "@inertiajs/vue3";
import { ref, watch, computed, onMounted, nextTick } from "vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { faArrowLeft, faEye } from "@fortawesome/free-solid-svg-icons";
// Ensure Quill is available before importing the wrapper component
import Quill from "quill";
if (typeof window !== "undefined" && !window.Quill) {
  // @ts-ignore
  window.Quill = Quill;
}
import "quill/dist/quill.snow.css";

const props = defineProps({
  template: { type: Object, default: null },
});

const form = useForm({
  name: props.template?.name ?? "",
  key: props.template?.key ?? "",
  subject_template: props.template?.subject_template ?? "",
  html_template: props.template?.html_template ?? "",
  text_template: props.template?.text_template ?? "",
  entity_types: props.template?.entity_types ?? ["client", "contract"],
  active: props.template?.active ?? true,
});

const preview = ref({ subject: "", html: "", text: "" });
const finalHtml = ref("");
const finalAttachments = ref([]);
const showFinal = ref(false);
const finalEmbedMode = ref("base64"); // 'base64' (default) or 'hosted' for diagnostics
const sendEmbedMode = ref("base64"); // embed mode for Send Test action
const isLocalHost = computed(() => {
  if (typeof window === "undefined") return false;
  const h = window.location.hostname || "";
  return /^(localhost|127\.0\.0\.1)$/i.test(h);
});
// If preview.html is empty (e.g., because only head/styles were changed), show the body-safe content from the current source as a fallback.
const previewHtml = computed(() => {
  const html = preview.value?.html || "";
  if (html.trim() !== "") {
    return containsDocScaffold(html) ? extractBody(html) : html;
  }
  // Fallback to local content if server preview didn't provide HTML
  return sourceMode.value
    ? extractBody(form.html_template || "")
    : stripDocScaffold(form.html_template || "");
});
const docsRaw = ref(props.template?.documents ? [...props.template.documents] : []);
const docs = computed(() =>
  (docsRaw.value ?? []).map((d) => ({
    ...d,
    url: d?.path ? `/storage/${d.path}` : null,
  }))
);
function updateLocalDoc(documentId, path, name = null, size = null) {
  if (!documentId) return;
  const idx = docsRaw.value.findIndex((d) => d.id === documentId);
  if (idx !== -1) {
    const next = { ...docsRaw.value[idx] };
    next.path = path ?? next.path;
    if (name) next.name = name;
    if (size != null) next.size = size;
    docsRaw.value.splice(idx, 1, next);
  }
}
function formatSize(bytes) {
  if (!bytes && bytes !== 0) return "";
  const kb = bytes / 1024;
  if (kb < 1024) return `${kb.toFixed(1)} KB`;
  const mb = kb / 1024;
  return `${mb.toFixed(2)} MB`;
}
const debounce = (fn, ms = 500) => {
  let t;
  return (...args) => {
    clearTimeout(t);
    t = setTimeout(() => fn(...args), ms);
  };
};

// Core preview fetcher; mirrors values when creating (no ID), calls backend when editing
const fetchPreview = () => {
  if (!props.template?.id) {
    preview.value = {
      subject: form.subject_template,
      html: form.html_template,
      text: form.text_template,
    };
    return;
  }
  window.axios
    .post(route("admin.email-templates.preview", props.template.id), {
      subject: form.subject_template,
      // Always send full HTML so head/styles can be respected and inlined server-side
      html: form.html_template,
      text: form.text_template,
      client_id: sample.value.client_id || undefined,
      case_id: sample.value.case_id || undefined,
      contract_id: sample.value.contract_id || undefined,
      extra: safeParseExtra(sample.value.extra),
    })
    .then((r) => {
      preview.value = r.data;
    });
};

const doPreview = debounce(fetchPreview, 400);

watch(
  () => [form.subject_template, form.html_template, form.text_template],
  () => doPreview(),
  { deep: true, immediate: true }
);

function submit() {
  if (props.template?.id) {
    form.put(route("admin.email-templates.update", props.template.id));
  } else {
    form.post(route("admin.email-templates.store"));
  }
}

async function fetchFinalHtml() {
  const { data } = await window.axios.post(
    route("admin.email-templates.render-final", props.template.id),
    {
      subject: form.subject_template,
      html: form.html_template,
      text: form.text_template,
      client_id: sample.value.client_id || undefined,
      case_id: sample.value.case_id || undefined,
      contract_id: sample.value.contract_id || undefined,
      extra: safeParseExtra(sample.value.extra),
      embed: finalEmbedMode.value,
    }
  );
  finalHtml.value = data?.html || "";
  finalAttachments.value = Array.isArray(data?.attachments) ? data.attachments : [];
}

async function openFinalHtmlDialog() {
  if (!props.template?.id) {
    alert("Najprej shranite predlogo.");
    return;
  }
  try {
    await fetchFinalHtml();
    showFinal.value = true;
  } catch (e) {
    console.error("Failed to render final HTML", e);
    alert("Neuspešen prikaz končne HTML vsebine.");
  }
}

function copyFinalHtml() {
  try {
    navigator.clipboard.writeText(finalHtml.value || "");
    alert("Končni HTML je kopiran v odložišče.");
  } catch (e) {
    console.warn("Clipboard write failed", e);
  }
}

function downloadFinalHtml() {
  const blob = new Blob([finalHtml.value || ""], { type: "text/html;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = `${(form.name || "email-template").replace(/[^a-z0-9-_]+/gi, "-")}.html`;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(url);
}

onMounted(() => {
  // Show something instantly and request preview immediately
  preview.value = {
    subject: form.subject_template,
    html: form.html_template,
    text: form.text_template,
  };
  // Populate cascading selects immediately so the Client dropdown isn't empty
  loadClients();
  fetchPreview();
  // Mount Quill editor directly
  try {
    if (quillContainer.value) {
      // instantiate lazily to ensure DOM is ready
      const editor = new Quill(quillContainer.value, {
        theme: "snow",
        modules: quillModules.value,
      });
      quill.value = editor;
      if (form.html_template) {
        const bodyOnly = stripDocScaffold(form.html_template);
        if (bodyOnly) {
          // Ensure Quill properly converts HTML to Delta
          editor.clipboard.dangerouslyPasteHTML(0, bodyOnly, "api");
        } else {
          editor.setText(
            "(Body is empty. Switch to Source HTML to edit full document.)",
            "api"
          );
        }
      }
      editor.on("text-change", (_delta, _old, source) => {
        // Ignore programmatic changes; only persist user edits
        if (source !== "user") {
          return;
        }
        if (!sourceMode.value) {
          const bodyHtml = editor.root.innerHTML;
          form.html_template = containsDocScaffold(form.html_template)
            ? replaceBody(form.html_template, bodyHtml)
            : bodyHtml;
        }
      });
    }
  } catch (e) {
    console.error("Failed to mount Quill", e);
  }
  // Initialize iframe editor if advanced mode is on
  if (advancedMode.value) {
    initIframeEditor();
  }
});

// --- Variable insertion and sample entity selection ---
const subjectRef = ref(null);
const quillContainer = ref(null);
const htmlSourceRef = ref(null);
const textRef = ref(null);
const activeField = ref(null); // 'subject' | 'html' | 'text'
const quill = ref(null);
const sourceMode = ref(false); // toggle for HTML source editing
// Advanced full-document editor that renders styles from <head>
const advancedMode = ref(false);
const iframeRef = ref(null);
let iframeSyncing = false;
const selectedImageSrc = ref("");

// Detect and handle full-document HTML so Quill doesn't wipe content
function containsDocScaffold(html) {
  if (!html || typeof html !== "string") return false;
  const h = html.toLowerCase();
  return (
    h.includes("<!doctype") ||
    h.includes("<html") ||
    h.includes("<head") ||
    h.includes("<body") ||
    h.includes("<style")
  );
}

function extractBody(html) {
  const m = /<body[^>]*>([\s\S]*?)<\/body>/i.exec(html);
  return m ? m[1] : html;
}

function stripDocScaffold(html) {
  if (!html) return "";
  let out = html;
  // Prefer body content when present
  out = extractBody(out);
  // Remove comments, doctype, html/head blocks, meta/title, and styles (Quill can't keep these)
  out = out
    .replace(/<!DOCTYPE[\s\S]*?>/gi, "")
    .replace(/<\/?html[^>]*>/gi, "")
    .replace(/<head[\s\S]*?>[\s\S]*?<\/head>/gi, "")
    .replace(/<\/?meta[^>]*>/gi, "")
    .replace(/<title[\s\S]*?>[\s\S]*?<\/title>/gi, "")
    .replace(/<style[\s\S]*?>[\s\S]*?<\/style>/gi, "");
  return out.trim();
}

// Replace only the inner content of <body>...</body> in a full document
function replaceBody(htmlDoc, newBody) {
  if (!htmlDoc || typeof htmlDoc !== "string") return newBody || "";
  const hasBody = /<body[^>]*>[\s\S]*?<\/body>/i.test(htmlDoc);
  if (!hasBody) {
    return newBody || "";
  }
  return htmlDoc.replace(/(<body[^>]*>)[\s\S]*?(<\/body>)/i, `$1${newBody || ""}$2`);
}

// Keep Quill and textarea in sync when toggling source mode
watch(
  () => sourceMode.value,
  (on) => {
    if (on) {
      // Switching to source view: if current model is NOT a full document,
      // sync from Quill. Otherwise, keep the full source untouched.
      if (quill.value && !containsDocScaffold(form.html_template)) {
        form.html_template = quill.value.root.innerHTML;
      }
    } else {
      // switching back to WYSIWYG: update editor html from model
      if (quill.value) {
        const bodyOnly = stripDocScaffold(form.html_template || "");
        if (bodyOnly) {
          quill.value.clipboard.dangerouslyPasteHTML(0, bodyOnly, "api");
        } else {
          quill.value.setText(
            "(Body is empty. Switch to Source HTML to edit full document.)",
            "api"
          );
        }
      } else if (quillContainer.value) {
        // if the instance doesn't exist for any reason, re-create it
        const editor = new Quill(quillContainer.value, {
          theme: "snow",
          modules: quillModules.value,
        });
        quill.value = editor;
        const bodyOnly = stripDocScaffold(form.html_template || "");
        if (bodyOnly) {
          editor.clipboard.dangerouslyPasteHTML(0, bodyOnly, "api");
        } else {
          editor.setText(
            "(Body is empty. Switch to Source HTML to edit full document.)",
            "api"
          );
        }
        editor.on("text-change", (_d, _o, source) => {
          if (source !== "user") {
            return;
          }
          if (!sourceMode.value) {
            const bodyHtml = editor.root.innerHTML;
            form.html_template = containsDocScaffold(form.html_template)
              ? replaceBody(form.html_template, bodyHtml)
              : bodyHtml;
          }
        });
      }
    }
  }
);

// Keep advanced editor in a stable state with source/quill
watch(
  () => advancedMode.value,
  async (on) => {
    if (on) {
      sourceMode.value = false;
      await nextTick();
      initIframeEditor();
    }
  }
);

// When HTML changes externally, reflect it into iframe (unless we're the ones syncing)
watch(
  () => form.html_template,
  async () => {
    if (!advancedMode.value || iframeSyncing) return;
    await nextTick();
    writeIframeDocument();
  }
);

function ensureFullDoc(html) {
  if (!html)
    return '<!doctype html><html><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /></head><body></body></html>';
  if (/<html[\s\S]*<\/html>/i.test(html)) return html;
  return `<!doctype html><html><head><meta charset=\"utf-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /></head><body>${html}</body></html>`;
}

function writeIframeDocument() {
  const iframe = iframeRef.value;
  if (!iframe) return;
  const doc = iframe.contentDocument;
  if (!doc) return;
  const html = ensureFullDoc(form.html_template || "");
  doc.open();
  doc.write(html);
  doc.close();
  try {
    doc.body.setAttribute("spellcheck", "false");
  } catch {}
}

function initIframeEditor() {
  writeIframeDocument();
  const iframe = iframeRef.value;
  if (!iframe) return;
  const doc = iframe.contentDocument;
  if (!doc) return;
  try {
    doc.designMode = "on";
  } catch {}
  // track selected image src on click
  doc.addEventListener("click", (e) => {
    const t = e.target;
    if (t && t.tagName === "IMG") {
      selectedImageSrc.value = t.getAttribute("src") || "";
    } else {
      selectedImageSrc.value = "";
    }
  });
  const handler = debounce(() => {
    if (!advancedMode.value) return;
    try {
      iframeSyncing = true;
      const full = doc.documentElement.outerHTML;
      form.html_template = full;
    } finally {
      iframeSyncing = false;
    }
  }, 250);
  doc.addEventListener("input", handler);
  doc.addEventListener("keyup", handler);
}

function iframeExec(command, value = null) {
  const iframe = iframeRef.value;
  if (!iframe) return;
  const doc = iframe.contentDocument;
  if (!doc) return;
  try {
    doc.body.focus();
  } catch {}
  try {
    doc.execCommand(command, false, value);
  } catch (e) {
    console.warn("execCommand failed", command, e);
  }
}

async function iframeInsertImage() {
  const input = document.createElement("input");
  input.type = "file";
  input.accept = "image/*";
  input.onchange = async () => {
    const file = input.files?.[0];
    if (!file) return;
    const data = new FormData();
    data.append("file", file);
    try {
      const { data: res } = await window.axios.post(
        route("admin.email-templates.upload-image"),
        data,
        { headers: { "Content-Type": "multipart/form-data" } }
      );
      const url = res?.url;
      const documentId = res?.document_id;
      if (url) {
        iframeExec("insertImage", url);
      }
    } catch (e) {
      console.error("Image upload failed", e);
    }
  };
  input.click();
}

async function iframeReplaceSelectedImage() {
  if (!props.template?.id) {
    alert("Najprej shranite predlogo, nato zamenjajte sliko.");
    return;
  }
  if (!selectedImageSrc.value) {
    alert("Najprej kliknite na sliko v dokumentu, ki jo želite zamenjati.");
    return;
  }
  const input = document.createElement("input");
  input.type = "file";
  input.accept = "image/*";
  input.onchange = async () => {
    const file = input.files?.[0];
    if (!file) return;
    const data = new FormData();
    data.append("file", file);
    data.append("current_src", selectedImageSrc.value);
    try {
      const { data: res } = await window.axios.post(
        route("admin.email-templates.replace-image", props.template.id),
        data,
        { headers: { "Content-Type": "multipart/form-data" } }
      );
      const url = res?.url;
      if (url) {
        // Replace src in the iframe document
        const iframe = iframeRef.value;
        const doc = iframe?.contentDocument;
        if (doc) {
          // Update only the selected image if possible, else do a global replace
          const imgs = Array.from(doc.querySelectorAll("img"));
          const img = imgs.find(
            (im) => (im.getAttribute("src") || "") === selectedImageSrc.value
          );
          if (img) {
            img.setAttribute("src", url);
          } else {
            doc.body.innerHTML = doc.body.innerHTML.replaceAll(
              selectedImageSrc.value,
              url
            );
          }
          // Sync back to the model
          iframeSyncing = true;
          form.html_template = doc.documentElement.outerHTML;
          iframeSyncing = false;
          selectedImageSrc.value = url;
        }
        if (documentId && res?.path) {
          updateLocalDoc(documentId, res.path, null, res?.size ?? null);
        }
      }
    } catch (e) {
      console.error("Replace image failed", e);
    }
  };
  input.click();
}

function setActive(field) {
  activeField.value = field;
}

function insertAtCursor(el, value, modelGetter, modelSetter) {
  if (!el) return;
  const start = el.selectionStart ?? 0;
  const end = el.selectionEnd ?? 0;
  const current = modelGetter();
  const next = current.slice(0, start) + value + current.slice(end);
  modelSetter(next);
  // restore caret after inserted value
  requestAnimationFrame(() => {
    el.focus();
    const pos = start + value.length;
    try {
      el.setSelectionRange(pos, pos);
    } catch {}
  });
}

function insertPlaceholder(token) {
  const content = `{{ ${token} }}`;
  if (activeField.value === "subject" && subjectRef.value) {
    insertAtCursor(
      subjectRef.value,
      content,
      () => form.subject_template,
      (v) => (form.subject_template = v)
    );
  } else if (activeField.value === "html") {
    // If in source mode, treat HTML as textarea
    if (sourceMode.value && htmlSourceRef.value) {
      insertAtCursor(
        htmlSourceRef.value,
        content,
        () => form.html_template,
        (v) => (form.html_template = v)
      );
      return;
    }
    // Insert into Quill editor at current selection
    if (quill.value) {
      let range = quill.value.getSelection(true);
      const index = range ? range.index : quill.value.getLength() - 1;
      quill.value.insertText(index, content, "user");
      quill.value.setSelection(index + content.length, 0, "user");
      // Sync back to form model as HTML
      form.html_template = quill.value.root.innerHTML;
    } else {
      // Fallback: append to the end of the model
      form.html_template = (form.html_template || "") + content;
    }
  } else if (activeField.value === "text" && textRef.value) {
    insertAtCursor(
      textRef.value,
      content,
      () => form.text_template,
      (v) => (form.text_template = v)
    );
  }
}

// Quill toolbar & image upload handler
const quillModules = computed(() => ({
  toolbar: {
    container: [
      ["bold", "italic", "underline", "strike"],
      [{ header: [1, 2, 3, false] }],
      [{ list: "ordered" }, { list: "bullet" }],
      ["link", "image"],
      [{ align: [] }],
      ["clean"],
    ],
    handlers: {
      image: () => onQuillImageUpload(),
    },
  },
}));

function onQuillImageUpload() {
  const input = document.createElement("input");
  input.type = "file";
  input.accept = "image/*";
  input.onchange = async () => {
    const file = input.files?.[0];
    if (!file) return;
    const data = new FormData();
    data.append("file", file);
    try {
      const { data: res } = await window.axios.post(
        route("admin.email-templates.upload-image"),
        data,
        { headers: { "Content-Type": "multipart/form-data" } }
      );
      const url = res?.url;
      if (url && quill.value) {
        const range = quill.value.getSelection(true);
        const index = range ? range.index : quill.value.getLength();
        quill.value.insertEmbed(index, "image", url, "user");
        quill.value.setSelection(index + 1, 0, "user");
        form.html_template = quill.value.root.innerHTML;
      }
    } catch (e) {
      // optional: show toast
      console.error("Image upload failed", e);
    }
  };
  input.click();
}

const placeholderGroups = computed(() => {
  const groups = [];
  const want = new Set(form.entity_types || []);
  const add = (key, label, tokens) => groups.push({ key, label, tokens });
  if (want.has("person")) {
    add("person", "Person", [
      "person.first_name",
      "person.last_name",
      "person.full_name",
      "person.email",
      "person.phone",
    ]);
  }
  if (want.has("client")) {
    add("client", "Client", ["client.id", "client.uuid"]);
  }
  if (want.has("client_case")) {
    add("case", "Case", ["case.id", "case.uuid", "case.reference"]);
  }
  if (want.has("contract")) {
    add("contract", "Contract", [
      "contract.id",
      "contract.uuid",
      "contract.reference",
      "contract.amount",
      "contract.meta.some_key",
    ]);
  }
  // Extra is always useful for ad-hoc data
  add("extra", "Extra", ["extra.some_key"]);
  return groups;
});

// Sample entity selection for preview
const sample = ref({ client_id: "", case_id: "", contract_id: "", extra: "" });

// Cascading select options
const clients = ref([]);
const cases = ref([]);
const contracts = ref([]);

async function loadClients() {
  const { data } = await window.axios.get(route("admin.email-templates.data.clients"));
  clients.value = data;
}
async function loadCases(clientId) {
  if (!clientId) {
    cases.value = [];
    return;
  }
  const { data } = await window.axios.get(
    route("admin.email-templates.data.cases", clientId)
  );
  cases.value = data;
}
async function loadContracts(caseId) {
  if (!caseId) {
    contracts.value = [];
    return;
  }
  const { data } = await window.axios.get(
    route("admin.email-templates.data.contracts", caseId)
  );
  contracts.value = data;
}

watch(
  () => sample.value.client_id,
  (v) => {
    sample.value.case_id = "";
    sample.value.contract_id = "";
    loadCases(v);
    doPreview();
  }
);
watch(
  () => sample.value.case_id,
  (v) => {
    sample.value.contract_id = "";
    loadContracts(v);
    doPreview();
  }
);
watch(
  () => sample.value.contract_id,
  () => doPreview()
);

function applySample() {
  fetchPreview();
  loadClients();
}

function safeParseExtra(input) {
  if (!input || typeof input !== "string") return undefined;
  try {
    const parsed = JSON.parse(input);
    return typeof parsed === "object" && parsed !== null ? parsed : undefined;
  } catch {
    return undefined;
  }
}

function sendTest() {
  if (!props.template?.id) {
    alert("Najprej shranite predlogo, nato pošljite test.");
    return;
  }
  if (!sample.value.to) {
    alert("Vnesite ciljni email naslov.");
    return;
  }
  const payload = {
    subject: form.subject_template,
    html: form.html_template,
    text: form.text_template,
    client_id: sample.value.client_id || undefined,
    person_id: sample.value.person_id || undefined,
    case_id: sample.value.case_id || undefined,
    contract_id: sample.value.contract_id || undefined,
    extra: safeParseExtra(sample.value.extra),
    to: sample.value.to,
    embed: sendEmbedMode.value,
  };

  // Small helper for simple notifications without reloading
  const notify = (message, _type = "info") => {
    if (!message) {
      return;
    }
    // Replace with your app's toast if available
    alert(message);
  };

  router.post(route("admin.email-templates.send-test", props.template.id), payload, {
    preserveScroll: true,
    preserveState: true,
    onSuccess: () => {
      try {
        const page = usePage();
        const flash = page?.props?.flash ?? {};
        if (flash.success) {
          notify(flash.success, "success");
          return;
        }
        if (flash.error) {
          notify(flash.error, "error");
          return;
        }
      } catch {}
      notify("Testni e-poštni naslov je bil poslan.", "success");
    },
    onError: () => {
      // Validation errors trigger onError; controller may also set flash('error') on redirect
      try {
        const page = usePage();
        const flash = page?.props?.flash ?? {};
        if (flash.error) {
          notify(flash.error, "error");
          return;
        }
      } catch {}
      notify(
        "Pri pošiljanju testnega e-poštnega sporočila je prišlo do napake.",
        "error"
      );
    },
  });
}
</script>

<template>
  <AdminLayout :title="props.template ? 'Uredi predlogo' : 'Nova predloga'">
    <Head :title="props.template ? 'Uredi predlogo' : 'Nova predloga'" />

    <div class="mb-4 flex items-center justify-between">
      <div class="flex items-center gap-3">
        <Link
          :href="route('admin.email-templates.index')"
          class="text-sm text-gray-600 hover:text-gray-800 inline-flex items-center gap-2"
        >
          <FontAwesomeIcon :icon="faArrowLeft" class="w-4 h-4" /> Nazaj
        </Link>
        <h1 class="text-xl font-semibold text-gray-800">
          {{ props.template ? "Uredi predlogo" : "Nova predloga" }}
        </h1>
      </div>
      <button
        @click="submit"
        :disabled="form.processing"
        class="px-4 py-2 text-sm rounded-md bg-indigo-600 text-white hover:bg-indigo-500 disabled:opacity-50"
      >
        Shrani
      </button>
    </div>

    <div class="space-y-6">
      <!-- Editor card -->
      <div class="rounded-xl border bg-white/60 backdrop-blur-sm shadow-sm p-5 space-y-5">
        <div class="flex items-center justify-between">
          <div class="font-semibold text-gray-900">Urejevalnik</div>
        </div>
        <!-- Variable insertion toolbar -->
        <div class="mb-2">
          <div class="text-xs uppercase tracking-wider text-gray-500 font-semibold mb-2">
            Vstavitev spremenljivk
          </div>
          <div class="flex flex-wrap gap-2">
            <template v-for="grp in placeholderGroups" :key="grp.key">
              <div class="flex items-center gap-2">
                <div class="text-[11px] text-gray-500 font-semibold w-16">
                  {{ grp.label }}
                </div>
                <div class="flex flex-wrap gap-1">
                  <button
                    v-for="t in grp.tokens"
                    :key="t"
                    type="button"
                    class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100 text-gray-700 transition-colors"
                    @click="insertPlaceholder(t)"
                  >
                    {{ t }}
                  </button>
                </div>
              </div>
            </template>
          </div>
        </div>
        <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
          <div>
            <label class="label">Ime</label>
            <input v-model="form.name" type="text" class="input" />
          </div>
          <div>
            <label class="label">Ključ</label>
            <input
              v-model="form.key"
              type="text"
              class="input"
              placeholder="e.g. welcome_email"
            />
          </div>
          <div class="md:col-span-2">
            <label class="label">Subject</label>
            <input
              v-model="form.subject_template"
              type="text"
              class="input"
              placeholder="Welcome, {{ person.full_name }}"
              ref="subjectRef"
              @focus="setActive('subject')"
            />
          </div>
          <div class="md:col-span-2">
            <div class="flex items-center justify-between">
              <label class="label">HTML vsebina</label>
              <div class="flex items-center gap-4 text-xs text-gray-600">
                <label class="inline-flex items-center gap-2">
                  <input type="checkbox" v-model="advancedMode" /> Napredni (poln
                  dokument)
                </label>
                <label class="inline-flex items-center gap-2">
                  <input type="checkbox" v-model="sourceMode" :disabled="advancedMode" />
                  Source HTML
                </label>
              </div>
            </div>
            <!-- Quill body editor (hidden when advanced editor is active) -->
            <div v-show="!sourceMode && !advancedMode">
              <div
                ref="quillContainer"
                class="bg-white border rounded-lg min-h-[260px] p-2 focus-within:ring-2 ring-indigo-500/40"
                @focusin="setActive('html')"
              ></div>
            </div>
            <!-- Source HTML textarea -->
            <div v-show="sourceMode && !advancedMode">
              <textarea
                v-model="form.html_template"
                rows="12"
                class="input font-mono"
                ref="htmlSourceRef"
                @focus="setActive('html')"
              ></textarea>
            </div>
            <!-- Advanced full-document editor (iframe) -->
            <div v-show="advancedMode" class="space-y-2">
              <div class="flex flex-wrap gap-2">
                <button
                  type="button"
                  class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
                  @click="() => iframeExec('bold')"
                >
                  B
                </button>
                <button
                  type="button"
                  class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
                  @click="() => iframeExec('italic')"
                >
                  <i>I</i>
                </button>
                <button
                  type="button"
                  class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
                  @click="() => iframeExec('underline')"
                >
                  <u>U</u>
                </button>
                <button
                  type="button"
                  class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
                  @click="() => iframeExec('insertUnorderedList')"
                >
                  • List
                </button>
                <button
                  type="button"
                  class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
                  @click="() => iframeExec('insertOrderedList')"
                >
                  1. List
                </button>
                <button
                  type="button"
                  class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
                  @click="iframeInsertImage"
                >
                  Slika
                </button>
                <button
                  type="button"
                  class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100 disabled:opacity-50"
                  :disabled="!selectedImageSrc"
                  @click="iframeReplaceSelectedImage"
                >
                  Zamenjaj izbrano sliko
                </button>
                <button
                  type="button"
                  class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
                  @click="() => iframeExec('justifyLeft')"
                >
                  Levo
                </button>
                <button
                  type="button"
                  class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
                  @click="() => iframeExec('justifyCenter')"
                >
                  Center
                </button>
                <button
                  type="button"
                  class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
                  @click="() => iframeExec('justifyRight')"
                >
                  Desno
                </button>
              </div>
              <iframe ref="iframeRef" class="w-full h-[360px] border rounded"></iframe>
              <div class="text-[11px] text-gray-500">
                Opomba: Napredni urejevalnik prikazuje celoten dokument v iframe, zato
                boste videli učinek stilov iz &lt;head&gt;. Pri pošiljanju se CSS še vedno
                pretvori v inline stile za email.
              </div>
              <div class="text-[11px] text-gray-500">
                Namig: če oznaka <code>&lt;img&gt;</code> nima atributa <code>src</code>,
                bo ob predogledu in pošiljanju sistem poskušal samodejno nastaviti sliko
                na podlagi pripetih slik te predloge. Najprej se išče ujemanje po
                <code>alt</code> (npr. <code>alt="Logo"</code> → dokument z imenom
                »logo«); če je pripeta le ena slika, bo uporabljena ta.
              </div>
            </div>
          </div>
          <div class="md:col-span-2">
            <label class="label">Text vsebina</label>
            <textarea
              v-model="form.text_template"
              rows="6"
              class="input font-mono"
              ref="textRef"
              @focus="setActive('text')"
            ></textarea>
          </div>
          <div>
            <label class="label">Entity types</label>
            <div class="flex flex-wrap gap-3 text-sm">
              <label class="inline-flex items-center gap-2"
                ><input type="checkbox" value="client" v-model="form.entity_types" />
                client</label
              >
              <label class="inline-flex items-center gap-2"
                ><input type="checkbox" value="client_case" v-model="form.entity_types" />
                client_case</label
              >
              <label class="inline-flex items-center gap-2"
                ><input type="checkbox" value="contract" v-model="form.entity_types" />
                contract</label
              >
              <label class="inline-flex items-center gap-2"
                ><input type="checkbox" value="person" v-model="form.entity_types" />
                person</label
              >
            </div>
          </div>
          <div class="flex items-center gap-2">
            <input id="active" type="checkbox" v-model="form.active" />
            <label for="active" class="text-sm text-gray-700">Aktivno</label>
          </div>
        </div>
      </div>

      <!-- Preview card -->
      <div class="rounded-xl border bg-white/60 backdrop-blur-sm shadow-sm p-5 space-y-5">
        <div class="flex items-center justify-between">
          <div class="font-semibold text-gray-900">Predogled</div>
          <button
            @click="doPreview"
            class="text-xs inline-flex items-center gap-2 px-2.5 py-1.5 rounded-md border text-gray-700 bg-gray-50 hover:bg-gray-100 transition-colors"
          >
            <FontAwesomeIcon :icon="faEye" class="w-3.5 h-3.5" /> Osveži
          </button>
        </div>
        <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
          <div>
            <div class="label">Sample entities</div>
            <div class="grid grid-cols-2 gap-2">
              <label class="text-xs text-gray-600">
                Client
                <select v-model="sample.client_id" class="input h-9">
                  <option value="">—</option>
                  <option v-for="c in clients" :key="c.id" :value="c.id">
                    {{ c.label }}
                  </option>
                </select>
              </label>
              <label class="text-xs text-gray-600">
                Case
                <select
                  v-model="sample.case_id"
                  class="input h-9"
                  :disabled="!sample.client_id"
                >
                  <option value="">—</option>
                  <option v-for="cs in cases" :key="cs.id" :value="cs.id">
                    {{ cs.label }}
                  </option>
                </select>
              </label>
              <label class="text-xs text-gray-600">
                Contract
                <select
                  v-model="sample.contract_id"
                  class="input h-9"
                  :disabled="!sample.case_id"
                >
                  <option value="">—</option>
                  <option v-for="ct in contracts" :key="ct.id" :value="ct.id">
                    {{ ct.label }}
                  </option>
                </select>
              </label>
              <div class="col-span-2">
                <label class="text-xs text-gray-600"
                  >Extra (JSON)
                  <textarea
                    rows="3"
                    v-model="sample.extra"
                    class="input font-mono"
                    placeholder='{"note":"hello"}'
                  ></textarea>
                </label>
              </div>
            </div>
            <div class="mt-2">
              <button
                @click="applySample"
                type="button"
                class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
              >
                Uporabi sample
              </button>
            </div>
          </div>
          <div>
            <div class="label">Subject</div>
            <div class="p-2 rounded bg-gray-50 text-sm">{{ preview.subject }}</div>
          </div>
        </div>
        <div>
          <div class="label">HTML</div>
          <div
            class="p-3 rounded-lg bg-gray-50 border ql-editor max-h-[480px] overflow-auto"
            v-html="previewHtml"
          ></div>
        </div>
        <div>
          <div class="label">Text</div>
          <pre class="p-3 rounded-lg bg-gray-50 border text-xs whitespace-pre-wrap">{{
            preview.text
          }}</pre>
        </div>
        <div class="text-xs text-gray-500" v-pre>
          Available placeholders example: {{ person.full_name }}, {{ client.uuid }},
          {{ case.reference }}, {{ contract.reference }}, {{ contract.meta.some_key }}
        </div>
        <div class="mt-4 flex flex-col sm:flex-row sm:items-end gap-2">
          <div class="w-full sm:w-auto">
            <label class="label">Pošlji test na</label>
            <input
              type="email"
              v-model="sample.to"
              class="input"
              placeholder="name@example.com"
            />
          </div>
          <div class="w-full sm:w-auto">
            <label class="label">Način slik</label>
            <select v-model="sendEmbedMode" class="input">
              <option value="base64">Vdelano (base64)</option>
              <option value="hosted">Gostovano (absolutni URL)</option>
            </select>
            <div
              v-if="sendEmbedMode === 'hosted' && isLocalHost"
              class="text-[11px] text-amber-600 mt-1"
            >
              Pozor: Uporabljate "localhost". Gmail/Outlook ne moreta pridobiti slik z
              lokalnega strežnika. Nastavite APP_URL/ASSET_URL na javni HTTPS domeni ali
              uporabite tunel (npr. ngrok) za test.
            </div>
          </div>
          <button
            type="button"
            class="h-9 inline-flex items-center px-3 rounded-md border border-indigo-600 bg-indigo-600 text-white text-xs hover:bg-indigo-500 transition-colors"
            @click="sendTest"
          >
            Pošlji test
          </button>
          <button
            type="button"
            class="h-9 inline-flex items-center px-3 rounded-md border text-xs bg-gray-50 hover:bg-gray-100"
            @click="openFinalHtmlDialog"
          >
            Pokaži končni HTML
          </button>
        </div>
      </div>

      <!-- Manage images panel -->
      <div class="rounded-xl border bg-white/60 backdrop-blur-sm shadow-sm p-5 space-y-3">
        <div class="flex items-center justify-between">
          <div class="font-semibold text-gray-800">Pripete slike</div>
          <div class="text-xs text-gray-500">
            Slike se shranijo ob shranjevanju predloge ali pošiljanju testa.
          </div>
        </div>
        <div v-if="props.template && docs.length" class="divide-y border rounded">
          <div
            v-for="d in docs"
            :key="d.id"
            class="flex items-center justify-between p-2 text-sm"
          >
            <div class="flex items-center gap-3 min-w-0">
              <a
                v-if="d.url"
                :href="d.url"
                target="_blank"
                class="text-indigo-600 hover:underline truncate"
              >
                {{ d.name || d.file_name || d.path }}
              </a>
              <span v-else class="text-gray-700 truncate">{{
                d.name || d.file_name || d.path
              }}</span>
              <span class="text-xs text-gray-500">{{ formatSize(d.size) }}</span>
            </div>
            <div class="flex items-center gap-2">
              <a
                v-if="d.url"
                :href="d.url"
                target="_blank"
                class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
                >Odpri</a
              >
            </div>
          </div>
        </div>
        <div v-else class="text-sm text-gray-500">Ni pripetih slik.</div>
        <div class="text-xs text-gray-500">
          Če se slike v urejevalniku ne prikazujejo, preverite ali imate vzpostavljeno
          povezavo do javnega diska (ukaz: storage:link).
        </div>
      </div>
    </div>
  </AdminLayout>

  <!-- Final HTML dialog -->
  <div
    v-if="showFinal"
    class="fixed inset-0 z-50 flex items-center justify-center bg-black/40"
    @click.self="showFinal = false"
  >
    <div
      class="bg-white rounded-lg shadow-xl max-w-5xl w-[92vw] max-h-[84vh] flex flex-col"
    >
      <div class="px-4 py-2 border-b flex items-center justify-between gap-2">
        <div class="font-semibold text-gray-800 text-sm">
          Končni HTML (točno to se pošlje)
        </div>
        <div class="flex items-center gap-2">
          <div class="flex items-center gap-1 text-[11px] text-gray-700">
            Način slik:
            <select
              v-model="finalEmbedMode"
              @change="fetchFinalHtml"
              class="border rounded px-2 py-1 text-[11px] bg-white hover:bg-gray-50"
            >
              <option value="base64">Vdelano (base64)</option>
              <option value="hosted">Gostovano (absolutni URL)</option>
            </select>
          </div>
          <div
            v-if="finalEmbedMode === 'hosted' && isLocalHost"
            class="text-[11px] text-amber-600"
          >
            Pozor: Uporabljate "localhost". Gmail/Outlook ne moreta pridobiti slik z
            lokalnega strežnika.
          </div>
          <button
            class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
            @click="copyFinalHtml"
          >
            Kopiraj
          </button>
          <button
            class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
            @click="downloadFinalHtml"
          >
            Prenesi .html
          </button>
          <button
            class="text-xs px-2 py-1 rounded border bg-gray-50 hover:bg-gray-100"
            @click="showFinal = false"
          >
            Zapri
          </button>
        </div>
      </div>
      <div class="p-3 overflow-auto space-y-3">
        <div v-if="finalAttachments.length" class="text-[11px] text-gray-600">
          <div class="font-semibold mb-1">CID priponke:</div>
          <ul class="list-disc pl-5">
            <li v-for="a in finalAttachments" :key="a.cid">
              <code>{{ a.src }}</code> → <code>cid:{{ a.cid }}</code>
            </li>
          </ul>
        </div>
        <pre class="text-xs whitespace-pre-wrap break-words">{{ finalHtml }}</pre>
      </div>
    </div>
  </div>
</template>

<style scoped>
.input {
  width: 100%;
  border-radius: 0.375rem;
  border: 1px solid #d1d5db;
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  line-height: 1.25rem;
}
.input:focus {
  outline: 2px solid transparent;
  outline-offset: 2px;
  border-color: #6366f1;
  box-shadow: 0 0 0 1px #6366f1;
}
.label {
  display: block;
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #6b7280;
  margin-bottom: 0.25rem;
}
</style>
