'use client';

import React, { useMemo, useState } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { adminClient } from '@/lib/api';
import type { AdminMessage, AdminMessageAttachment } from '@zyphon/api-client';
import { CHANNELS, ago, type ChannelId } from '@/lib/types';
import { Button } from '@/components/ui/Button';
import { Badge } from '@/components/ui/Badge';
import { Input } from '@/components/ui/Input';
import { Select } from '@/components/ui/Select';
import { useToast } from '@/components/Toast';

type Attempt = { p: string; ok: boolean; e?: string };
type ViewMode = 'all' | 'email' | 'sms' | 'whatsapp';

function asAttempts(value: unknown): Attempt[] {
  if (!Array.isArray(value)) return [];
  const out: Attempt[] = [];
  for (const item of value) {
    if (!item || typeof item !== 'object') continue;
    const row = item as Record<string, unknown>;
    const attempt: Attempt = {
      p: String(row.p || row.provider || 'provider'),
      ok: Boolean(row.ok ?? row.success),
    };
    if (row.e != null) attempt.e = String(row.e);
    else if (row.error != null) attempt.e = String(row.error);
    out.push(attempt);
  }
  return out;
}

function asAttachments(value: unknown): AdminMessageAttachment[] {
  if (!Array.isArray(value)) return [];
  return value
    .filter((item): item is Record<string, unknown> => Boolean(item) && typeof item === 'object')
    .map((row) => ({
      filename: String(row.filename || 'attachment'),
      contentType: String(row.contentType || 'application/octet-stream'),
      size_bytes: Number(row.size_bytes || 0),
      ...(row.url ? { url: String(row.url) } : {}),
    }));
}

function formatBytes(n: number): string {
  if (!n || n < 0) return '—';
  if (n < 1024) return `${n} B`;
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
  return `${(n / (1024 * 1024)).toFixed(1)} MB`;
}

function fileKindLabel(contentType: string, filename: string): string {
  const ct = contentType.toLowerCase();
  const name = filename.toLowerCase();
  if (ct.startsWith('image/') || /\.(png|jpe?g|webp|gif)$/.test(name)) return 'Image';
  if (ct.startsWith('video/') || /\.(mp4|3gp|mov)$/.test(name)) return 'Video';
  if (ct.startsWith('audio/') || /\.(mp3|ogg|aac|m4a|amr)$/.test(name)) return 'Audio';
  if (ct.includes('pdf') || name.endsWith('.pdf')) return 'PDF';
  if (ct.includes('html') || name.endsWith('.html') || name.endsWith('.htm')) return 'HTML';
  if (ct.includes('zip') || name.endsWith('.zip')) return 'ZIP';
  if (ct.startsWith('text/')) return 'Text';
  return 'Document';
}

function AttachmentList({ items }: { items: AdminMessageAttachment[] }) {
  if (!items.length) return null;
  return (
    <div className="mb-5">
      <div className="text-xs font-semibold uppercase tracking-wider text-muted mb-2">
        Attachments ({items.length})
      </div>
      <div className="flex flex-col gap-2">
        {items.map((a, i) => (
          <div
            key={`${a.filename}-${i}`}
            className="flex items-center gap-3 p-3 rounded-[var(--r)] border border-line bg-bg"
          >
            <div className="w-9 h-9 rounded-md border border-line bg-surface-2 grid place-items-center text-[10px] font-bold text-muted flex-none">
              {fileKindLabel(a.contentType, a.filename)}
            </div>
            <div className="min-w-0 flex-1">
              <div className="text-sm font-medium text-text truncate">{a.filename}</div>
              <div className="text-[11px] text-muted font-mono truncate">
                {a.contentType}
                {a.size_bytes > 0 ? ` · ${formatBytes(a.size_bytes)}` : ''}
                {a.url ? ` · ${a.url}` : ''}
              </div>
            </div>
            {a.url ? (
              <a
                href={a.url}
                target="_blank"
                rel="noreferrer"
                className="text-xs font-medium text-accent hover:underline flex-none"
              >
                Open URL ↗
              </a>
            ) : (
              <span className="text-[10px] text-muted flex-none" title="File bytes are not stored in Zyphon logs">
                Sent with message
              </span>
            )}
          </div>
        ))}
      </div>
      <p className="text-[11px] text-muted m-0 mt-2">
        Zyphon keeps attachment names, URLs, and sizes for the console. File bytes go only to the provider — they are not stored here.
      </p>
    </div>
  );
}

