// @File: frontend/src/pages/admin/cms/CmsChatBranding.tsx
// @Desc: Full chat widget branding settings with live preview.
//        - Identity (name, avatars, fallback initials)
//        - Colors & Theme
//        - Launcher
//        - Messages
//        - Footer & Sound
//        Everything persists to /api/v1/chat/admin/branding and the public
//        ChatWidget reads /api/v1/chat/branding.
import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import { createClient } from "@metagptx/web-sdk";
import {
  Loader2,
  Save,
  RotateCcw,
  ExternalLink,
  Upload,
  ImagePlus,
  Palette,
  Sparkles,
  MessageCircle,
  Headset,
  X,
  Send,
  UserCircle2,
  AlertCircle,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import CmsLayout from "./CmsLayout";
import { PageHeader } from "./ui";

const client = createClient();

const BRANDING_BUCKET = "chat-branding";

const LAUNCHER_STYLES = [
  { value: "circle", label: "Circle" },
  { value: "pill", label: "Pill" },
  { value: "square", label: "Square" },
];

const LAUNCHER_ICONS = [
  { value: "chat", label: "Chat bubble" },
  { value: "sparkles", label: "Sparkles" },
  { value: "headset", label: "Headset" },
  { value: "custom_upload", label: "Custom upload" },
];

const LAUNCHER_POSITIONS = [
  { value: "bottom-right", label: "Bottom right" },
  { value: "bottom-left", label: "Bottom left" },
];

const THEME_MODES = [
  { value: "light", label: "Light" },
  { value: "dark", label: "Dark" },
  { value: "auto", label: "Auto (system)" },
];

const ROUNDED_LEVELS = [
  { value: "none", label: "None" },
  { value: "sm", label: "Small" },
  { value: "md", label: "Medium" },
  { value: "lg", label: "Large" },
  { value: "xl", label: "Extra large" },
];

const FONT_FAMILIES = [
  { value: "System", label: "System default" },
  { value: "Inter", label: "Inter" },
  { value: "Poppins", label: "Poppins" },
  { value: "Roboto", label: "Roboto" },
  { value: "Cairo", label: "Cairo (Arabic)" },
];

const SOUND_PRESETS = [
  { value: "soft_chime", label: "Soft chime" },
  { value: "ping", label: "Ping" },
  { value: "pop", label: "Pop" },
  { value: "none", label: "None (silent)" },
];

interface Branding {
  widget_name: string;
  avatar_url: string;
  avatar_fallback_initials: string;
  agent_avatar_url: string;
  primary_color: string;
  accent_color: string;
  bubble_bg_color: string;
  bubble_text_color: string;
  header_bg_color: string;
  header_text_color: string;
  launcher_style: string;
  launcher_icon: string;
  launcher_icon_url: string;
  launcher_position: string;
  welcome_message: string;
  offline_message: string;
  ai_intro_message: string;
  human_handover_message: string;
  input_placeholder: string;
  show_branding_footer: boolean;
  footer_text: string;
  enable_sound: boolean;
  notification_sound: string;
  theme_mode: string;
  rounded: string;
  font_family: string;
}

const HEX_RE = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;

function isValidHex(v: string): boolean {
  return HEX_RE.test(v || "");
}

function slugifyKey(name: string): string {
  const clean = (name || "asset").replace(/[^a-z0-9.-]+/gi, "-").toLowerCase();
  const ts = Date.now();
  return `branding/${ts}-${clean}`;
}

async function uploadFileToBucket(file: File, kind: string): Promise<string> {
  const object_key = slugifyKey(`${kind}-${file.name}`);
  // Get presigned URL and upload directly.
  await client.storage.upload({
    bucket_name: BRANDING_BUCKET,
    object_key,
    file,
  });
  const res = await client.storage.getDownloadUrl({
    bucket_name: BRANDING_BUCKET,
    object_key,
  });
  return res?.data?.download_url || "";
}

export default function CmsChatBranding() {
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [resetting, setResetting] = useState(false);
  const [err, setErr] = useState<string | null>(null);
  const [okMsg, setOkMsg] = useState<string | null>(null);
  const [branding, setBranding] = useState<Branding | null>(null);
  const [defaults, setDefaults] = useState<Branding | null>(null);

  const load = useCallback(async () => {
    setLoading(true);
    setErr(null);
    try {
      const res = await client.apiCall.invoke({
        url: "/api/v1/chat/branding",
        method: "GET",
        data: {},
      });
      setBranding(res?.data?.branding || null);
      setDefaults(res?.data?.defaults || null);
    } catch (e: any) {
      setErr(e?.data?.detail || e?.message || "Failed to load branding.");
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    load();
  }, [load]);

  const update = (patch: Partial<Branding>) =>
    setBranding((prev) => (prev ? { ...prev, ...patch } : prev));

  const save = async () => {
    if (!branding) return;
    // Validate colors before sending.
    const colorKeys: (keyof Branding)[] = [
      "primary_color",
      "accent_color",
      "bubble_bg_color",
      "bubble_text_color",
      "header_bg_color",
      "header_text_color",
    ];
    for (const k of colorKeys) {
      const v = branding[k] as string;
      if (!isValidHex(v)) {
        setErr(`"${k}" must be a valid hex color (e.g. #059669). Got: ${v}`);
        return;
      }
    }
    setSaving(true);
    setErr(null);
    setOkMsg(null);
    try {
      const res = await client.apiCall.invoke({
        url: "/api/v1/chat/admin/branding",
        method: "PUT",
        data: branding,
      });
      setBranding(res?.data?.branding || branding);
      setOkMsg("Branding saved. The widget will pick it up within seconds.");
    } catch (e: any) {
      setErr(e?.data?.detail || e?.message || "Failed to save.");
    } finally {
      setSaving(false);
    }
  };

  const reset = async () => {
    if (
      !window.confirm(
        "Reset all chat branding to defaults? Uploaded avatars will stay in storage but will no longer be used."
      )
    )
      return;
    setResetting(true);
    setErr(null);
    setOkMsg(null);
    try {
      const res = await client.apiCall.invoke({
        url: "/api/v1/chat/admin/branding/reset",
        method: "POST",
        data: {},
      });
      setBranding(res?.data?.branding || null);
      setOkMsg("Branding reset to defaults.");
    } catch (e: any) {
      setErr(e?.data?.detail || e?.message || "Failed to reset.");
    } finally {
      setResetting(false);
    }
  };

  if (loading || !branding) {
    return (
      <CmsLayout title="Chat Widget Branding">
        <div className="flex items-center gap-2 text-sm text-muted-foreground">
          <Loader2 className="h-4 w-4 animate-spin" /> Loading branding…
        </div>
      </CmsLayout>
    );
  }

  return (
    <CmsLayout title="Chat Widget Branding">
      <PageHeader
        icon={<Palette className="w-6 h-6" />}
        title="Chat Widget Branding"
        description="Customize the AI chat widget's identity, colors, launcher, messages and voice. Changes go live within seconds."
      />

      {err && (
        <div className="mb-4 rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-800 flex items-center gap-2">
          <AlertCircle className="h-4 w-4" /> {err}
        </div>
      )}
      {okMsg && (
        <div className="mb-4 rounded-lg border border-emerald-200 bg-emerald-50 p-3 text-sm text-emerald-800">
          {okMsg}
        </div>
      )}

      <div className="grid gap-6 lg:grid-cols-[1fr_420px]">
        {/* Form */}
        <div className="space-y-4">
          <IdentitySection branding={branding} update={update} />
          <ColorsSection branding={branding} update={update} />
          <LauncherSection branding={branding} update={update} />
          <MessagesSection branding={branding} update={update} />
          <FooterSoundSection branding={branding} update={update} />

          <div className="flex flex-wrap items-center gap-2 pt-2">
            <Button
              onClick={save}
              disabled={saving}
              className="bg-emerald-600 text-white hover:bg-emerald-700"
            >
              {saving ? (
                <>
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" /> Saving…
                </>
              ) : (
                <>
                  <Save className="mr-2 h-4 w-4" /> Save branding
                </>
              )}
            </Button>
            <Button variant="outline" onClick={reset} disabled={resetting}>
              {resetting ? (
                <Loader2 className="mr-2 h-4 w-4 animate-spin" />
              ) : (
                <RotateCcw className="mr-2 h-4 w-4" />
              )}
              Reset to defaults
            </Button>
            <Button variant="ghost" asChild>
              <a href="/" target="_blank" rel="noopener noreferrer">
                <ExternalLink className="mr-2 h-4 w-4" /> Preview on site
              </a>
            </Button>
          </div>
        </div>

        {/* Live preview */}
        <div className="lg:sticky lg:top-6 h-fit">
          <LivePreview branding={branding} />
        </div>
      </div>
    </CmsLayout>
  );
}

// ---------- Sections ----------
function SectionCard({
  title,
  subtitle,
  children,
}: {
  title: string;
  subtitle?: string;
  children: React.ReactNode;
}) {
  return (
    <div className="rounded-xl border bg-card p-4 shadow-sm">
      <div className="mb-3">
        <h3 className="text-sm font-semibold text-slate-900">{title}</h3>
        {subtitle && (
          <p className="text-xs text-muted-foreground mt-0.5">{subtitle}</p>
        )}
      </div>
      {children}
    </div>
  );
}

function IdentitySection({
  branding,
  update,
}: {
  branding: Branding;
  update: (p: Partial<Branding>) => void;
}) {
  return (
    <SectionCard
      title="Identity"
      subtitle="Widget name, AI avatar and human agent fallback."
    >
      <div className="grid gap-3 md:grid-cols-2">
        <div className="md:col-span-2">
          <Label>Widget display name</Label>
          <Input
            value={branding.widget_name}
            onChange={(e) => update({ widget_name: e.target.value })}
            placeholder="DoitEasy Support"
          />
        </div>
        <AvatarUploader
          label="AI bot avatar"
          url={branding.avatar_url}
          onChange={(url) => update({ avatar_url: url })}
          kind="ai-avatar"
        />
        <AvatarUploader
          label="Human agent fallback avatar"
          url={branding.agent_avatar_url}
          onChange={(url) => update({ agent_avatar_url: url })}
          kind="agent-avatar"
        />
        <div>
          <Label>Fallback initials</Label>
          <Input
            maxLength={3}
            value={branding.avatar_fallback_initials}
            onChange={(e) =>
              update({
                avatar_fallback_initials: e.target.value
                  .toUpperCase()
                  .slice(0, 3),
              })
            }
            placeholder="DE"
          />
          <p className="text-[11px] text-muted-foreground mt-1">
            Shown when no avatar image is available.
          </p>
        </div>
      </div>
    </SectionCard>
  );
}

function AvatarUploader({
  label,
  url,
  onChange,
  kind,
}: {
  label: string;
  url: string;
  onChange: (url: string) => void;
  kind: string;
}) {
  const [uploading, setUploading] = useState(false);
  const [err, setErr] = useState<string | null>(null);
  const inputRef = useRef<HTMLInputElement | null>(null);

  const onPick = async (file: File | null) => {
    if (!file) return;
    if (file.size > 2 * 1024 * 1024) {
      setErr("File too large (max 2MB).");
      return;
    }
    setErr(null);
    setUploading(true);
    try {
      const uploaded = await uploadFileToBucket(file, kind);
      if (uploaded) onChange(uploaded);
    } catch (e: any) {
      setErr(e?.message || "Upload failed.");
    } finally {
      setUploading(false);
      if (inputRef.current) inputRef.current.value = "";
    }
  };

  return (
    <div>
      <Label>{label}</Label>
      <div className="flex items-center gap-3 mt-1">
        <div className="h-14 w-14 rounded-full overflow-hidden bg-muted ring-1 ring-slate-200 flex items-center justify-center">
          {url ? (
            <img
              src={url}
              alt={label}
              className="h-full w-full object-cover"
            />
          ) : (
            <UserCircle2 className="h-8 w-8 text-slate-400" />
          )}
        </div>
        <div className="flex-1 min-w-0">
          <div className="flex items-center gap-2">
            <input
              ref={inputRef}
              type="file"
              accept="image/*"
              className="hidden"
              onChange={(e) => onPick(e.target.files?.[0] || null)}
            />
            <Button
              type="button"
              size="sm"
              variant="outline"
              onClick={() => inputRef.current?.click()}
              disabled={uploading}
            >
              {uploading ? (
                <Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
              ) : (
                <Upload className="mr-1.5 h-3.5 w-3.5" />
              )}
              Upload
            </Button>
            {url && (
              <Button
                type="button"
                size="sm"
                variant="ghost"
                className="text-red-600"
                onClick={() => onChange("")}
              >
                Remove
              </Button>
            )}
          </div>
          <p className="text-[11px] text-muted-foreground mt-1">
            PNG/JPG/SVG, 1:1, 256×256 min, max 2MB.
          </p>
          {err && <p className="text-[11px] text-red-600 mt-1">{err}</p>}
        </div>
      </div>
    </div>
  );
}

function ColorField({
  label,
  value,
  onChange,
}: {
  label: string;
  value: string;
  onChange: (v: string) => void;
}) {
  const valid = isValidHex(value);
  return (
    <div>
      <Label>{label}</Label>
      <div className="flex items-center gap-2 mt-1">
        <input
          type="color"
          value={valid ? value : "#000000"}
          onChange={(e) => onChange(e.target.value)}
          className="h-9 w-10 rounded border border-slate-200 cursor-pointer bg-white p-0"
        />
        <Input
          value={value}
          onChange={(e) => onChange(e.target.value)}
          placeholder="#059669"
          className={valid ? "" : "border-red-400"}
        />
      </div>
    </div>
  );
}

function ColorsSection({
  branding,
  update,
}: {
  branding: Branding;
  update: (p: Partial<Branding>) => void;
}) {
  return (
    <SectionCard
      title="Colors & Theme"
      subtitle="Pick colors and theme. Preview updates instantly on the right."
    >
      <div className="grid gap-3 md:grid-cols-2">
        <ColorField
          label="Primary color"
          value={branding.primary_color}
          onChange={(v) => update({ primary_color: v })}
        />
        <ColorField
          label="Accent color"
          value={branding.accent_color}
          onChange={(v) => update({ accent_color: v })}
        />
        <ColorField
          label="Visitor bubble background"
          value={branding.bubble_bg_color}
          onChange={(v) => update({ bubble_bg_color: v })}
        />
        <ColorField
          label="Visitor bubble text"
          value={branding.bubble_text_color}
          onChange={(v) => update({ bubble_text_color: v })}
        />
        <ColorField
          label="Header background"
          value={branding.header_bg_color}
          onChange={(v) => update({ header_bg_color: v })}
        />
        <ColorField
          label="Header text"
          value={branding.header_text_color}
          onChange={(v) => update({ header_text_color: v })}
        />
      </div>
      <div className="grid gap-3 md:grid-cols-3 mt-3">
        <div>
          <Label>Theme mode</Label>
          <Select
            value={branding.theme_mode}
            onValueChange={(v) => update({ theme_mode: v })}
          >
            <SelectTrigger>
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {THEME_MODES.map((t) => (
                <SelectItem key={t.value} value={t.value}>
                  {t.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
        <div>
          <Label>Rounded corners</Label>
          <Select
            value={branding.rounded}
            onValueChange={(v) => update({ rounded: v })}
          >
            <SelectTrigger>
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {ROUNDED_LEVELS.map((t) => (
                <SelectItem key={t.value} value={t.value}>
                  {t.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
        <div>
          <Label>Font family</Label>
          <Select
            value={branding.font_family}
            onValueChange={(v) => update({ font_family: v })}
          >
            <SelectTrigger>
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {FONT_FAMILIES.map((t) => (
                <SelectItem key={t.value} value={t.value}>
                  {t.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
      </div>
    </SectionCard>
  );
}

function LauncherSection({
  branding,
  update,
}: {
  branding: Branding;
  update: (p: Partial<Branding>) => void;
}) {
  return (
    <SectionCard
      title="Launcher"
      subtitle="The floating button visitors click to open the chat."
    >
      <div className="grid gap-3 md:grid-cols-3">
        <div>
          <Label>Shape</Label>
          <Select
            value={branding.launcher_style}
            onValueChange={(v) => update({ launcher_style: v })}
          >
            <SelectTrigger>
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {LAUNCHER_STYLES.map((t) => (
                <SelectItem key={t.value} value={t.value}>
                  {t.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
        <div>
          <Label>Icon</Label>
          <Select
            value={branding.launcher_icon}
            onValueChange={(v) => update({ launcher_icon: v })}
          >
            <SelectTrigger>
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {LAUNCHER_ICONS.map((t) => (
                <SelectItem key={t.value} value={t.value}>
                  {t.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
        <div>
          <Label>Position</Label>
          <Select
            value={branding.launcher_position}
            onValueChange={(v) => update({ launcher_position: v })}
          >
            <SelectTrigger>
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {LAUNCHER_POSITIONS.map((t) => (
                <SelectItem key={t.value} value={t.value}>
                  {t.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
      </div>
      {branding.launcher_icon === "custom_upload" && (
        <div className="mt-3">
          <AvatarUploader
            label="Custom launcher icon (SVG/PNG)"
            url={branding.launcher_icon_url}
            onChange={(url) => update({ launcher_icon_url: url })}
            kind="launcher-icon"
          />
        </div>
      )}
    </SectionCard>
  );
}

function MessagesSection({
  branding,
  update,
}: {
  branding: Branding;
  update: (p: Partial<Branding>) => void;
}) {
  const insertVariable = (
    field: keyof Branding,
    variable: string,
    currentValue: string
  ) => {
    update({ [field]: `${currentValue} ${variable}`.trim() } as Partial<
      Branding
    >);
  };

  return (
    <SectionCard
      title="Messages"
      subtitle="Customize the greeting, intros and placeholders. Supports variables {client_name} and {time_of_day}."
    >
      <div className="space-y-3">
        <div>
          <div className="flex items-center justify-between">
            <Label>Welcome message (pre-chat)</Label>
            <div className="flex gap-1">
              <Button
                size="sm"
                variant="ghost"
                className="h-6 px-2 text-[11px]"
                onClick={() =>
                  insertVariable(
                    "welcome_message",
                    "{client_name}",
                    branding.welcome_message
                  )
                }
              >
                + client_name
              </Button>
              <Button
                size="sm"
                variant="ghost"
                className="h-6 px-2 text-[11px]"
                onClick={() =>
                  insertVariable(
                    "welcome_message",
                    "{time_of_day}",
                    branding.welcome_message
                  )
                }
              >
                + time_of_day
              </Button>
            </div>
          </div>
          <Textarea
            rows={2}
            value={branding.welcome_message}
            onChange={(e) => update({ welcome_message: e.target.value })}
          />
        </div>
        <div>
          <Label>AI intro (first bubble after chat opens)</Label>
          <Textarea
            rows={3}
            value={branding.ai_intro_message}
            onChange={(e) => update({ ai_intro_message: e.target.value })}
          />
        </div>
        <div>
          <Label>Human handover message</Label>
          <Textarea
            rows={2}
            value={branding.human_handover_message}
            onChange={(e) => update({ human_handover_message: e.target.value })}
          />
        </div>
        <div>
          <Label>Offline message (when no agents + AI disabled)</Label>
          <Textarea
            rows={2}
            value={branding.offline_message}
            onChange={(e) => update({ offline_message: e.target.value })}
          />
        </div>
        <div>
          <Label>Input placeholder</Label>
          <Input
            value={branding.input_placeholder}
            onChange={(e) => update({ input_placeholder: e.target.value })}
          />
        </div>
      </div>
    </SectionCard>
  );
}

function FooterSoundSection({
  branding,
  update,
}: {
  branding: Branding;
  update: (p: Partial<Branding>) => void;
}) {
  return (
    <SectionCard title="Footer & Sound">
      <div className="grid gap-3 md:grid-cols-2">
        <div className="flex items-center justify-between rounded-md border border-slate-200 p-3">
          <div>
            <Label className="mb-1 block">Show footer text</Label>
            <p className="text-[11px] text-muted-foreground">
              e.g. "Powered by DoitEasy ✦ AI + Human support"
            </p>
          </div>
          <Switch
            checked={!!branding.show_branding_footer}
            onCheckedChange={(v) => update({ show_branding_footer: v })}
          />
        </div>
        <div>
          <Label>Footer text</Label>
          <Input
            value={branding.footer_text}
            onChange={(e) => update({ footer_text: e.target.value })}
            disabled={!branding.show_branding_footer}
          />
        </div>
        <div className="flex items-center justify-between rounded-md border border-slate-200 p-3">
          <div>
            <Label className="mb-1 block">Enable notification sound</Label>
            <p className="text-[11px] text-muted-foreground">
              Plays a subtle sound when a new message arrives.
            </p>
          </div>
          <Switch
            checked={!!branding.enable_sound}
            onCheckedChange={(v) => update({ enable_sound: v })}
          />
        </div>
        <div>
          <Label>Sound preset</Label>
          <Select
            value={branding.notification_sound}
            onValueChange={(v) => update({ notification_sound: v })}
          >
            <SelectTrigger>
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {SOUND_PRESETS.map((t) => (
                <SelectItem key={t.value} value={t.value}>
                  {t.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
      </div>
    </SectionCard>
  );
}

// ---------- Live preview ----------
function resolveTimeOfDay(): string {
  const h = new Date().getHours();
  if (h < 5) return "Good night";
  if (h < 12) return "Good morning";
  if (h < 18) return "Good afternoon";
  return "Good evening";
}

function resolveMessage(text: string, clientName: string): string {
  return (text || "")
    .replaceAll("{client_name}", clientName || "there")
    .replaceAll("{time_of_day}", resolveTimeOfDay());
}

function roundedToClass(r: string): string {
  switch (r) {
    case "none":
      return "rounded-none";
    case "sm":
      return "rounded-md";
    case "md":
      return "rounded-lg";
    case "lg":
      return "rounded-2xl";
    case "xl":
      return "rounded-3xl";
    default:
      return "rounded-2xl";
  }
}

function launcherShapeClass(s: string): string {
  switch (s) {
    case "pill":
      return "rounded-full px-5 h-12 w-auto";
    case "square":
      return "rounded-xl h-14 w-14";
    default:
      return "rounded-full h-14 w-14";
  }
}

function LauncherIcon({
  icon,
  iconUrl,
  color,
}: {
  icon: string;
  iconUrl: string;
  color: string;
}) {
  if (icon === "custom_upload" && iconUrl) {
    return <img src={iconUrl} alt="launcher" className="h-6 w-6" />;
  }
  const cls = "h-6 w-6";
  if (icon === "sparkles") return <Sparkles className={cls} style={{ color }} />;
  if (icon === "headset") return <Headset className={cls} style={{ color }} />;
  return <MessageCircle className={cls} style={{ color }} />;
}

function LivePreview({ branding }: { branding: Branding }) {
  const rounded = roundedToClass(branding.rounded);
  const welcome = resolveMessage(branding.welcome_message, "Alex");
  const aiIntro = resolveMessage(branding.ai_intro_message, "Alex");
  const isDark = branding.theme_mode === "dark";
  const panelBg = isDark ? "#0f172a" : "#ffffff";
  const panelText = isDark ? "#f1f5f9" : "#0f172a";
  const bodyBg = isDark ? "#111827" : "#f8fafc";

  return (
    <div className="rounded-xl border bg-gradient-to-br from-slate-50 to-slate-100 p-4 shadow-sm">
      <div className="mb-3 flex items-center gap-2 text-xs font-semibold text-slate-600">
        <Sparkles className="h-3.5 w-3.5" /> Live preview
      </div>

      {/* Mock phone/site background */}
      <div className="relative h-[560px] overflow-hidden rounded-2xl border bg-slate-200">
        {/* Launcher */}
        <div
          className={`absolute bottom-4 ${
            branding.launcher_position === "bottom-left" ? "left-4" : "right-4"
          }`}
        >
          <div
            className={`flex items-center justify-center shadow-xl ${launcherShapeClass(
              branding.launcher_style
            )}`}
            style={{ backgroundColor: branding.primary_color }}
          >
            <LauncherIcon
              icon={branding.launcher_icon}
              iconUrl={branding.launcher_icon_url}
              color={branding.header_text_color}
            />
            {branding.launcher_style === "pill" && (
              <span
                className="ml-2 text-sm font-semibold"
                style={{ color: branding.header_text_color }}
              >
                Chat
              </span>
            )}
          </div>
        </div>

        {/* Widget panel */}
        <div
          className={`absolute bottom-20 ${
            branding.launcher_position === "bottom-left" ? "left-4" : "right-4"
          } w-[320px] overflow-hidden shadow-2xl border ${rounded}`}
          style={{
            backgroundColor: panelBg,
            color: panelText,
            fontFamily:
              branding.font_family === "System"
                ? undefined
                : branding.font_family,
          }}
        >
          {/* Header */}
          <div
            className="flex items-center justify-between px-3 py-2.5"
            style={{
              backgroundColor: branding.header_bg_color,
              color: branding.header_text_color,
            }}
          >
            <div className="flex min-w-0 items-center gap-2">
              <div className="h-8 w-8 shrink-0 overflow-hidden rounded-full bg-white/20 flex items-center justify-center text-[11px] font-bold">
                {branding.avatar_url ? (
                  <img
                    src={branding.avatar_url}
                    alt="ai"
                    className="h-full w-full object-cover"
                  />
                ) : (
                  branding.avatar_fallback_initials || "AI"
                )}
              </div>
              <div className="min-w-0 leading-tight">
                <div className="truncate text-[13px] font-semibold">
                  {branding.widget_name}
                </div>
                <div className="truncate text-[10px] opacity-90">
                  AI Assistant
                </div>
              </div>
            </div>
            <X className="h-4 w-4 opacity-80" />
          </div>

          {/* Body */}
          <div
            className="flex flex-col gap-2 p-3"
            style={{ backgroundColor: bodyBg, minHeight: 280 }}
          >
            <div
              className="self-start max-w-[85%] rounded-2xl px-3 py-2 text-xs shadow"
              style={{
                backgroundColor: isDark ? "#1f2937" : "#ffffff",
                color: isDark ? "#e2e8f0" : "#0f172a",
              }}
            >
              <div
                className="mb-0.5 text-[10px] font-semibold"
                style={{ color: branding.primary_color }}
              >
                {branding.widget_name} <span className="opacity-70">AI</span>
              </div>
              {welcome}
            </div>
            <div
              className="self-start max-w-[85%] rounded-2xl px-3 py-2 text-xs shadow"
              style={{
                backgroundColor: isDark ? "#1f2937" : "#ffffff",
                color: isDark ? "#e2e8f0" : "#0f172a",
              }}
            >
              {aiIntro}
            </div>
            <div
              className="self-end max-w-[85%] rounded-2xl px-3 py-2 text-xs shadow"
              style={{
                backgroundColor: branding.bubble_bg_color,
                color: branding.bubble_text_color,
              }}
            >
              Hi, I need help with my hosting plan.
            </div>
          </div>

          {/* Input */}
          <div
            className="flex items-center gap-2 border-t px-2 py-2"
            style={{
              borderColor: isDark ? "#1f2937" : "#e2e8f0",
              backgroundColor: panelBg,
            }}
          >
            <div
              className="flex-1 rounded-md border px-2 py-1.5 text-[11px]"
              style={{
                borderColor: isDark ? "#334155" : "#e2e8f0",
                color: isDark ? "#94a3b8" : "#64748b",
                backgroundColor: isDark ? "#0b1220" : "#ffffff",
              }}
            >
              {branding.input_placeholder}
            </div>
            <div
              className="h-7 w-7 shrink-0 rounded-md flex items-center justify-center"
              style={{ backgroundColor: branding.primary_color }}
            >
              <Send
                className="h-3.5 w-3.5"
                style={{ color: branding.header_text_color }}
              />
            </div>
          </div>

          {branding.show_branding_footer && branding.footer_text && (
            <div
              className="px-3 py-1.5 text-center text-[10px]"
              style={{
                backgroundColor: panelBg,
                color: isDark ? "#94a3b8" : "#64748b",
              }}
            >
              {branding.footer_text}
            </div>
          )}
        </div>
      </div>

      <p className="mt-2 text-[11px] text-muted-foreground">
        Preview uses "Alex" as {"{client_name}"} and your local time for{" "}
        {"{time_of_day}"}.
      </p>
    </div>
  );
}