<template>
  <div class="min-h-dvh bg-[#f5f7f8] text-[#3C393D] font-sans">
    <!-- Login -->
    <div
      v-if="!token"
      class="min-h-dvh flex items-center justify-center px-4"
    >
      <form
        class="w-full max-w-sm bg-white rounded-2xl shadow-lg p-8 space-y-4"
        @submit.prevent="login"
      >
        <h1 class="text-xl font-bold text-center">Müco Admin</h1>
        <p class="text-sm text-gray-500 text-center">
          İçerik yönetim paneline giriş yapın
        </p>
        <input
          v-model="password"
          type="password"
          placeholder="Şifre"
          autocomplete="current-password"
          class="w-full border border-gray-300 rounded-lg px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-[#3FA0C7]"
        />
        <button
          type="submit"
          :disabled="busy"
          class="w-full bg-[#3FA0C7] hover:bg-[#3590b5] text-white rounded-lg py-2.5 font-semibold disabled:opacity-50 cursor-pointer"
        >
          {{ busy ? "..." : "Giriş Yap" }}
        </button>
        <p v-if="error" class="text-sm text-red-600 text-center">{{ error }}</p>
      </form>
    </div>

    <!-- Panel -->
    <AdminMediaPicker v-if="token" />
    <div v-if="token" class="flex min-h-dvh">
      <!-- Sidebar -->
      <aside
        class="w-64 shrink-0 bg-white border-r border-gray-200 flex flex-col"
      >
        <div class="px-4 py-4 border-b border-gray-200">
          <h1 class="font-bold">Müco Admin</h1>
          <p class="text-xs text-gray-400">İçerik (JSON) Yönetimi</p>
        </div>
        <nav class="flex-1 overflow-y-auto p-2">
          <template v-for="(group, page) in grouped" :key="page">
            <p
              class="px-2 pt-3 pb-1 text-[11px] font-semibold uppercase tracking-wide text-gray-400"
            >
              {{ PAGE_LABELS[page] ?? page }}
            </p>
            <button
              v-for="ds in group"
              :key="ds.page + '/' + ds.locale"
              class="w-full text-left px-2 py-1.5 rounded-md text-sm cursor-pointer flex items-center justify-between"
              :class="
                selected &&
                selected.page === ds.page &&
                selected.locale === ds.locale
                  ? 'bg-[#DFEDEE] text-[#3C393D] font-semibold'
                  : 'hover:bg-gray-100 text-gray-600'
              "
              @click="select(ds)"
            >
              <span>{{ ds.locale.toUpperCase() }}</span>
              <span class="text-[10px] text-gray-400">{{
                formatBytes(ds.bytes)
              }}</span>
            </button>
          </template>
        </nav>
        <div class="p-3 border-t border-gray-200 space-y-2">
          <button
            class="w-full text-sm bg-[#3FA0C7] hover:bg-[#3590b5] text-white rounded-lg py-2.5 font-bold cursor-pointer disabled:opacity-50"
            :disabled="publishing"
            @click="publish"
          >
            {{ publishing ? "Yayınlanıyor..." : "🚀 Yayınla" }}
          </button>
          <p
            v-if="publishState && !publishing"
            class="text-[11px] text-center"
            :class="publishState.ok ? 'text-emerald-600' : 'text-red-600'"
          >
            {{
              publishState.ok
                ? "Son yayın başarılı ✓"
                : "Son yayın başarısız — loga bakın"
            }}
          </p>
          <button
            class="w-full text-sm bg-[#3C393D] hover:bg-black text-white rounded-lg py-2 cursor-pointer disabled:opacity-50"
            :disabled="busy"
            @click="exportFiles"
          >
            DB → JSON Dosyalarına Aktar
          </button>
          <button
            class="w-full text-sm border border-gray-300 hover:bg-gray-50 rounded-lg py-2 cursor-pointer disabled:opacity-50"
            :disabled="busy"
            @click="importFiles"
          >
            JSON Dosyalarından Yükle
          </button>
          <button
            class="w-full text-xs text-gray-400 hover:text-gray-600 py-1 cursor-pointer"
            @click="logout"
          >
            Çıkış yap
          </button>
        </div>
      </aside>

      <!-- Editor -->
      <main class="flex-1 flex flex-col min-w-0">
        <div
          class="flex items-center gap-3 px-5 py-3 bg-white border-b border-gray-200"
        >
          <template v-if="selected">
            <h2 class="font-semibold">
              {{ PAGE_LABELS[selected.page] ?? selected.page }}
              <span class="text-[#3FA0C7]">{{
                selected.locale.toUpperCase()
              }}</span>
            </h2>
            <span v-if="selectedUpdatedAt" class="text-xs text-gray-400">
              Son güncelleme: {{ formatDate(selectedUpdatedAt) }}
            </span>
            <span
              v-if="dirty"
              class="text-xs bg-amber-100 text-amber-700 rounded-full px-2 py-0.5"
              >kaydedilmedi</span
            >
          </template>
          <h2 v-else class="text-gray-400">Soldan bir veri seti seçin</h2>
          <div class="flex-1"></div>
          <template v-if="selected">
            <button
              class="text-xs text-gray-400 hover:text-gray-600 px-2 py-1.5 cursor-pointer"
              @click="toggleMode"
            >
              {{ viewMode === "form" ? "Gelişmiş (JSON)" : "← Form Görünümü" }}
            </button>
            <button
              v-if="viewMode === 'json'"
              class="text-sm border border-gray-300 hover:bg-gray-50 rounded-lg px-3 py-1.5 cursor-pointer"
              @click="formatJson"
            >
              Biçimlendir
            </button>
            <button
              class="text-sm bg-[#3FA0C7] hover:bg-[#3590b5] text-white rounded-lg px-4 py-1.5 font-semibold cursor-pointer disabled:opacity-50"
              :disabled="busy || !dirty"
              @click="save"
            >
              Kaydet
            </button>
          </template>
        </div>

        <div
          v-if="jsonError"
          class="px-5 py-2 bg-red-50 text-red-700 text-sm border-b border-red-100"
        >
          JSON hatası: {{ jsonError }}
        </div>
        <div
          v-if="notice"
          class="px-5 py-2 bg-emerald-50 text-emerald-700 text-sm border-b border-emerald-100"
        >
          {{ notice }}
        </div>
        <pre
          v-if="showPublishLog"
          class="max-h-48 overflow-y-auto px-5 py-3 bg-[#111] text-[#9fe8a8] text-xs leading-relaxed border-b border-gray-800 whitespace-pre-wrap"
          >{{ publishState?.log || "..." }}</pre
        >

        <div
          v-if="selected && viewMode === 'form'"
          class="flex-1 overflow-y-auto p-5 space-y-3"
        >
          <template v-if="model && !Array.isArray(model)">
            <AdminField
              v-for="k in rootKeys"
              :key="k"
              :parent="model"
              :field="k"
              :depth="0"
            />
          </template>
          <AdminField
            v-else-if="model"
            :parent="rootWrap"
            :field="selected.page"
            :depth="0"
          />
        </div>
        <textarea
          v-else-if="selected"
          v-model="editorText"
          spellcheck="false"
          class="flex-1 w-full resize-none font-mono text-[13px] leading-relaxed p-5 bg-[#1e1e2e] text-[#e6e6ef] focus:outline-none"
          @input="onEdit"
        ></textarea>
        <div
          v-else
          class="flex-1 flex items-center justify-center text-gray-300 text-sm"
        >
          İçerik JSON'ları Postgres'te saklanır; "DB → JSON Dosyalarına Aktar"
          ile siteye yansıtılır.
        </div>
      </main>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from "vue";
