// Villa Mesochori — owners' area extras: seasonal pricing calendar + photo manager.
const axNS = window.VillaMesochoriDesignSystem_9e1a21;
const { Button: AxButton, Input: AxInput, LucideIcon: AxIcon } = axNS;

const AX_MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

function axISO(y, m, d) {
  return `${y}-${String(m + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
}

function axPriceFor(iso, draft) {
  let p = Number(draft.nightly) || 0;
  (draft.seasons || []).forEach((s) => {
    if (s.from && s.to && iso >= s.from && iso <= s.to) p = Number(s.price) || p;
  });
  return p;
}

function axCellColor(p, base) {
  if (!base || p === base) return "var(--surface-sunken)";
  const delta = Math.min(1, Math.abs(p - base) / base);
  const a = 0.25 + 0.6 * delta;
  return p > base ? `rgba(192, 94, 55, ${a.toFixed(2)})` : `rgba(78, 122, 90, ${a.toFixed(2)})`;
}

function AxMonth({ year, month, draft }) {
  const base = Number(draft.nightly) || 0;
  const startDow = (new Date(year, month, 1).getDay() + 6) % 7; // Monday first
  const days = new Date(year, month + 1, 0).getDate();
  const cells = [];
  for (let i = 0; i < startDow; i++) cells.push(null);
  for (let d = 1; d <= days; d++) cells.push(d);
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
      <span style={{ font: "700 12px var(--font-body)", color: "var(--text-heading)" }}>{AX_MONTHS[month]}</span>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(7, 15px)", gap: 2 }}>
        {cells.map((d, i) => {
          if (!d) return <span key={i}></span>;
          const iso = axISO(year, month, d);
          const p = axPriceFor(iso, draft);
          return (
            <span
              key={i}
              title={`${d} ${AX_MONTHS[month]} ${year} — ${draft.currency}${p}/night`}
              style={{ width: 15, height: 15, borderRadius: 3, background: axCellColor(p, base), cursor: "default" }}
            ></span>
          );
        })}
      </div>
    </div>
  );
}

function SeasonPricing({ draft, setDraft }) {
  const [year, setYear] = React.useState(new Date().getFullYear());
  const seasons = draft.seasons || [];
  const setSeason = (i, patch) => {
    const next = seasons.map((s, j) => (j === i ? { ...s, ...patch } : s));
    setDraft((d) => ({ ...d, seasons: next }));
  };
  const addSeason = () => setDraft((d) => ({
    ...d,
    seasons: [...seasons, { label: "New season", from: `${year}-06-01`, to: `${year}-06-30`, price: Number(draft.nightly) || 0 }],
  }));
  const removeSeason = (i) => setDraft((d) => ({ ...d, seasons: seasons.filter((_, j) => j !== i) }));

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 20 }}>
      {/* Season rules */}
      <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
        {seasons.map((s, i) => (
          <div key={i} style={{ display: "grid", gridTemplateColumns: "1fr 150px 150px 110px 36px", gap: 10, alignItems: "end" }}>
            <AxInput label={i === 0 ? "Season" : undefined} value={s.label || ""} onChange={(e) => setSeason(i, { label: e.target.value })} placeholder="e.g. High season" />
            <AxInput label={i === 0 ? "From" : undefined} type="date" value={s.from || ""} onChange={(e) => setSeason(i, { from: e.target.value })} />
            <AxInput label={i === 0 ? "To" : undefined} type="date" value={s.to || ""} onChange={(e) => setSeason(i, { to: e.target.value })} />
            <AxInput label={i === 0 ? "Per night" : undefined} type="number" value={`${s.price}`} onChange={(e) => setSeason(i, { price: Number(e.target.value) })} />
            <button
              onClick={() => removeSeason(i)}
              title="Remove this season"
              style={{ appearance: "none", background: "none", border: "1px solid var(--border-strong)", borderRadius: "var(--radius-md)", height: 40, cursor: "pointer", color: "var(--text-muted)", display: "inline-flex", alignItems: "center", justifyContent: "center" }}
            ><AxIcon name="trash-2" size={16} /></button>
          </div>
        ))}
        <div><AxButton variant="secondary" size="sm" onClick={addSeason}>Add a season</AxButton></div>
        <p style={{ font: "var(--type-small)", color: "var(--text-muted)", margin: 0 }}>
          Dates are inclusive. Where seasons overlap, the one lower in the list wins. Nights outside any season use the base rate ({draft.currency}{draft.nightly}).
        </p>
      </div>

      {/* Annual calendar */}
      <div style={{ background: "var(--surface-card)", border: "1px solid var(--border-soft)", borderRadius: "var(--radius-lg)", padding: 20 }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
            <AxButton variant="ghost" size="sm" onClick={() => setYear(year - 1)}>←</AxButton>
            <span style={{ font: "var(--type-h4)" }}>{year}</span>
            <AxButton variant="ghost" size="sm" onClick={() => setYear(year + 1)}>→</AxButton>
          </div>
          <div style={{ display: "flex", gap: 14, font: "var(--type-small)", color: "var(--text-muted)", alignItems: "center" }}>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}><span style={{ width: 12, height: 12, borderRadius: 3, background: "var(--surface-sunken)", border: "1px solid var(--border-soft)" }}></span> base rate</span>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}><span style={{ width: 12, height: 12, borderRadius: 3, background: "rgba(192,94,55,0.6)" }}></span> higher</span>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}><span style={{ width: 12, height: 12, borderRadius: 3, background: "rgba(78,122,90,0.6)" }}></span> lower</span>
          </div>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: "20px 24px" }}>
          {AX_MONTHS.map((_, m) => <AxMonth key={m} year={year} month={m} draft={draft} />)}
        </div>
        <p style={{ font: "var(--type-small)", color: "var(--text-muted)", margin: "14px 0 0" }}>Hover any day to see its nightly rate.</p>
      </div>
    </div>
  );
}

// ---- Photo manager ----

const AX_SLOTS = [
  ["imgHero", "Home — hero (the big view photo)"],
  ["imgHouse", "Home — the house / living room"],
  ["imgBedDouble", "Home — the double bedroom"],
  ["imgBedTwin", "Home — the twin bedroom"],
  ["imgView", "Home — 'The view' arch photo"],
  ["imgVillage", "Home — the village"],
];

function axResize(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onerror = reject;
    reader.onload = () => {
      const img = new Image();
      img.onerror = reject;
      img.onload = () => {
        const max = 1600;
        const scale = Math.min(1, max / Math.max(img.width, img.height));
        const cv = document.createElement("canvas");
        cv.width = Math.round(img.width * scale);
        cv.height = Math.round(img.height * scale);
        cv.getContext("2d").drawImage(img, 0, 0, cv.width, cv.height);
        resolve(cv.toDataURL("image/jpeg", 0.82));
      };
      img.src = reader.result;
    };
    reader.readAsDataURL(file);
  });
}

function AxPhotoRow({ k, label, draft, setDraft }) {
  const fileRef = React.useRef(null);
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(false);
  const isDefault = draft[k] === window.VMContent.defaults[k];
  const onFile = (e) => {
    const f = e.target.files && e.target.files[0];
    e.target.value = "";
    if (!f) return;
    setBusy(true); setErr(false);
    axResize(f)
      .then((dataUrl) => window.VMContent.uploadImage(k, dataUrl))
      .then((url) => { setDraft((d) => ({ ...d, [k]: url })); setBusy(false); })
      .catch(() => { setErr(true); setBusy(false); });
  };
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 16, padding: "12px 0", borderBottom: "1px solid var(--border-soft)" }}>
      <img src={draft[k]} alt={label} style={{ width: 96, height: 64, objectFit: "cover", borderRadius: "var(--radius-md)", background: "var(--surface-sunken)", flexShrink: 0 }} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ font: "600 14px var(--font-body)", color: "var(--text-heading)" }}>{label}</div>
        <div style={{ font: "var(--type-small)", color: err ? "var(--danger)" : "var(--text-muted)" }}>
          {err ? "Upload failed — try a smaller photo" : busy ? "Uploading…" : isDefault ? "Original photo" : "Your photo"}
        </div>
      </div>
      <input ref={fileRef} type="file" accept="image/*" onChange={onFile} style={{ display: "none" }} />
      <AxButton variant="secondary" size="sm" onClick={() => fileRef.current.click()} disabled={busy}>Replace</AxButton>
      {!isDefault && (
        <AxButton variant="ghost" size="sm" onClick={() => setDraft((d) => ({ ...d, [k]: window.VMContent.defaults[k] }))}>Restore original</AxButton>
      )}
    </div>
  );
}

function PhotoManager({ draft, setDraft }) {
  return (
    <div style={{ display: "flex", flexDirection: "column" }}>
      {AX_SLOTS.map(([k, label]) => <AxPhotoRow key={k} k={k} label={label} draft={draft} setDraft={setDraft} />)}
      <p style={{ font: "var(--type-small)", color: "var(--text-muted)", margin: "12px 0 0" }}>
        Photos are resized automatically before upload. Remember to press Save changes below — that's when the new photo goes live.
      </p>
    </div>
  );
}

function GuestBook() {
  const [guests, setGuests] = React.useState(null);
  const [err, setErr] = React.useState(false);
  React.useEffect(() => {
    window.VMContent.getGuests().then(setGuests).catch(() => setErr(true));
  }, []);

  const downloadCsv = () => {
    const esc = (v) => `"${String(v == null ? "" : v).replace(/"/g, '""')}"`;
    const rows = [["Requested", "Name", "Email", "Check-in", "Nights", "Guests", "Notes", "Quoted total"]]
      .concat(guests.map((g) => [g.when, g.name, g.email, g.checkin, g.nights, g.guests, g.notes, g.total]));
    const blob = new Blob([rows.map((r) => r.map(esc).join(",")).join("\n")], { type: "text/csv" });
    const a = document.createElement("a");
    a.href = URL.createObjectURL(blob);
    a.download = "villa-mesochori-guests.csv";
    a.click();
    URL.revokeObjectURL(a.href);
  };

  if (err) return <p style={{ font: "var(--type-body)", color: "var(--text-muted)", margin: 0 }}>Couldn't load the guest book — try signing out and in again.</p>;
  if (!guests) return <p style={{ font: "var(--type-body)", color: "var(--text-muted)", margin: 0 }}>Loading…</p>;
  if (!guests.length) return <p style={{ font: "var(--type-body)", color: "var(--text-muted)", margin: 0 }}>No booking requests yet — every request made on the site will be captured here with the guest's name, email, dates and notes.</p>;

  const list = guests.slice().reverse();
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
        <span style={{ font: "var(--type-body)", color: "var(--text-muted)" }}>{guests.length} request{guests.length === 1 ? "" : "s"} captured</span>
        <AxButton variant="secondary" size="sm" onClick={downloadCsv}>Download CSV for email lists</AxButton>
      </div>
      <div style={{ background: "var(--surface-card)", border: "1px solid var(--border-soft)", borderRadius: "var(--radius-lg)", overflow: "hidden" }}>
        <div style={{ display: "grid", gridTemplateColumns: "1.2fr 1.6fr 1fr 0.6fr 0.6fr", gap: 12, padding: "10px 16px", font: "700 12px var(--font-body)", textTransform: "uppercase", letterSpacing: "0.08em", color: "var(--text-muted)", borderBottom: "1px solid var(--border-soft)" }}>
          <span>Name</span><span>Email</span><span>Check-in</span><span>Nights</span><span>Guests</span>
        </div>
        {list.map((g, i) => (
          <div key={i} style={{ borderBottom: i < list.length - 1 ? "1px solid var(--border-soft)" : "none", padding: "12px 16px" }}>
            <div style={{ display: "grid", gridTemplateColumns: "1.2fr 1.6fr 1fr 0.6fr 0.6fr", gap: 12, font: "var(--type-body)", alignItems: "baseline" }}>
              <span style={{ fontWeight: 600, color: "var(--text-heading)" }}>{g.name || "—"}</span>
              <a href={`mailto:${g.email}`}>{g.email || "—"}</a>
              <span>{g.checkin}</span>
              <span>{g.nights}</span>
              <span>{g.guests}</span>
            </div>
            {g.notes ? <div style={{ font: "var(--type-small)", color: "var(--text-muted)", marginTop: 4 }}>“{g.notes}” · quoted {g.total}</div> : <div style={{ font: "var(--type-small)", color: "var(--text-muted)", marginTop: 4 }}>quoted {g.total}</div>}
          </div>
        ))}
      </div>
    </div>
  );
}

