"use client";

import { useState, useEffect } from "react";
import { BlockChangelog, type ChangelogEntry } from "./BlockChangelog";

const LS_PREFIX = "bb-block-preview:";

function readLocalPreview(path: string, fallback: boolean): boolean {
  if (typeof window === "undefined") return fallback;
  const v = localStorage.getItem(LS_PREFIX + path);
  if (v === null) return fallback;
  return v === "true";
}

function writeLocalPreview(path: string, value: boolean) {
  localStorage.setItem(LS_PREFIX + path, String(value));
  window.dispatchEvent(new Event("bb-preview-change"));
}

interface BlockMeta {
  path: string;
  name: string;
  version: string;
  isInPreview: boolean;
  changelog: ChangelogEntry[];
}

interface SnapshotListItem {
  id: string;
  version: string;
  createdAt: string;
}

export interface SnapshotData {
  html: string;
  css: string;
}

interface BlockMetaBarProps {
  path: string;
  defaultVersion: string;
  defaultIsInPreview: boolean;
  defaultChangelog?: ChangelogEntry[];
  onSnapshotSelect?: (snapshot: SnapshotData | null) => void;
}

function captureBlockHtml(path: string): { html: string; css: string } {
  const container = document.querySelector(`[data-block-capture="${path}"]`);
  if (!container) throw new Error("Block container not found");

  const html = container.innerHTML;

  const cssRules: string[] = [];
  for (const sheet of document.styleSheets) {
    try {
      for (const rule of sheet.cssRules) {
        const text = rule.cssText;
        if (text.includes("bb-") || text.includes("--brand") || text.includes("--bb-")) {
          cssRules.push(text);
        }
      }
    } catch { /* cross-origin sheets */ }
  }

  return { html, css: cssRules.join("\n") };
}