import { useHead } from "@vueuse/head";

useHead({
  title: "Müco Admin",
  meta: [{ name: "robots", content: "noindex, nofollow" }],
});

type Dataset = {
  page: string;
  locale: string;
  updated_at: string;
  bytes: number;
};

const TOKEN_KEY = "muco-admin-token";

const PAGE_LABELS: Record<string, string> = {
  home: "Ana Sayfa",
  menu: "Menü",
  campaigns: "Kampanyalar",
  legal: "Yasal Metinler",
  "sinirsiz-kahvalti": "Sınırsız Kahvaltı",
};

const token = ref<string | null>(null);
const password = ref("");
const busy = ref(false);
const error = ref("");
const notice = ref("");
const jsonError = ref("");

const datasets = ref<Dataset[]>([]);
const selected = ref<Dataset | null>(null);
const selectedUpdatedAt = ref<string | null>(null);
const editorText = ref("");
const savedText = ref(""); // compact JSON snapshot of last saved content
const model = ref<any>(null); // reactive form model
const viewMode = ref<"form" | "json">("form");

const dirty = computed(() => {
  if (!selected.value) return false;
  if (viewMode.value === "json") {
    try {
      return JSON.stringify(JSON.parse(editorText.value)) !== savedText.value;
    } catch {
      return true;
    }
  }
  return JSON.stringify(model.value) !== savedText.value;
});