export default function MessagesPage() {
  const { toast } = useToast();
  const queryClient = useQueryClient();

  const [selectedApp, setSelectedApp] = useState<string>('');
  const [viewMode, setViewMode] = useState<ViewMode>('all');
  const [searchQuery, setSearchQuery] = useState('');
  const [statusFilter, setStatusFilter] = useState('');
  const [selectedId, setSelectedId] = useState<string | null>(null);

  // Compose modal state
  const [showCompose, setShowCompose] = useState(false);
  const [composeChannel, setComposeChannel] = useState<ChannelId>('email');
  const [composeTemplateId, setComposeTemplateId] = useState('');
  const [composeVars, setComposeVars] = useState<Record<string, string>>({});
  const [composeTo, setComposeTo] = useState('');
  const [composeSubject, setComposeSubject] = useState('Welcome to Zettai');
  const [composeBody, setComposeBody] = useState(
    'Hello! Your message was routed cleanly through Zyphon Unified Messaging Gateway.',
  );
  const [composeSending, setComposeSending] = useState(false);

  const { data: messages = [], isLoading: loading } = useQuery({
    queryKey: ['messages'],
    queryFn: () => adminClient.getMessages({ limit: 200 }),
    refetchInterval: 4000,
  });

  const { data: apps = [] } = useQuery({
    queryKey: ['applications'],
    queryFn: () => adminClient.getApplications(),
  });

  const { data: providers = [] } = useQuery({
    queryKey: ['providers'],
    queryFn: () => adminClient.getProviders(),
  });

  const { data: templatesData } = useQuery({
    queryKey: ['templates'],
    queryFn: () => adminClient.getTemplates(),
  });
  const allTemplates = (templatesData?.templates || []) as Array<{
    id: string;
    name: string;
    channel: ChannelId;
    subject?: string;
    body: string;
    dlt_id?: string;
    variables?: string[];
  }>;

  // Build application list combining configured apps + any apps seen in messages
  const appTabs = useMemo(() => {
    const map = new Map<string, number>();
    for (const a of apps) {
      map.set(a.name, 0);
    }
    for (const m of messages) {
      const name = m.app || 'Direct';
      map.set(name, (map.get(name) || 0) + 1);
    }
    return Array.from(map.entries()).map(([name, count]) => ({ name, count }));
  }, [apps, messages]);

  const filteredMessages = useMemo(() => {
    const q = searchQuery.toLowerCase().trim();
    return messages.filter((m) => {
      if (selectedApp && m.app !== selectedApp) return false;
      if (viewMode !== 'all' && m.channel !== viewMode) return false;
      if (statusFilter && m.status !== statusFilter) return false;
      if (q) {
        const target =
          `${m.to} ${m.app} ${m.id} ${m.via || ''} ${m.subject || ''} ${m.body || ''}`.toLowerCase();
        if (!target.includes(q)) return false;
      }
      return true;
    });
  }, [messages, selectedApp, viewMode, statusFilter, searchQuery]);

  const activeSelectedId =
    selectedId && filteredMessages.some((m) => m.id === selectedId)
      ? selectedId
      : filteredMessages[0]?.id || null;

  const selectedFromList = useMemo(
    () =>
      messages.find((m) => m.id === (viewMode === 'email' ? activeSelectedId : selectedId)) ||
      null,
    [messages, selectedId, activeSelectedId, viewMode],
  );

  const detailQuery = useQuery({
    queryKey: ['messages', 'detail', selectedFromList?.id],
    queryFn: () => adminClient.getMessageDetail(selectedFromList!.id),
    enabled: Boolean(selectedFromList?.id),
  });

  const detail = detailQuery.data as
    | { message?: Record<string, unknown>; attempts?: unknown }
    | undefined;
  const detailMessage = detail?.message;
  const detailAttempts = asAttempts(detail?.attempts ?? detailMessage?.attempts);
  const activeMessage: AdminMessage | null = selectedFromList
    ? {
        ...selectedFromList,
        subject:
          (detailMessage?.subject as string | undefined) ||
          selectedFromList.subject ||
          'Transactional Notification',
        body:
          (detailMessage?.body_preview as string | undefined) ||
          (detailMessage?.body_stored as string | undefined) ||
          selectedFromList.body ||
          (selectedFromList.note
            ? `Delivery Error: ${selectedFromList.note}`
            : `Message dispatched via ${selectedFromList.via || 'gateway'} to ${selectedFromList.to}.`),
        status: String(detailMessage?.status || selectedFromList.status) as AdminMessage['status'],
        via:
          detailMessage?.provider != null
            ? String(detailMessage.provider)
            : selectedFromList.via,
        ms:
          detailMessage?.latency_ms != null
            ? Number(detailMessage.latency_ms)
            : selectedFromList.ms,
        note:
          detailMessage?.error && typeof detailMessage.error === 'object'
            ? String((detailMessage.error as { message?: string }).message || '')
            : selectedFromList.note,
        att: detailAttempts.length > 0 ? detailAttempts : selectedFromList.att,
        attachments:
          asAttachments(detailMessage?.attachments).length > 0
            ? asAttachments(detailMessage?.attachments)
            : selectedFromList.attachments || [],
      }
    : null;

  const renderWithVars = (text: string, vars: Record<string, string>) => {
    return text.replace(/\{\{\s*([a-zA-Z0-9_]+)\s*\}\}/g, (_match, key) => {
      return vars[key] !== undefined && vars[key] !== '' ? vars[key]! : `{{${key}}}`;
    });
  };

  const handleSelectComposeTemplate = (tplId: string) => {
    setComposeTemplateId(tplId);
    if (!tplId) {
      setComposeVars({});
      return;
    }
    const tpl = allTemplates.find((t) => t.id === tplId);
    if (!tpl) return;
    if (tpl.subject) setComposeSubject(tpl.subject);
    if (tpl.body) setComposeBody(tpl.body);

    const detected = new Set<string>(tpl.variables || []);
    const regex = /\{\{\s*([a-zA-Z0-9_]+)\s*\}\}/g;
    for (const src of [tpl.subject || '', tpl.body || '']) {
      let m: RegExpExecArray | null;
      while ((m = regex.exec(src)) !== null) {
        if (m[1]) detected.add(m[1]);
      }
    }
    const nextVars: Record<string, string> = {};
    detected.forEach((v) => {
      nextVars[v] = composeVars[v] || '';
    });
    setComposeVars(nextVars);
  };

  const resolveProviderForApp = (appName: string, channel: ChannelId) => {
    const appObj = apps.find((a) => a.name === appName || a.id === appName);
    const boundIds = appObj?.bindings?.[channel] || [];
    for (const bid of boundIds) {
      const found = providers.find((p) => p.id === bid && p.channel === channel);
      if (found) return found;
    }
    return providers.find((p) => p.channel === channel);
  };

  const handleComposeSend = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!composeTo.trim()) {
      toast('Enter a recipient address or phone number');
      return;
    }
    const prov =
      providers.find((p) => p.channel === composeChannel) ||
      resolveProviderForApp(selectedApp || apps[0]?.name || '', composeChannel);
    if (!prov) {
      toast(`No ${CHANNELS[composeChannel].name} provider connected yet.`);
      return;
    }
    setComposeSending(true);
    try {
      const finalSubject =
        composeChannel === 'email'
          ? renderWithVars(composeSubject, composeVars)
          : undefined;
      const finalBody = renderWithVars(composeBody, composeVars);
      const selectedTpl = allTemplates.find((t) => t.id === composeTemplateId);
      const res = await adminClient.testSendProvider(prov.id, {
        to: composeTo.trim(),
        subject: finalSubject,
        body: finalBody,
        template_id: selectedTpl?.dlt_id || selectedTpl?.id || undefined,
        variables: Object.keys(composeVars).length > 0 ? composeVars : undefined,
      });
      if (res.ok) {
        toast(`Sent via ${prov.name} (${res.latency_ms}ms)`);
        setShowCompose(false);
        setComposeTo('');
        await queryClient.invalidateQueries({ queryKey: ['messages'] });
        await queryClient.invalidateQueries({ queryKey: ['stats'] });
      } else {
        toast(res.error || 'Dispatch failed');
      }
    } catch (err: any) {
      toast(err.message || 'Dispatch failed');
    } finally {
      setComposeSending(false);
    }
  };

  const emailCount = messages.filter(
    (m) => (!selectedApp || m.app === selectedApp) && m.channel === 'email',
  ).length;
  const smsCount = messages.filter(
    (m) => (!selectedApp || m.app === selectedApp) && m.channel === 'sms',
  ).length;
  const waCount = messages.filter(
    (m) => (!selectedApp || m.app === selectedApp) && m.channel === 'whatsapp',
  ).length;

  return (
    <div>
      {/* Header */}
      <div className="flex gap-3 items-end justify-between mb-5 flex-wrap">
        <div>
          <h1 className="text-2xl font-bold tracking-tight text-text m-0 mb-1">
            Live Application Messages
          </h1>
          <div className="text-muted text-sm">
            Inspect outbound & routed communications per application in Gmail, SMS handset, or WhatsApp views.
          </div>
        </div>
        <Button
          variant="primary"
          onClick={() => {
            setComposeChannel(viewMode === 'all' ? 'email' : viewMode);
            setShowCompose(true);
          }}
        >
          + Dispatch message
        </Button>
      </div>

      {/* Application Selector Bar */}
      <div className="zy-card-3d p-3 mb-4">
        <div className="text-xs font-semibold uppercase tracking-wider text-muted mb-2">
          Filter by Application
        </div>
        <div className="flex items-center gap-2 flex-wrap">
          <button
            type="button"
            onClick={() => setSelectedApp('')}
            className={`px-3 py-1.5 rounded-[var(--r)] text-xs font-semibold border transition-all cursor-pointer ${
              selectedApp === ''
                ? 'bg-accent text-on-accent border-accent'
                : 'bg-bg text-text border-line hover:bg-surface-2'
            }`}
          >
            All Applications ({messages.length})
          </button>
          {appTabs.map((a) => (
            <button
              key={a.name}
              type="button"
              onClick={() => setSelectedApp(a.name)}
              className={`px-3 py-1.5 rounded-[var(--r)] text-xs font-semibold border transition-all cursor-pointer flex items-center gap-1.5 ${
                selectedApp === a.name
                  ? 'bg-accent text-on-accent border-accent'
                  : 'bg-bg text-text border-line hover:bg-surface-2'
              }`}
            >
              <span>{a.name}</span>
              <span className="opacity-80 font-mono">({a.count})</span>
            </button>
          ))}
        </div>
      </div>

      {/* Channel Experience Tabs + Search */}
      <div className="flex gap-3 items-center justify-between mb-4 flex-wrap">
        <div className="inline-flex rounded-[var(--r)] border border-line bg-surface p-1 gap-1">
          <button
            type="button"
            onClick={() => setViewMode('all')}
            className={`px-3 py-1.5 rounded-[calc(var(--r)-2px)] text-xs font-semibold transition-all cursor-pointer border-0 ${
              viewMode === 'all'
                ? 'bg-accent text-on-accent'
                : 'bg-transparent text-muted hover:text-text'
            }`}
          >
            Unified Stream ({emailCount + smsCount + waCount})
          </button>
          <button
            type="button"
            onClick={() => setViewMode('email')}
            className={`px-3 py-1.5 rounded-[calc(var(--r)-2px)] text-xs font-semibold transition-all cursor-pointer border-0 ${
              viewMode === 'email'
                ? 'bg-accent text-on-accent'
                : 'bg-transparent text-muted hover:text-text'
            }`}
          >
            ✉ Email Inbox ({emailCount})
          </button>
          <button
            type="button"
            onClick={() => setViewMode('sms')}
            className={`px-3 py-1.5 rounded-[calc(var(--r)-2px)] text-xs font-semibold transition-all cursor-pointer border-0 ${
              viewMode === 'sms'
                ? 'bg-accent text-on-accent'
                : 'bg-transparent text-muted hover:text-text'
            }`}
          >
            💬 SMS Handset ({smsCount})
          </button>
          <button
            type="button"
            onClick={() => setViewMode('whatsapp')}
            className={`px-3 py-1.5 rounded-[calc(var(--r)-2px)] text-xs font-semibold transition-all cursor-pointer border-0 ${
              viewMode === 'whatsapp'
                ? 'bg-accent text-on-accent'
                : 'bg-transparent text-muted hover:text-text'
            }`}
          >
            🟢 WhatsApp Chat ({waCount})
          </button>
        </div>

        <div className="flex gap-2 items-center flex-wrap flex-1 justify-end">
          <input
            type="text"
            placeholder="Search recipient, subject, body, ID…"
            value={searchQuery}
            onChange={(e) => setSearchQuery(e.target.value)}
            className="w-[240px] bg-surface border border-line rounded-[var(--r)] px-3 py-1.5 text-text text-sm focus:border-accent focus:outline-none"
          />
          <select
            value={statusFilter}
            onChange={(e) => setStatusFilter(e.target.value)}
            className="bg-surface border border-line rounded-[var(--r)] px-3 py-1.5 text-text text-sm focus:border-accent focus:outline-none"
          >
            <option value="">All statuses</option>
            <option value="delivered">Delivered</option>
            <option value="sent">Sent</option>
            <option value="failed">Failed</option>
            <option value="blocked">Blocked</option>
          </select>
        </div>
      </div>

      {/* VIEW 1: GMAIL-STYLE EMAIL INBOX */}
      {viewMode === 'email' && (
        <div className="zy-card-3d overflow-hidden grid grid-cols-1 lg:grid-cols-[360px_1fr] min-h-[500px]">
          {/* Left Inbox List */}
          <div className="border-r border-line bg-bg overflow-y-auto max-h-[600px]">
            <div className="px-4 py-3 border-b border-line flex items-center justify-between bg-surface">
              <span className="font-semibold text-xs uppercase tracking-wider text-muted">
                {selectedApp ? `${selectedApp} · Outbox` : 'All Apps · Email Outbox'}
              </span>
              <Badge tone="accent">{filteredMessages.length} mails</Badge>
            </div>
            {filteredMessages.length === 0 ? (
              <div className="p-8 text-center text-muted text-sm">
                No emails found for this filter.
              </div>
            ) : (
              filteredMessages.map((m) => {
                const isSelected = m.id === activeSelectedId;
                return (
                  <div
                    key={m.id}
                    onClick={() => setSelectedId(m.id)}
                    className={`p-3.5 border-b border-line cursor-pointer transition-colors ${
                      isSelected ? 'bg-accent-soft border-l-4 border-l-accent' : 'hover:bg-surface-2'
                    }`}
                  >
                    <div className="flex items-center justify-between gap-2 mb-1">
                      <div className="flex items-center gap-2 min-w-0">
                        <span className="w-6 h-6 rounded-full bg-surface-2 border border-line text-xs font-bold grid place-items-center flex-none">
                          {(m.app || 'Z')[0]?.toUpperCase()}
                        </span>
                        <span className="font-semibold text-sm text-text truncate">{m.to}</span>
                      </div>
                      <span className="text-[11px] text-muted flex-none">{ago(m.ts)}</span>
                    </div>
                    <div className="text-xs font-semibold text-text truncate mb-0.5 flex items-center gap-1.5">
                      <span className="truncate">{m.subject || 'Transactional Notification'}</span>
                      {(m.attachments?.length || 0) > 0 ? (
                        <span
                          className="text-muted flex-none"
                          title={`${m.attachments!.length} attachment(s)`}
                        >
                          📎 {m.attachments!.length}
                        </span>
                      ) : null}
                    </div>
                    <div className="text-xs text-muted truncate mb-2">
                      {m.body || m.note || `Routed via ${m.via || 'SMTP'}`}
                    </div>
                    <div className="flex items-center justify-between text-[11px]">
                      <span className="font-mono text-muted">{m.app}</span>
                      <Badge
                        tone={
                          m.status === 'delivered' || m.status === 'sent'
                            ? 'ok'
                            : m.status === 'failed'
                            ? 'danger'
                            : 'warn'
                        }
                      >
                        {m.status}
                      </Badge>
                    </div>
                  </div>
                );
              })
            )}
          </div>

          {/* Right Gmail Reader Pane */}
          <div className="p-6 bg-surface flex flex-col justify-between">
            {activeMessage ? (
              <div>
                <div className="flex items-start justify-between gap-4 border-b border-line pb-4 mb-4 flex-wrap">
                  <div>
                    <div className="flex items-center gap-2 mb-1">
                      <Badge tone="accent">{activeMessage.app}</Badge>
                      <Badge
                        tone={
                          activeMessage.status === 'delivered' || activeMessage.status === 'sent'
                            ? 'ok'
                            : 'danger'
                        }
                      >
                        {activeMessage.status.toUpperCase()}
                      </Badge>
                      <span className="text-xs font-mono text-muted">
                        {activeMessage.ms} ms via {activeMessage.via || 'smtp'}
                      </span>
                    </div>
                    <h2 className="text-xl font-bold text-text m-0 mt-1">
                      {activeMessage.subject || 'Transactional Notification'}
                    </h2>
                  </div>
                  <div className="text-xs text-muted font-mono">
                    {new Date(activeMessage.ts).toLocaleString()}
                  </div>
                </div>

                <div className="flex items-center gap-3 mb-5 p-3 rounded-[var(--r)] bg-bg border border-line">
                  <div className="w-9 h-9 rounded-full bg-accent text-on-accent font-bold grid place-items-center">
                    {(activeMessage.app || 'Z')[0]?.toUpperCase()}
                  </div>
                  <div className="text-xs leading-relaxed flex-1">
                    <div>
                      <span className="text-muted">Application: </span>
                      <b className="text-text">{activeMessage.app}</b>
                      <span className="text-muted"> via </span>
                      <span className="font-mono text-text">{activeMessage.via || 'SMTP'}</span>
                    </div>
                    <div>
                      <span className="text-muted">To: </span>
                      <span className="font-mono text-text font-medium">{activeMessage.to}</span>
                    </div>
                  </div>
                  <div className="text-[11px] font-mono text-muted">ID: {activeMessage.id}</div>
                </div>

                {/* Email Body Box */}
                <div className="rounded-[var(--rl)] border border-line bg-bg p-5 mb-5 text-sm text-text leading-relaxed whitespace-pre-wrap min-h-[160px]">
                  {activeMessage.body}
                </div>

                <AttachmentList items={activeMessage.attachments || []} />

                {/* Provider Trace */}
                <div className="border-t border-line pt-4">
                  <div className="text-xs font-semibold uppercase tracking-wider text-muted mb-2">
                    Gateway Delivery Trace
                  </div>
                  <div className="space-y-1.5">
                    {activeMessage.att.map((a, idx) => {
                      const matched = providers.find((p) => p.id === a.p);
                      const providerLabel = matched?.name || a.p;
                      return (
                        <div
                          key={idx}
                          className="flex flex-col gap-1 text-xs p-2.5 rounded bg-bg border border-line"
                        >
                          <div className="flex items-center justify-between gap-2 flex-wrap">
                            <span>
                              Attempt #{idx + 1} · <b>{providerLabel}</b>
                              {matched && matched.name !== a.p ? (
                                <span className="text-muted font-mono ml-1.5">{a.p}</span>
                              ) : null}
                            </span>
                            <span
                              className={
                                a.ok ? 'text-ok font-semibold' : 'text-danger font-semibold'
                              }
                            >
                              {a.ok ? '✓ Accepted by provider' : '✕ Rejected'}
                            </span>
                          </div>
                          {!a.ok && (
                            <div className="text-danger leading-relaxed whitespace-pre-wrap break-words">
                              {a.e || 'Unknown provider error'}
                            </div>
                          )}
                        </div>
                      );
                    })}
                  </div>
                </div>
              </div>
            ) : (
              <div className="m-auto text-center text-muted">
                Select an email from the inbox list to inspect its content and SMTP trace.
              </div>
            )}
          </div>
        </div>
      )}

      {/* VIEW 2: SMS HANDSET & DLT CONSOLE */}
      {viewMode === 'sms' && (
        <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
          {filteredMessages.length === 0 ? (
            <div className="zy-card-3d p-10 text-center text-muted col-span-full">
              No SMS dispatches yet for {selectedApp || 'any application'}. Click{' '}
              <b>+ Dispatch message</b> to test your SMS route.
            </div>
          ) : (
            filteredMessages.map((m) => {
              const bodyText =
                m.body ||
                `Your Zyphon verification OTP is dispatched via ${m.via || 'DLT Gateway'}.`;
              const charCount = bodyText.length;
              const segments = Math.max(1, Math.ceil(charCount / 160));
              return (
                <div key={m.id} className="zy-sms-frame p-4 flex flex-col justify-between gap-3">
                  <div className="flex items-center justify-between border-b border-line pb-2.5">
                    <div className="flex items-center gap-2">
                      <span className="px-2 py-0.5 rounded bg-accent-soft text-accent font-mono text-xs font-bold">
                        IN-DLT SMS
                      </span>
                      <b className="text-sm text-text">{m.app}</b>
                    </div>
                    <Badge
                      tone={
                        m.status === 'delivered' || m.status === 'sent'
                          ? 'ok'
                          : m.status === 'failed'
                          ? 'danger'
                          : 'warn'
                      }
                    >
                      {m.status}
                    </Badge>
                  </div>

                  <div className="py-2">
                    <div className="text-[11px] text-muted font-mono mb-1">
                      To: <b className="text-text">{m.to}</b> · Via: <b>{m.via || 'SMS Route'}</b>
                    </div>
                    <div className="zy-sms-bubble p-3.5 text-sm leading-relaxed">
                      {bodyText}
                      {(m.attachments?.length || 0) > 0 && (
                        <div className="mt-2 pt-2 border-t border-line/50 space-y-1">
                          {m.attachments!.map((a, idx) => (
                            <div
                              key={`${a.filename}-${idx}`}
                              className="flex items-center justify-between gap-2 text-xs bg-surface-2 rounded px-2 py-1"
                            >
                              <span className="font-mono truncate">
                                [{fileKindLabel(a.contentType, a.filename)}] {a.filename}
                              </span>
                              {a.url ? (
                                <a
                                  href={a.url}
                                  target="_blank"
                                  rel="noreferrer"
                                  className="text-accent hover:underline flex-none"
                                >
                                  Open ↗
                                </a>
                              ) : null}
                            </div>
                          ))}
                        </div>
                      )}
                    </div>
                  </div>

                  <div className="flex items-center justify-between text-[11px] text-muted font-mono border-t border-line pt-2">
                    <span>
                      {charCount} chars · {segments} {segments === 1 ? 'segment' : 'segments'}
                    </span>
                    <span>
                      {m.ms} ms · {ago(m.ts)}
                    </span>
                  </div>
                </div>
              );
            })
          )}
        </div>
      )}

      {/* VIEW 3: WHATSAPP BUSINESS CHAT VIEW */}
      {viewMode === 'whatsapp' && (
        <div className="zy-card-3d overflow-hidden">
          <div className="px-4 py-3 bg-surface border-b border-line flex items-center justify-between">
            <div className="flex items-center gap-2.5">
              <span className="w-3 h-3 rounded-full bg-ok" />
              <b className="text-sm text-text">
                WhatsApp Business Stream {selectedApp ? `· ${selectedApp}` : ''}
              </b>
            </div>
            <span className="text-xs text-muted font-mono">
              {filteredMessages.length} dispatches
            </span>
          </div>
          <div className="zy-wa-canvas p-6 min-h-[380px] space-y-4">
            {filteredMessages.length === 0 ? (
              <div className="bg-surface border border-line rounded-[var(--rl)] p-8 text-center text-muted max-w-md mx-auto">
                No WhatsApp messages yet. Connect Meta Cloud API, Gupshup, or 360dialog in Channels to send WhatsApp templates.
              </div>
            ) : (
              filteredMessages.map((m) => (
                <div key={m.id} className="max-w-lg ml-auto">
                  <div className="text-[11px] text-muted font-mono mb-1 text-right">
                    {m.app} → <b>{m.to}</b> via {m.via || 'WhatsApp'}
                  </div>
                  <div className="zy-wa-bubble p-3.5 text-sm">
                    {(m.attachments?.length || 0) > 0 && (
                      <div className="mb-2 space-y-1.5">
                        {m.attachments!.map((a, idx) => (
                          <div
                            key={`${a.filename}-${idx}`}
                            className="flex items-center justify-between gap-2 text-xs rounded bg-bg/40 border border-line/40 px-2.5 py-1.5"
                          >
                            <span className="font-mono truncate">
                              [{fileKindLabel(a.contentType, a.filename)}] {a.filename}
                            </span>
                            {a.url ? (
                              <a
                                href={a.url}
                                target="_blank"
                                rel="noreferrer"
                                className="text-accent hover:underline flex-none"
                              >
                                Open ↗
                              </a>
                            ) : (
                              <span className="text-[10px] opacity-75">Uploaded</span>
                            )}
                          </div>
                        ))}
                      </div>
                    )}
                    <div className="leading-relaxed">
                      {m.body || 'WhatsApp template message dispatched via Zyphon.'}
                    </div>
                    <div className="flex items-center justify-end gap-1.5 text-[11px] opacity-75 mt-1.5 font-mono">
                      <span>{new Date(m.ts).toLocaleTimeString()}</span>
                      <span>· {m.ms}ms</span>
                      <span className={m.status === 'failed' ? 'text-danger' : 'text-ok font-bold'}>
                        {m.status === 'failed' ? '✕ Failed' : '✓✓ Delivered'}
                      </span>
                    </div>
                  </div>
                </div>
              ))
            )}
          </div>
        </div>
      )}

      {/* VIEW 4: UNIFIED STREAM TABLE */}
      {viewMode === 'all' && (
        <div className="zy-card-3d p-1.5 overflow-hidden">
          <div className="overflow-x-auto">
            <table className="w-full border-collapse">
              <thead>
                <tr className="border-b border-line text-left text-muted text-[12.5px] font-medium">
                  <th className="py-2.5 px-3">When</th>
                  <th className="py-2.5 px-3">Application</th>
                  <th className="py-2.5 px-3">Channel</th>
                  <th className="py-2.5 px-3">Recipient</th>
                  <th className="py-2.5 px-3">Content / Subject</th>
                  <th className="py-2.5 px-3">Status</th>
                  <th className="py-2.5 px-3">Provider</th>
                </tr>
              </thead>
              <tbody>
                {filteredMessages.length > 0 ? (
                  filteredMessages.map((m) => (
                    <tr
                      key={m.id}
                      onClick={() => setSelectedId(m.id)}
                      className="border-b border-line last:border-0 hover:bg-surface-2 cursor-pointer transition-colors"
                    >
                      <td className="py-3 px-3 text-muted text-xs font-mono">{ago(m.ts)}</td>
                      <td className="py-3 px-3">
                        <Badge tone="accent">{m.app}</Badge>
                      </td>
                      <td className="py-3 px-3 text-text font-medium">
                        {CHANNELS[m.channel]?.name || m.channel}
                      </td>
                      <td className="py-3 px-3 text-text font-mono text-[13px]">{m.to}</td>
                      <td className="py-3 px-3 text-muted text-xs max-w-[280px]">
                        <div className="truncate">
                          {m.subject ? <b className="text-text">{m.subject}: </b> : null}
                          {m.body || m.note || '—'}
                        </div>
                        {(m.attachments?.length || 0) > 0 ? (
                          <div className="text-[11px] text-muted mt-0.5">
                            📎 {m.attachments!.map((a) => a.filename).join(', ')}
                          </div>
                        ) : null}
                      </td>
                      <td className="py-3 px-3">
                        <span
                          className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-semibold ${
                            m.status === 'delivered' || m.status === 'sent'
                              ? 'bg-ok-soft text-ok'
                              : m.status === 'failed'
                              ? 'bg-danger-soft text-danger'
                              : 'bg-warn-soft text-warn'
                          }`}
                        >
                          {m.status.charAt(0).toUpperCase() + m.status.slice(1)}
                        </span>
                      </td>
                      <td className="py-3 px-3 text-muted font-mono text-xs">
                        {m.via || '—'} ({m.ms}ms)
                      </td>
                    </tr>
                  ))
                ) : (
                  <tr>
                    <td colSpan={7} className="py-10 text-center text-muted">
                      {loading ? 'Loading live messages…' : 'No messages match the current filter.'}
                    </td>
                  </tr>
                )}
              </tbody>
            </table>
          </div>
        </div>
      )}

      {/* Drawer for Unified / SMS / WhatsApp item click */}
      {selectedId && viewMode !== 'email' && activeMessage && (
        <>
          <div
            onClick={() => setSelectedId(null)}
            className="fixed inset-0 bg-overlay z-30 transition-opacity"
          />
          <aside className="fixed top-0 right-0 h-full w-[min(560px,100vw)] bg-bg border-l border-line z-40 overflow-y-auto p-[26px] shadow-card">
            <div className="flex justify-between items-center mb-3">
              <Badge tone="accent">{activeMessage.app}</Badge>
              <button
                onClick={() => setSelectedId(null)}
                className="text-muted hover:text-text text-[13px] font-medium px-2 py-1 rounded cursor-pointer border-0 bg-transparent"
              >
                Close ✕
              </button>
            </div>

            <h1 className="text-xl font-bold tracking-tight text-text mb-1">
              {CHANNELS[activeMessage.channel]?.name} to {activeMessage.to}
            </h1>
            <div className="flex items-center gap-2.5 my-2 mb-4 flex-wrap">
              <Badge
                tone={
                  activeMessage.status === 'delivered' || activeMessage.status === 'sent'
                    ? 'ok'
                    : 'danger'
                }
              >
                {activeMessage.status.toUpperCase()}
              </Badge>
              <span className="text-muted text-[13px] font-mono">
                {new Date(activeMessage.ts).toLocaleString()} · {activeMessage.ms} ms
              </span>
            </div>

            {activeMessage.subject && (
              <div className="mb-3 text-sm">
                <span className="text-muted">Subject: </span>
                <b className="text-text">{activeMessage.subject}</b>
              </div>
            )}

            <div className="zy-card-3d p-4 mb-4">
              <div className="text-xs font-semibold uppercase tracking-wider text-muted mb-1.5">
                Message Payload
              </div>
              <div className="text-sm text-text whitespace-pre-wrap">{activeMessage.body}</div>
            </div>

            <AttachmentList items={activeMessage.attachments || []} />

            <div className="zy-card-3d p-[18px] mb-4">
              <h2 className="text-base font-semibold text-text mb-3">Delivery Timeline</h2>
              <div className="border-l-2 border-line pl-4 ml-1 space-y-3">
                <div className="relative text-[13px] text-text">
                  Accepted by Zyphon from <b>{activeMessage.app}</b>
                </div>
                {activeMessage.att.map((a, i) => (
                  <div
                    key={i}
                    className={`relative text-[13px] ${a.ok ? 'text-ok' : 'text-danger'}`}
                  >
                    {a.ok ? (
                      <>
                        Routed via <b>{a.p}</b> successfully
                      </>
                    ) : (
                      <>
                        <b>{a.p}</b> failed: {a.e || 'error'}
                      </>
                    )}
                  </div>
                ))}
              </div>
            </div>

            <div className="text-muted text-xs font-mono">Message ID: {activeMessage.id}</div>
          </aside>
        </>
      )}

      {/* Compose Modal */}
      {showCompose && (
        <div className="fixed inset-0 bg-overlay z-50 flex items-center justify-center p-4">
          <div className="zy-card-3d bg-surface w-[min(520px,94vw)] p-6 max-h-[92vh] overflow-y-auto">
            <h2 className="text-lg font-bold text-text m-0 mb-1">Dispatch Message</h2>
            <p className="text-muted text-xs mb-4">
              Tests the connected provider for the selected channel. App attribution comes from
              provider bindings automatically.
            </p>
            <form onSubmit={handleComposeSend} className="space-y-3">
              <div>
                <label className="block text-xs font-semibold uppercase text-muted mb-1">
                  Channel
                </label>
                <div className="grid grid-cols-3 gap-2">
                  {(['email', 'sms', 'whatsapp'] as ChannelId[]).map((ch) => (
                    <button
                      key={ch}
                      type="button"
                      onClick={() => {
                        setComposeChannel(ch);
                        setComposeTemplateId('');
                        setComposeVars({});
                      }}
                      className={`py-2 px-3 rounded-[var(--r)] border text-xs font-semibold cursor-pointer ${
                        composeChannel === ch
                          ? 'border-accent bg-accent-soft text-text'
                          : 'border-line bg-bg text-muted'
                      }`}
                    >
                      {CHANNELS[ch].name}
                    </button>
                  ))}
                </div>
              </div>
              <div>
                <label className="block text-xs font-semibold uppercase text-muted mb-1">
                  Template (Optional)
                </label>
                <Select
                  value={composeTemplateId}
                  onChange={(e) => handleSelectComposeTemplate(e.target.value)}
                >
                  <option value="">Custom message (no template)</option>
                  {allTemplates
                    .filter((t) => t.channel === composeChannel)
                    .map((t) => (
                      <option key={t.id} value={t.id}>
                        {t.name} ({t.id})
                      </option>
                    ))}
                </Select>
              </div>
              {Object.keys(composeVars).length > 0 && (
                <div className="p-3 rounded-[var(--r)] border border-line bg-bg space-y-2">
                  <div className="text-[11px] font-semibold uppercase tracking-wider text-muted">
                    Template Variables
                  </div>
                  <div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
                    {Object.keys(composeVars).map((varKey) => (
                      <label key={varKey} className="block text-xs text-muted">
                        {`{{${varKey}}}`}
                        <Input
                          className="mt-1"
                          placeholder={`Value for ${varKey}`}
                          value={composeVars[varKey] || ''}
                          onChange={(e) =>
                            setComposeVars((prev) => ({ ...prev, [varKey]: e.target.value }))
                          }
                        />
                      </label>
                    ))}
                  </div>
                </div>
              )}
              <div>
                <label className="block text-xs font-semibold uppercase text-muted mb-1">
                  Recipient ({composeChannel === 'email' ? 'Email' : 'Phone +91...'})
                </label>
                <Input
                  value={composeTo}
                  onChange={(e) => setComposeTo(e.target.value)}
                  placeholder={
                    composeChannel === 'email' ? 'user@domain.com' : '+919876543210'
                  }
                  autoFocus
                />
              </div>
              {composeChannel === 'email' && (
                <div>
                  <label className="block text-xs font-semibold uppercase text-muted mb-1">
                    Subject
                  </label>
                  <Input
                    value={composeSubject}
                    onChange={(e) => setComposeSubject(e.target.value)}
                  />
                </div>
              )}
              <div>
                <label className="block text-xs font-semibold uppercase text-muted mb-1">
                  Message Content
                </label>
                <textarea
                  rows={3}
                  value={composeBody}
                  onChange={(e) => setComposeBody(e.target.value)}
                  className="w-full bg-bg border border-line rounded-[var(--r)] px-3 py-2 text-text text-sm focus:border-accent focus:outline-none"
                />
              </div>
              <div className="flex justify-end gap-2 pt-2">
                <Button type="button" variant="ghost" onClick={() => setShowCompose(false)}>
                  Cancel
                </Button>
                <Button type="submit" variant="primary" disabled={composeSending}>
                  {composeSending ? 'Dispatching…' : 'Send Message'}
                </Button>
              </div>
            </form>
          </div>
        </div>
      )}
    </div>
  );
}