function SquareSecrets() {
  const [token, setToken] = React.useState("");
  const [sandbox, setSandbox] = React.useState(false);
  const [state, setState] = React.useState("idle"); // idle | saving | saved | error
  const serverMode = window.VMContent.serverMode();
  const save = () => {
    setState("saving");
    window.VMContent.saveSecret({ squareAccessToken: token, squareSandbox: sandbox })
      .then(() => { setState("saved"); setToken(""); setTimeout(() => setState("idle"), 2500); })
      .catch(() => setState("error"));
  };
  if (!serverMode) {
    return <p style={{ font: "var(--type-small)", color: "var(--text-muted)", margin: 0 }}>The Square access token can only be set on the live site (it's stored on the server, never in the browser).</p>;
  }
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      <AxInput label="Square access token" type="password" value={token} onChange={(e) => setToken(e.target.value)} hint="Stored on the server only — developer.squareup.com → your app → Production → Access token" />
      <label style={{ display: "flex", alignItems: "center", gap: 8, font: "var(--type-body)", color: "var(--text-body)" }}>
        <input type="checkbox" checked={sandbox} onChange={(e) => setSandbox(e.target.checked)} />
        Sandbox (testing) mode — tick while trying it out with a sandbox token
      </label>
      <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
        <AxButton variant="secondary" size="sm" onClick={save} disabled={!token || state === "saving"}>{state === "saving" ? "Saving…" : "Save token to server"}</AxButton>
        {state === "saved" && <span style={{ font: "var(--type-small)", color: "var(--secondary)" }}>Saved securely</span>}
        {state === "error" && <span style={{ font: "var(--type-small)", color: "var(--danger, #B4452E)" }}>Couldn't save — try again</span>}
      </div>
    </div>
  );
}

function CalendarSync() {
  const [url, setUrl] = React.useState("");
  const [state, setState] = React.useState("idle"); // idle | saving | saved | error
  const [status, setStatus] = React.useState(null); // {configured, count}
  const serverMode = window.VMContent.serverMode();
  const refresh = () => window.VMContent.getAvailability().then((a) => setStatus({ configured: a.configured, count: a.busy.length }));
  React.useEffect(() => { if (serverMode) refresh(); }, []);
  const save = () => {
    setState("saving");
    window.VMContent.saveSecret({ icalUrl: url.trim() })
      .then(() => { setState("saved"); setUrl(""); refresh(); setTimeout(() => setState("idle"), 2500); })
      .catch(() => setState("error"));
  };
  if (!serverMode) {
    return <p style={{ font: "var(--type-small)", color: "var(--text-muted)", margin: 0 }}>Calendar sync runs on the live site — the calendar address is stored on the server, never in the browser.</p>;
  }
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      <p style={{ font: "var(--type-small)", color: "var(--text-muted)", margin: 0 }}>
        In Google Calendar: Settings → your availability calendar → “Integrate calendar” → copy the <strong>Secret address in iCal format</strong> and paste it here. Any event on that calendar blocks those dates on the booking page (re-synced every 15 minutes).
      </p>
      <AxInput label="Calendar secret iCal address" type="password" value={url} onChange={(e) => setUrl(e.target.value)} placeholder="https://calendar.google.com/calendar/ical/…/basic.ics" hint="Stored on the server only. Paste an empty value to turn sync off." />
      <div style={{ display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap" }}>
        <AxButton variant="secondary" size="sm" onClick={save} disabled={state === "saving"}>{state === "saving" ? "Saving…" : "Save & sync now"}</AxButton>
        {state === "saved" && <span style={{ font: "var(--type-small)", color: "var(--secondary)" }}>Saved</span>}
        {state === "error" && <span style={{ font: "var(--type-small)", color: "var(--danger, #B4452E)" }}>Couldn't save — check the address</span>}
        {status && (
          <span style={{ font: "var(--type-small)", color: "var(--text-muted)" }}>
            {status.configured ? `Sync is on — ${status.count} night${status.count === 1 ? "" : "s"} currently blocked` : "Sync is off — all dates show as available"}
          </span>
        )}
      </div>
    </div>
  );
}

// Generic card-list editor — used for house details and places to go
function AxCardShell({ title, onRemove, children }) {
  return (
    <div style={{ background: "var(--surface-card)", border: "1px solid var(--border-soft)", borderRadius: "var(--radius-lg)", padding: 18, display: "flex", flexDirection: "column", gap: 12 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
        <span style={{ font: "700 13px var(--font-body)", textTransform: "uppercase", letterSpacing: "0.1em", color: "var(--text-muted)" }}>{title}</span>
        <button onClick={onRemove} title="Remove" style={{ appearance: "none", background: "none", border: "1px solid var(--border-strong)", borderRadius: "var(--radius-md)", width: 32, height: 32, cursor: "pointer", color: "var(--text-muted)", display: "inline-flex", alignItems: "center", justifyContent: "center" }}><AxIcon name="trash-2" size={15} /></button>
      </div>
      {children}
    </div>
  );
}

function AxArea({ label, value, onChange, rows }) {
  return (
    <label style={{ display: "flex", flexDirection: "column", gap: 6 }}>
      <span style={{ font: "600 14px var(--font-body)", color: "var(--text-heading)" }}>{label}</span>
      <textarea value={value || ""} onChange={onChange} rows={rows || 3} style={{ font: "var(--type-body)", color: "var(--text-body)", background: "var(--surface-card)", border: "1px solid var(--border-strong)", borderRadius: "var(--radius-md)", padding: "10px 14px", resize: "vertical" }}></textarea>
    </label>
  );
}

function HouseCardsEditor({ draft, setDraft }) {
  const cards = draft.houseCards || [];
  const set = (i, patch) => setDraft((d) => ({ ...d, houseCards: cards.map((c, j) => (j === i ? { ...c, ...patch } : c)) }));
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
      <p style={{ font: "var(--type-small)", color: "var(--text-muted)", margin: 0 }}>These cards appear on the home page under “The house” — one card per area (the balcony, the kitchen, the garden…). Add as many as you like.</p>
      {cards.map((card, i) => (
        <AxCardShell key={i} title={card.title || `Card ${i + 1}`} onRemove={() => setDraft((d) => ({ ...d, houseCards: cards.filter((_, j) => j !== i) }))}>
          <AxInput label="Area" value={card.title || ""} onChange={(e) => set(i, { title: e.target.value })} placeholder="e.g. The balcony" />
          <AxArea label="Description" value={card.body} onChange={(e) => set(i, { body: e.target.value })} />
        </AxCardShell>
      ))}
      <div><AxButton variant="secondary" size="sm" onClick={() => setDraft((d) => ({ ...d, houseCards: [...cards, { title: "", body: "" }] }))}>Add an area</AxButton></div>
    </div>
  );
}

function AxPlaceImg({ place, onUploaded }) {
  const fileRef = React.useRef(null);
  const [busy, setBusy] = React.useState(false);
  const onFile = (e) => {
    const f = e.target.files && e.target.files[0];
    e.target.value = "";
    if (!f) return;
    setBusy(true);
    axResize(f)
      .then((dataUrl) => window.VMContent.uploadImage("place", dataUrl))
      .then((url) => { onUploaded(url); setBusy(false); })
      .catch(() => setBusy(false));
  };
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
      {place.img ? (
        <img src={place.img} alt="" style={{ width: 96, height: 64, objectFit: "cover", borderRadius: "var(--radius-md)", background: "var(--surface-sunken)", flexShrink: 0 }} />
      ) : (
        <div style={{ width: 96, height: 64, borderRadius: "var(--radius-md)", background: "var(--surface-sunken)", border: "1px solid var(--border-soft)", flexShrink: 0, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--text-muted)" }}>
        <AxIcon name="image" size={18} />
      </div>
      )}
      <input ref={fileRef} type="file" accept="image/*" onChange={onFile} style={{ display: "none" }} />
      <AxButton variant="secondary" size="sm" onClick={() => fileRef.current.click()} disabled={busy}>{busy ? "Uploading…" : place.img ? "Replace photo" : "Add photo"}</AxButton>
    </div>
  );
}

// Pull coordinates out of anything Google Maps gives you: a share link with @lat,lng,
// a ?q=lat,lng link, or a plain "36.5104, 23.0662" paste from right-click → coordinates.
function axParseCoords(str) {
  const s = String(str || "");
  let m = s.match(/@(-?\d{1,2}\.\d+),(-?\d{1,3}\.\d+)/) ||
          s.match(/[?&](?:q|query|ll|center)=(-?\d{1,2}\.\d+)\s*,\s*(-?\d{1,3}\.\d+)/) ||
          s.match(/^\s*(-?\d{1,2}\.\d+)\s*,\s*(-?\d{1,3}\.\d+)\s*$/) ||
          s.match(/!3d(-?\d{1,2}\.\d+)!4d(-?\d{1,3}\.\d+)/);
  if (!m) return null;
  const lat = Number(m[1]), lng = Number(m[2]);
  if (Number.isNaN(lat) || Number.isNaN(lng) || Math.abs(lat) > 90 || Math.abs(lng) > 180) return null;
  return { lat, lng };
}

function AxLocationField({ place, onCoords }) {
  const [text, setText] = React.useState("");
  const [state, setState] = React.useState("idle"); // idle | ok | bad
  const apply = (v) => {
    setText(v);
    const c = axParseCoords(v);
    if (c) { onCoords(c); setState("ok"); } else setState(v.trim() ? "bad" : "idle");
  };
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
      <AxInput
        label="Google Maps link or coordinates"
        value={text}
        onChange={(e) => apply(e.target.value)}
        placeholder="Paste a Google Maps share link, or e.g. 36.5104, 23.0662"
        hint={
          state === "ok" ? `Pin set — ${place.lat.toFixed(4)}, ${place.lng.toFixed(4)}` :
          state === "bad" ? "Couldn't find coordinates in that — in Google Maps, right-click the spot and click the coordinates to copy them" :
          `Current pin: ${(place.lat ?? 0).toFixed(4)}, ${(place.lng ?? 0).toFixed(4)}`
        }
      />
    </div>
  );
}

function PlacesEditor({ draft, setDraft }) {
  const places = draft.places || [];
  const set = (i, patch) => setDraft((d) => ({ ...d, places: places.map((p, j) => (j === i ? { ...p, ...patch } : p)) }));
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
      <p style={{ font: "var(--type-small)", color: "var(--text-muted)", margin: 0 }}>The cards on the “Places to go” page. Category groups the filter tags — type an existing one (Beaches, Day trips, Tavernas, Nature, Neapoli) or a new one and a tag appears automatically. Drop in a Google Maps link to pin the place on the map.</p>
      {places.map((p, i) => (
        <AxCardShell key={i} title={p.name || `Place ${i + 1}`} onRemove={() => setDraft((d) => ({ ...d, places: places.filter((_, j) => j !== i) }))}>
          <div style={{ display: "grid", gridTemplateColumns: "2fr 1fr", gap: 12 }}>
            <AxInput label="Name" value={p.name || ""} onChange={(e) => set(i, { name: e.target.value })} />
            <AxInput label="Category" value={p.cat || ""} onChange={(e) => set(i, { cat: e.target.value })} placeholder="Neapoli / Beaches / …" />
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 2fr", gap: 12 }}>
            <AxInput label="Distance from the house" value={p.dist || ""} onChange={(e) => set(i, { dist: e.target.value })} placeholder="e.g. 10 min drive" />
            <AxLocationField place={p} onCoords={(coords) => set(i, coords)} />
          </div>
          <AxArea label="Our tip (shown handwritten on the card)" value={p.tip} onChange={(e) => set(i, { tip: e.target.value })} rows={2} />
          <AxPlaceImg place={p} onUploaded={(url) => set(i, { img: url })} />
        </AxCardShell>
      ))}
      <div><AxButton variant="secondary" size="sm" onClick={() => setDraft((d) => ({ ...d, places: [...places, { cat: "", name: "", dist: "", tip: "", img: "", lat: 36.5359, lng: 23.0799 }] }))}>Add a place</AxButton></div>
    </div>
  );
}

function ArrivalEditor({ draft, setDraft }) {
  const steps = draft.arriveSteps || [];
  const set = (i, patch) => setDraft((d) => ({ ...d, arriveSteps: steps.map((s, j) => (j === i ? { ...s, ...patch } : s)) }));
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
      <AxLocationField
        place={{ lat: draft.houseLat, lng: draft.houseLng }}
        onCoords={(coords) => setDraft((d) => ({ ...d, houseLat: coords.lat, houseLng: coords.lng }))}
      />
      <p style={{ font: "var(--type-small)", color: "var(--text-muted)", margin: 0 }}>The direction steps below appear as numbered photo cards — add one card per landmark on the way to the house (4–6 works well).</p>
      {steps.map((s, i) => (
        <AxCardShell key={i} title={`Step ${i + 1}${s.title ? " — " + s.title : ""}`} onRemove={() => setDraft((d) => ({ ...d, arriveSteps: steps.filter((_, j) => j !== i) }))}>
          <AxInput label="Landmark" value={s.title || ""} onChange={(e) => set(i, { title: e.target.value })} placeholder="e.g. The church square" />
          <AxArea label="What to do here" value={s.body} onChange={(e) => set(i, { body: e.target.value })} rows={2} />
          <AxLocationField place={s} onCoords={(coords) => set(i, coords)} />
          <AxPlaceImg place={s} onUploaded={(url) => set(i, { img: url })} />
        </AxCardShell>
      ))}
      <div><AxButton variant="secondary" size="sm" onClick={() => setDraft((d) => ({ ...d, arriveSteps: [...steps, { title: "", body: "", img: "" }] }))}>Add a step</AxButton></div>
    </div>
  );
}

function GalleryEditor({ draft, setDraft }) {
  const items = draft.gallery || [];
  const set = (i, patch) => setDraft((d) => ({ ...d, gallery: items.map((g, j) => (j === i ? { ...g, ...patch } : g)) }));
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
      <p style={{ font: "var(--type-small)", color: "var(--text-muted)", margin: 0 }}>The expandable “More photos” gallery on the home page — kitchen, bathrooms, garden and anything else guests should see. Cards without a photo show a “coming soon” placeholder until you upload one.</p>
      {items.map((g, i) => (
        <AxCardShell key={i} title={g.label || `Photo ${i + 1}`} onRemove={() => setDraft((d) => ({ ...d, gallery: items.filter((_, j) => j !== i) }))}>
          <AxInput label="Caption" value={g.label || ""} onChange={(e) => set(i, { label: e.target.value })} placeholder="e.g. The kitchen & dining table" />
          <AxPlaceImg place={g} onUploaded={(url) => set(i, { img: url })} />
        </AxCardShell>
      ))}
      <div><AxButton variant="secondary" size="sm" onClick={() => setDraft((d) => ({ ...d, gallery: [...items, { label: "", img: "" }] }))}>Add a photo card</AxButton></div>
    </div>
  );
}

window.VMAdminExtras = { SeasonPricing, PhotoManager, GuestBook, SquareSecrets, CalendarSync, HouseCardsEditor, PlacesEditor, ArrivalEditor, GalleryEditor };