// Root-level form alanları: locale gizli, meta en sonda
const rootKeys = computed(() => {
  if (!model.value || Array.isArray(model.value)) return [];
  return Object.keys(model.value)
    .filter((k) => k !== "locale")
    .sort((a, b) => (a === "meta" ? 1 : b === "meta" ? -1 : 0));
});

// Kök dizi (ör. kampanyalar) için sarmalayıcı
const rootWrap = computed(() => ({
  [selected.value?.page ?? "liste"]: model.value,
}));

function toggleMode() {
  if (viewMode.value === "form") {
    editorText.value = JSON.stringify(model.value, null, 2);
    jsonError.value = "";
    viewMode.value = "json";
  } else {
    try {
      model.value = JSON.parse(editorText.value);
      jsonError.value = "";
      viewMode.value = "form";
    } catch (e: any) {
      jsonError.value = e.message;
    }
  }
}

type PublishState = {
  running: boolean;
  startedAt: string | null;
  finishedAt: string | null;
  ok: boolean | null;
  log: string;
};

const publishState = ref<PublishState | null>(null);
const publishing = computed(() => !!publishState.value?.running);
const showPublishLog = computed(
  () => publishing.value || publishState.value?.ok === false,
);
let publishTimer: ReturnType<typeof setInterval> | null = null;

const grouped = computed(() => {
  const g: Record<string, Dataset[]> = {};
  for (const ds of datasets.value) (g[ds.page] ??= []).push(ds);
  return g;
});

function authHeaders(): Record<string, string> {
  return { Authorization: `Bearer ${token.value}` };
}

async function api(path: string, options: RequestInit = {}) {
  const res = await fetch(`/api/admin${path}`, {
    ...options,
    headers: {
      "Content-Type": "application/json",
      ...authHeaders(),
      ...(options.headers || {}),
    },
  });
  if (res.status === 401 && path !== "/login") {
    token.value = null;
    localStorage.removeItem(TOKEN_KEY);
    throw new Error("Oturum süresi doldu, tekrar giriş yapın");
  }
  const body = await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(body.error || `HTTP ${res.status}`);
  return body;
}

function flash(msg: string) {
  notice.value = msg;
  setTimeout(() => (notice.value = ""), 4000);
}

async function login() {
  busy.value = true;
  error.value = "";
  try {
    const res = await fetch("/api/admin/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ password: password.value }),
    });
    const body = await res.json().catch(() => ({}));
    if (!res.ok) throw new Error("Şifre hatalı");
    token.value = body.token;
    localStorage.setItem(TOKEN_KEY, body.token);
    password.value = "";
    await loadDatasets();
    await refreshPublishState();
    if (publishState.value?.running) {
      publishTimer ??= setInterval(refreshPublishState, 3000);
    }
  } catch (e: any) {
    error.value = e.message;
  } finally {
    busy.value = false;
  }
}

async function logout() {
  try {
    await api("/logout", { method: "POST" });
  } catch {}
  token.value = null;
  localStorage.removeItem(TOKEN_KEY);
  selected.value = null;
}

async function loadDatasets() {
  datasets.value = await api("/datasets");
}