export function BlockMetaBar({ path, defaultVersion, defaultIsInPreview, defaultChangelog = [], onSnapshotSelect }: BlockMetaBarProps) {
  const [meta, setMeta] = useState<BlockMeta | null>(null);
  const [editing, setEditing] = useState(false);
  const [versionInput, setVersionInput] = useState(defaultVersion);
  const [saving, setSaving] = useState(false);
  const [savingVersion, setSavingVersion] = useState<false | 'saving' | 'done'>(false);
  const [togglingPreview, setTogglingPreview] = useState(false);
  const [apiDown, setApiDown] = useState(false);
  const [localPreview, setLocalPreview] = useState(defaultIsInPreview);
  const [snapshots, setSnapshots] = useState<SnapshotListItem[]>([]);
  const [selectedSnapshotId, setSelectedSnapshotId] = useState<string>("current");
  const [loadingSnapshot, setLoadingSnapshot] = useState(false);

  const apiUrl = process.env.NEXT_PUBLIC_API_URL;

  useEffect(() => {
    setLocalPreview(readLocalPreview(path, defaultIsInPreview));
  }, [path, defaultIsInPreview]);

  useEffect(() => {
    if (!apiUrl) { setApiDown(true); return; }
    fetch(`${apiUrl}/blocks/by-path?path=${encodeURIComponent(path)}`)
      .then((r) => r.json())
      .then((data: BlockMeta) => {
        setMeta(data);
        setVersionInput(data.version);
      })
      .catch(() => setApiDown(true));
  }, [apiUrl, path]);

  useEffect(() => {
    if (!apiUrl || apiDown) return;
    fetchSnapshots();
  }, [apiUrl, apiDown, path]);

  async function fetchSnapshots() {
    if (!apiUrl) return;
    try {
      const r = await fetch(`${apiUrl}/blocks/snapshots?path=${encodeURIComponent(path)}`);
      const data: SnapshotListItem[] = await r.json();
      setSnapshots(data);
    } catch { /* ignore */ }
  }

  async function patch(data: { version?: string; isInPreview?: boolean; changelog?: ChangelogEntry[] }) {
    if (!apiUrl) return null;
    const r = await fetch(`${apiUrl}/blocks/by-path?path=${encodeURIComponent(path)}`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    });
    return r.json() as Promise<BlockMeta>;
  }

  async function saveVersion() {
    if (!meta) return;
    setSaving(true);
    try {
      const updated = await patch({ version: versionInput });
      if (updated) { setMeta(updated); setEditing(false); }
    } finally {
      setSaving(false);
    }
  }

  async function saveFullVersion() {
    if (apiDown || !apiUrl) return;
    setSavingVersion('saving');
    try {
      // 1. Update block metadata
      const updated = await patch({ version: defaultVersion, changelog: defaultChangelog });
      if (updated) {
        setMeta(updated);
        setVersionInput(updated.version);
      }

      // 2. Capture and save HTML snapshot
      try {
        const { html, css } = captureBlockHtml(path);
        await fetch(`${apiUrl}/blocks/snapshots?path=${encodeURIComponent(path)}`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ version: defaultVersion, changelog: defaultChangelog, html, css }),
        });
        await fetchSnapshots();
      } catch { /* snapshot capture may fail if container not found */ }

      setSavingVersion('done');
      setTimeout(() => setSavingVersion(false), 1500);
    } catch {
      setSavingVersion(false);
    }
  }

  async function togglePreview() {
    if (apiDown) {
      const newVal = !localPreview;
      setLocalPreview(newVal);
      writeLocalPreview(path, newVal);
      return;
    }
    if (!meta) return;
    setTogglingPreview(true);
    try {
      const updated = await patch({ isInPreview: !meta.isInPreview });
      if (updated) setMeta(updated);
    } finally {
      setTogglingPreview(false);
    }
  }

  async function handleVersionSelect(value: string) {
    setSelectedSnapshotId(value);
    if (value === "current") {
      onSnapshotSelect?.(null);
      return;
    }
    if (!apiUrl) return;
    setLoadingSnapshot(true);
    try {
      const r = await fetch(`${apiUrl}/blocks/snapshots/${value}`);
      const data = await r.json();
      onSnapshotSelect?.({ html: data.html, css: data.css });
    } catch {
      onSnapshotSelect?.(null);
      setSelectedSnapshotId("current");
    } finally {
      setLoadingSnapshot(false);
    }
  }

  const version = meta?.version ?? defaultVersion;
  const isInPreview = apiDown ? localPreview : (meta?.isInPreview ?? localPreview);
  const changelog: ChangelogEntry[] = (meta?.changelog && meta.changelog.length > 0) ? meta.changelog : defaultChangelog;
  const isViewingSnapshot = selectedSnapshotId !== "current";

  return (
    <>
      <div
        className="flex items-center flex-wrap gap-3 px-4 py-2 rounded-lg text-xs mb-6"
        style={{ background: "var(--bb-sidebar-bg)", border: "1px solid var(--bb-border)" }}
      >
        {/* Version selector */}
        <span className="font-semibold" style={{ color: "var(--bb-text-muted)" }}>
          Версия:
        </span>
        {snapshots.length > 0 ? (
          <select
            value={selectedSnapshotId}
            onChange={(e) => handleVersionSelect(e.target.value)}
            disabled={loadingSnapshot}
            className="font-mono px-2 py-0.5 rounded text-xs"
            style={{
              background: "var(--bb-sidebar-active-bg, #dff0fa)",
              color: "var(--brand-053m)",
              border: "1px solid var(--bb-border)",
              cursor: "pointer",
            }}
          >
            <option value="current">{version} (текущая)</option>
            {snapshots.map((s) => (
              <option key={s.id} value={s.id}>
                {s.version} — {new Date(s.createdAt).toLocaleDateString("ru")}
              </option>
            ))}
          </select>
        ) : editing ? (
          <span className="flex items-center gap-1.5">
            <input
              className="px-2 py-0.5 rounded border text-xs font-mono w-20"
              style={{ borderColor: "var(--bb-border)", color: "var(--bb-text)" }}
              value={versionInput}
              onChange={(e) => setVersionInput(e.target.value)}
              onKeyDown={(e) => { if (e.key === 'Enter') saveVersion(); if (e.key === 'Escape') setEditing(false); }}
              autoFocus
            />
            <button
              onClick={saveVersion}
              disabled={saving}
              className="px-2 py-0.5 rounded text-xs font-medium"
              style={{ background: "var(--brand-053m)", color: "#fff" }}
            >
              {saving ? '...' : 'Сохранить'}
            </button>
            <button
              onClick={() => { setEditing(false); setVersionInput(version); }}
              className="px-2 py-0.5 rounded text-xs"
              style={{ color: "var(--bb-text-muted)" }}
            >
              Отмена
            </button>
          </span>
        ) : (
          <button
            onClick={() => !apiDown && setEditing(true)}
            title={apiDown ? 'Версия из кода (API недоступен)' : 'Изменить версию'}
            className="font-mono px-2 py-0.5 rounded"
            style={{
              background: "var(--bb-sidebar-active-bg, #dff0fa)",
              color: "var(--brand-053m)",
              cursor: apiDown ? 'default' : 'pointer',
            }}
          >
            {version}
          </button>
        )}

        {loadingSnapshot && (
          <span className="text-xs" style={{ color: "var(--bb-text-muted)" }}>загрузка...</span>
        )}

        <span style={{ color: "var(--bb-border)" }}>·</span>

        {/* Preview toggle */}
        <button
          onClick={togglePreview}
          disabled={togglingPreview || (!apiDown && !meta)}
          title={isInPreview ? "Убрать из превью страницы" : "Включить в превью страницы"}
          className="flex items-center gap-1.5 px-2.5 py-1 rounded font-medium transition-colors cursor-pointer"
          style={isInPreview ? {
            background: "#dcfce7",
            color: "#16a34a",
            border: "1px solid #86efac",
          } : {
            background: "var(--bb-sidebar-bg)",
            color: "var(--bb-text-muted)",
            border: "1px solid var(--bb-border)",
          }}
        >
          <span
            className="inline-block w-1.5 h-1.5 rounded-full"
            style={{ background: isInPreview ? "#22c55e" : "#d1d5db" }}
          />
          {togglingPreview
            ? '...'
            : isInPreview
              ? "В превью"
              : "Не в превью"}
        </button>

        <span style={{ color: "var(--bb-border)" }}>·</span>

        {/* Save version button */}
        <button
          onClick={saveFullVersion}
          disabled={apiDown || savingVersion === 'saving' || isViewingSnapshot}
          title={apiDown ? 'API недоступен' : isViewingSnapshot ? 'Переключитесь на текущую версию' : 'Сохранить текущую версию и changelog в БД'}
          className="px-2.5 py-1 rounded font-medium transition-colors"
          style={savingVersion === 'done' ? {
            background: "#dcfce7",
            color: "#16a34a",
            border: "1px solid #86efac",
            cursor: "default",
          } : {
            background: "var(--bb-sidebar-bg)",
            color: (apiDown || isViewingSnapshot) ? "var(--bb-text-muted)" : "var(--brand-053m)",
            border: "1px solid var(--bb-border)",
            cursor: (apiDown || isViewingSnapshot) ? "default" : "pointer",
            opacity: (apiDown || isViewingSnapshot) ? 0.5 : 1,
          }}
        >
          {savingVersion === 'saving' ? '...' : savingVersion === 'done' ? 'Сохранено' : 'Сохранить версию'}
        </button>

        {/* Subtle offline dot */}
        {apiDown && (
          <span
            className="inline-block w-1.5 h-1.5 rounded-full"
            title="API недоступен — данные из кода"
            style={{ background: "#d1d5db" }}
          />
        )}
      </div>

      {/* Archive notice */}
      {isViewingSnapshot && (
        <div
          className="flex items-center gap-2 px-4 py-2 rounded-lg text-xs mb-4"
          style={{ background: "#fef3c7", border: "1px solid #fcd34d", color: "#92400e" }}
        >
          Архивная версия (только просмотр).
          <button
            onClick={() => handleVersionSelect("current")}
            className="underline font-medium"
            style={{ color: "#92400e" }}
          >
            Вернуться к текущей
          </button>
        </div>
      )}

      {/* Changelog rendered from API or fallback */}
      {changelog.length > 0 && <BlockChangelog changelog={changelog} />}
    </>
  );
}