async function select(ds: Dataset) {
  if (dirty.value && !confirm("Kaydedilmemiş değişiklikler var, devam?")) {
    return;
  }
  busy.value = true;
  jsonError.value = "";
  try {
    const row = await api(`/datasets/${ds.page}/${ds.locale}`);
    selected.value = ds;
    selectedUpdatedAt.value = row.updated_at;
    model.value = row.content;
    savedText.value = JSON.stringify(row.content);
    editorText.value = JSON.stringify(row.content, null, 2);
  } catch (e: any) {
    flash(e.message);
  } finally {
    busy.value = false;
  }
}

function onEdit() {
  try {
    JSON.parse(editorText.value);
    jsonError.value = "";
  } catch (e: any) {
    jsonError.value = e.message;
  }
}

function formatJson() {
  try {
    editorText.value = JSON.stringify(JSON.parse(editorText.value), null, 2);
    jsonError.value = "";
  } catch (e: any) {
    jsonError.value = e.message;
  }
}

async function save() {
  if (!selected.value) return;
  let content: unknown;
  if (viewMode.value === "json") {
    try {
      content = JSON.parse(editorText.value);
    } catch (e: any) {
      jsonError.value = e.message;
      return;
    }
  } else {
    content = JSON.parse(JSON.stringify(model.value));
  }
  busy.value = true;
  try {
    const row = await api(
      `/datasets/${selected.value.page}/${selected.value.locale}`,
      { method: "PUT", body: JSON.stringify({ content }) },
    );
    model.value = content;
    savedText.value = JSON.stringify(content);
    editorText.value = JSON.stringify(content, null, 2);
    selectedUpdatedAt.value = row.updated_at;
    flash("Kaydedildi ✓ (Siteye yansıtmak için 'DB → JSON Dosyalarına Aktar')");
    await loadDatasets();
  } catch (e: any) {
    flash(e.message);
  } finally {
    busy.value = false;
  }
}

async function exportFiles() {
  busy.value = true;
  try {
    const res = await api("/export", { method: "POST" });
    flash(`${res.written.length} dosya yazıldı: src/data güncellendi ✓`);
  } catch (e: any) {
    flash(e.message);
  } finally {
    busy.value = false;
  }
}

async function refreshPublishState() {
  try {
    publishState.value = await api("/publish/status");
  } catch {
    return;
  }
  if (!publishState.value?.running && publishTimer) {
    clearInterval(publishTimer);
    publishTimer = null;
    if (publishState.value?.ok) flash("Site yayınlandı ✓");
  }
}

async function publish() {
  if (publishing.value) return;
  if (!confirm("Site DB'deki içerikle yeniden build edilip yayınlanacak. Devam?"))
    return;
  try {
    await api("/publish", { method: "POST" });
    await refreshPublishState();
    publishTimer ??= setInterval(refreshPublishState, 3000);
  } catch (e: any) {
    flash(e.message);
  }
}

async function importFiles() {
  if (!confirm("JSON dosyaları DB'nin üzerine yazılacak. Emin misiniz?"))
    return;
  busy.value = true;
  try {
    const res = await api("/import", { method: "POST" });
    flash(`${res.written}/${res.total} veri seti dosyalardan yüklendi ✓`);
    await loadDatasets();
    if (selected.value) await select(selected.value);
  } catch (e: any) {
    flash(e.message);
  } finally {
    busy.value = false;
  }
}

function formatBytes(b: number) {
  if (!b) return "";
  return b > 1024 ? `${(b / 1024).toFixed(1)} KB` : `${b} B`;
}

function formatDate(d: string) {
  return new Date(d).toLocaleString("tr-TR");
}

onMounted(async () => {
  const stored = localStorage.getItem(TOKEN_KEY);
  if (stored) {
    token.value = stored;
    try {
      await loadDatasets();
      await refreshPublishState();
      if (publishState.value?.running) {
        publishTimer ??= setInterval(refreshPublishState, 3000);
      }
    } catch {
      // token invalid — api() already cleared it
    }
  }
});
</script>
