import React, { useState, useCallback } from "react";
import {
  Home,
  RefreshCw,
  TrendingUp,
  Key,
  CalendarDays,
  HelpCircle,
  Lock,
  Calendar,
  CheckCircle2,
  ArrowLeft,
  ArrowRight,
  ExternalLink,
  Video,
  Phone,
  MapPin,
  MessageSquare,
  User,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { resolveBrandVars } from "@/lib/colors";
import { safeWindowOpen } from "@/lib/safe-url";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Field, FieldLabel, FieldError } from "@/components/ui/field";
import {
  ChatWidgetLauncher,
  ChatWidgetHeader,
  ChatWidgetMessage,
  ChatWidgetInputBar,
  type ChatWidgetMessageRole,
} from "@/components/ui/chat-widget-primitives";

/**
 * ChatWidget — WealthX DS (Broker Website Embeddable Chat)
 *
 * Two-screen flow:
 *   Screen 1 — TopicGrid: lead selects a conversation topic
 *   Screen 2 — Chat: AI conversation based on selected topic
 *
 * Exports (atomic order):
 *   ChatWidgetIntakeForm      — Molecule  — Screen 1 contact form
 *   ChatWidgetTopicCard       — Molecule  — Single topic option card
 *   ChatWidgetTopicGrid       — Organism  — Screen 2 topic selection grid
 *   ChatWidgetInteractiveCard — Molecule  — AI-embedded interactive cards
 *   ChatWidgetWindow          — Template  — 3-screen container + localStorage cache
 *   ChatWidget                — Root      — Floating widget with FAB launcher
 *
 * Pure display component for story control. Real API wiring done in the app layer.
 */

// ---------------------------------------------------------------------------
// Shared types
// ---------------------------------------------------------------------------

export interface ChatWidgetUser {
  name: string;
  phone: string;
  email: string;
}

export interface ChatWidgetTopic {
  id: string;
  icon: React.ReactNode;
  label: string;
  description?: string;
}

export interface ChatWidgetChatMessage {
  id: string;
  role: ChatWidgetMessageRole;
  content: string;
  timestamp?: string;
  isStreaming?: boolean;
  /** Optional inline interactive card rendered below the message bubble. */
  interactiveCard?: ChatWidgetInteractiveCardData;
}

export type ChatWidgetScreen = "intake" | "topics" | "chat" | "booking";

// ---------------------------------------------------------------------------
// Default topics
// ---------------------------------------------------------------------------

export const DEFAULT_CHAT_WIDGET_TOPICS: ChatWidgetTopic[] = [
  {
    id: "buy_home",
    icon: <Home className="size-5" />,
    label: "Buy a Home",
    description: "Purchase your first or next property",
  },
  {
    id: "refinance",
    icon: <RefreshCw className="size-5" />,
    label: "Refinance",
    description: "Get a better rate on your current loan",
  },
  {
    id: "investment",
    icon: <TrendingUp className="size-5" />,
    label: "Investment Property",
    description: "Grow your property portfolio",
  },
  {
    id: "first_home_buyer",
    icon: <Key className="size-5" />,
    label: "First Home Buyer",
    description: "First home buyer grants & schemes",
  },
  {
    id: "book_meeting",
    icon: <CalendarDays className="size-5" />,
    label: "Book a Meeting",
    description: "Talk directly with an adviser",
  },
  {
    id: "general_question",
    icon: <HelpCircle className="size-5" />,
    label: "General Question",
    description: "Ask anything about home loans",
  },
];

// ---------------------------------------------------------------------------
// ChatWidgetIntakeForm (Molecule — Screen 1)
// ---------------------------------------------------------------------------

export interface ChatWidgetIntakeFormProps {
  brokerName?: string;
  onSubmit: (user: ChatWidgetUser) => void;
  isSubmitting?: boolean;
  className?: string;
}

export function ChatWidgetIntakeForm({
  brokerName,
  onSubmit,
  isSubmitting,
  className,
}: ChatWidgetIntakeFormProps) {
  const [name, setName] = useState("");
  const [phone, setPhone] = useState("");
  const [email, setEmail] = useState("");
  const [errors, setErrors] = useState<
    Partial<Record<keyof ChatWidgetUser, string>>
  >({});

  const clearError = (field: keyof ChatWidgetUser) =>
    setErrors((prev) => ({ ...prev, [field]: undefined }));

  const validate = (): Partial<Record<keyof ChatWidgetUser, string>> => {
    const e: Partial<Record<keyof ChatWidgetUser, string>> = {};
    if (!name.trim()) e.name = "Name is required";
    if (!phone.trim()) e.phone = "Phone number is required";
    if (!email.trim()) e.email = "Email is required";
    else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email))
      e.email = "Enter a valid email address";
    return e;
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    const errs = validate();
    if (Object.keys(errs).length > 0) {
      setErrors(errs);
      return;
    }
    onSubmit({ name: name.trim(), phone: phone.trim(), email: email.trim() });
  };

  return (
    <div className={cn("flex flex-col gap-5 p-5", className)}>
      <div>
        <p className="text-body-large font-semibold text-foreground">
          {brokerName ? `Hi from ${brokerName}!` : "Hi there!"}
        </p>
        <p className="mt-1 text-body-medium text-muted-foreground">
          To get started, please share your contact details.
        </p>
      </div>

      <form onSubmit={handleSubmit} noValidate className="flex flex-col gap-3">
        <Field>
          <FieldLabel>
            Full Name <span className="text-destructive">*</span>
          </FieldLabel>
          <Input
            value={name}
            onChange={(e) => {
              setName(e.target.value);
              clearError("name");
            }}
            placeholder="Jane Smith"
            disabled={isSubmitting}
            aria-invalid={!!errors.name || undefined}
          />
          {errors.name && <FieldError>{errors.name}</FieldError>}
        </Field>

        <Field>
          <FieldLabel>
            Phone Number <span className="text-destructive">*</span>
          </FieldLabel>
          <Input
            type="tel"
            value={phone}
            onChange={(e) => {
              setPhone(e.target.value);
              clearError("phone");
            }}
            placeholder="0400 000 000"
            disabled={isSubmitting}
            aria-invalid={!!errors.phone || undefined}
          />
          {errors.phone && <FieldError>{errors.phone}</FieldError>}
        </Field>

        <Field>
          <FieldLabel>
            Email Address <span className="text-destructive">*</span>
          </FieldLabel>
          <Input
            type="email"
            value={email}
            onChange={(e) => {
              setEmail(e.target.value);
              clearError("email");
            }}
            placeholder="jane@example.com"
            disabled={isSubmitting}
            aria-invalid={!!errors.email || undefined}
          />
          {errors.email && <FieldError>{errors.email}</FieldError>}
        </Field>

        <Button
          type="submit"
          variant="default"
          className="mt-1 w-full"
          disabled={isSubmitting}
          loading={isSubmitting}
        >
          Start Chat
          <ArrowRight className="size-4" />
        </Button>
      </form>

      <p className="flex items-center justify-center gap-1 text-center text-[11px] text-muted-foreground">
        <Lock className="size-3" />
        Your info is safe with us
      </p>
    </div>
  );
}

// ---------------------------------------------------------------------------
// ChatWidgetTopicCard (Molecule — single topic)
// ---------------------------------------------------------------------------

export interface ChatWidgetTopicCardProps {
  topic: ChatWidgetTopic;
  onClick: (topicId: string) => void;
  className?: string;
}

export function ChatWidgetTopicCard({
  topic,
  onClick,
  className,
}: ChatWidgetTopicCardProps) {
  return (
    <Button
      variant="outline"
      onClick={() => onClick(topic.id)}
      className={cn(
        "h-auto w-full flex-col items-start gap-1.5 whitespace-normal border-border px-3 py-3 text-left",
        "hover:border-primary hover:bg-primary/5",
        className,
      )}
    >
      <span className="text-muted-foreground" aria-hidden="true">
        {topic.icon}
      </span>
      <span className="text-body-medium font-semibold text-foreground">
        {topic.label}
      </span>
      {topic.description && (
        <span className="text-body-small leading-snug text-muted-foreground">
          {topic.description}
        </span>
      )}
    </Button>
  );
}

// ---------------------------------------------------------------------------
// ChatWidgetTopicGrid (Organism — Screen 2)
// ---------------------------------------------------------------------------

export interface ChatWidgetTopicGridProps {
  userName: string;
  topics?: ChatWidgetTopic[];
  onTopicSelect: (topicId: string) => void;
  className?: string;
}

export function ChatWidgetTopicGrid({
  userName,
  topics = DEFAULT_CHAT_WIDGET_TOPICS,
  onTopicSelect,
  className,
}: ChatWidgetTopicGridProps) {
  return (
    <div className={cn("flex flex-col gap-4 p-5", className)}>
      <div>
        <p className="text-body-large font-semibold text-foreground">
          Hi {userName}!
        </p>
        <p className="mt-0.5 text-body-medium text-muted-foreground">
          What would you like to discuss today?
        </p>
      </div>
      <div className="grid grid-cols-2 gap-2">
        {topics.map((topic) => (
          <ChatWidgetTopicCard
            key={topic.id}
            topic={topic}
            onClick={onTopicSelect}
          />
        ))}
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// ChatWidgetInteractiveCard (Molecule — AI-embedded cards)
// ---------------------------------------------------------------------------

export type ChatWidgetInteractiveCardType =
  | "quick-reply"
  | "appointment"
  | "meeting-type"
  | "confirmation";

export type ChatWidgetMeetingTypeId = "video" | "phone" | "in-person";

export interface ChatWidgetMeetingTypeOption {
  id: ChatWidgetMeetingTypeId;
  label: string;
}

export interface ChatWidgetQuickReplyOption {
  id: string;
  label: string;
}

export interface ChatWidgetAppointmentSlot {
  id: string;
  /** Human-readable datetime, e.g. "Mon 28 Apr · 2:00 PM" */
  datetime: string;
  type: "video" | "in-person" | "phone";
}

/** Data shape for an interactive card — no callbacks, safe to embed in message data. */
export interface ChatWidgetInteractiveCardData {
  type: ChatWidgetInteractiveCardType;
  options?: ChatWidgetQuickReplyOption[];
  slots?: ChatWidgetAppointmentSlot[];
  meetingTypes?: ChatWidgetMeetingTypeOption[];
  confirmedSlot?: ChatWidgetAppointmentSlot;
  meetingType?: ChatWidgetMeetingTypeId;
  topic?: string;
  advisorName?: string;
}

export interface ChatWidgetInteractiveCardProps extends ChatWidgetInteractiveCardData {
  onQuickReply?: (optionId: string) => void;
  onSlotSelect?: (slotId: string) => void;
  onMeetingTypeSelect?: (typeId: ChatWidgetMeetingTypeId) => void;
  className?: string;
}

const MEETING_TYPE_LABELS: Record<ChatWidgetMeetingTypeId, string> = {
  video: "Video Call",
  phone: "Phone Call",
  "in-person": "In-Person Meeting",
};

function MeetingTypeIcon({
  id,
  className = "size-4",
}: {
  id: ChatWidgetMeetingTypeId;
  className?: string;
}) {
  const Icon = id === "video" ? Video : id === "phone" ? Phone : MapPin;
  return <Icon className={cn("shrink-0 text-muted-foreground", className)} />;
}

export function ChatWidgetInteractiveCard({
  type,
  options,
  onQuickReply,
  slots,
  onSlotSelect,
  meetingTypes,
  onMeetingTypeSelect,
  confirmedSlot,
  meetingType,
  topic,
  advisorName,
  className,
}: ChatWidgetInteractiveCardProps) {
  if (type === "quick-reply") {
    return (
      <div className={cn("flex flex-wrap gap-2 pt-1", className)}>
        {options?.map((opt) => (
          <Button
            key={opt.id}
            variant="outline-primary"
            size="sm"
            onClick={() => onQuickReply?.(opt.id)}
          >
            {opt.label}
          </Button>
        ))}
      </div>
    );
  }

  if (type === "appointment") {
    return (
      <div
        className={cn(
          "flex flex-col gap-2 border border-border bg-card p-3",
          className,
        )}
      >
        <p className="text-body-small font-semibold text-foreground">
          Choose a time
        </p>
        {slots?.map((slot) => (
          <Button
            key={slot.id}
            variant="outline"
            onClick={() => onSlotSelect?.(slot.id)}
            className="h-auto w-full justify-start gap-2 px-3 py-2 hover:border-primary hover:bg-primary/5"
          >
            <Calendar className="size-4 shrink-0 text-muted-foreground" />
            <span className="text-foreground">{slot.datetime}</span>
          </Button>
        ))}
      </div>
    );
  }

  if (type === "meeting-type") {
    return (
      <div
        className={cn(
          "flex flex-col gap-2 border border-border bg-card p-3",
          className,
        )}
      >
        <p className="text-body-small font-semibold text-foreground">
          How would you prefer to meet?
        </p>
        {meetingTypes?.map((mt) => (
          <Button
            key={mt.id}
            variant="outline"
            onClick={() => onMeetingTypeSelect?.(mt.id)}
            className="h-auto w-full justify-start gap-2 px-3 py-2 hover:border-primary hover:bg-primary/5"
          >
            <MeetingTypeIcon id={mt.id} />
            <span className="text-foreground">{mt.label}</span>
          </Button>
        ))}
      </div>
    );
  }

  if (type === "confirmation") {
    return (
      <div
        className={cn(
          "flex flex-col gap-3 border border-border bg-card p-3",
          className,
        )}
      >
        <div className="flex items-center gap-2">
          <CheckCircle2 className="size-4 shrink-0 text-green-600" />
          <p className="text-body-medium font-semibold text-foreground">
            Appointment Confirmed
          </p>
        </div>
        <div className="flex flex-col gap-1.5 border-t border-border pt-2 text-body-small text-muted-foreground">
          {confirmedSlot && (
            <div className="flex items-center gap-2">
              <Calendar className="size-3.5 shrink-0" />
              <span>{confirmedSlot.datetime}</span>
            </div>
          )}
          {meetingType && (
            <div className="flex items-center gap-2">
              <MeetingTypeIcon id={meetingType} className="size-3.5" />
              <span>{MEETING_TYPE_LABELS[meetingType]}</span>
            </div>
          )}
          {topic && (
            <div className="flex items-center gap-2">
              <MessageSquare className="size-3.5 shrink-0" />
              <span>{topic}</span>
            </div>
          )}
          {advisorName && (
            <div className="flex items-center gap-2">
              <User className="size-3.5 shrink-0" />
              <span>with {advisorName}</span>
            </div>
          )}
        </div>
      </div>
    );
  }

  return null;
}

// ---------------------------------------------------------------------------
// ChatWidgetWindow (Template — 3-screen container)
// ---------------------------------------------------------------------------

export interface ChatWidgetWindowProps {
  isOpen: boolean;
  brokerName?: string;
  /**
   * Solid brand color (hex) — sets `--primary` on the widget so all interactive
   * elements match, plus a contrast-safe `--primary-foreground` so text stays
   * readable on light colors. Omit to inherit the tenant color from ThemeProvider.
   */
  brandColor?: string;
  gradientFrom?: string;
  gradientTo?: string;
  onMinimize?: () => void;
  // Screen 1
  onIntakeSubmit?: (user: ChatWidgetUser) => void;
  isSubmittingIntake?: boolean;
  // Screen 2
  topics?: ChatWidgetTopic[];
  onTopicSelect?: (topicId: string) => void;
  /** External booking URL. When provided and user selects "Book a Meeting", shows a booking screen instead of chat. */
  bookingUrl?: string;
  // Screen 3
  messages?: ChatWidgetChatMessage[];
  inputValue?: string;
  onInputChange?: (value: string) => void;
  onSend?: (value: string) => void;
  isStreaming?: boolean;
  onSlotSelect?: (slotId: string) => void;
  onQuickReply?: (optionId: string) => void;
  onMeetingTypeSelect?: (typeId: ChatWidgetMeetingTypeId) => void;
  /** Override starting screen — used in stories to skip to a specific screen. */
  initialScreen?: ChatWidgetScreen;
  /** Override cached user — used in stories to pre-populate the user. */
  initialUser?: ChatWidgetUser;
  className?: string;
}

export function ChatWidgetWindow({
  isOpen,
  brokerName = "Your Broker",
  brandColor,
  gradientFrom,
  gradientTo,
  onMinimize,
  onIntakeSubmit,
  isSubmittingIntake,
  topics,
  onTopicSelect,
  bookingUrl,
  messages = [],
  inputValue = "",
  onInputChange,
  onSend,
  isStreaming,
  onSlotSelect,
  onQuickReply,
  onMeetingTypeSelect,
  initialScreen,
  initialUser,
  className,
}: ChatWidgetWindowProps) {
  const [screen, setScreen] = useState<ChatWidgetScreen>(
    () => initialScreen ?? "topics",
  );

  const [user, setUser] = useState<ChatWidgetUser | null>(
    () => initialUser ?? null,
  );

  const handleIntakeSubmit = useCallback(
    (data: ChatWidgetUser) => {
      setUser(data);
      setScreen("topics");
      onIntakeSubmit?.(data);
    },
    [onIntakeSubmit],
  );

  const handleTopicSelect = useCallback(
    (topicId: string) => {
      setScreen(topicId === "book_meeting" && bookingUrl ? "booking" : "chat");
      onTopicSelect?.(topicId);
    },
    [onTopicSelect, bookingUrl],
  );

  if (!isOpen) return null;

  const showBackBar = screen === "chat" || screen === "booking";

  return (
    <div
      className={cn(
        "flex h-[600px] w-[360px] flex-col overflow-hidden border border-border bg-background shadow-xl",
        className,
      )}
      style={resolveBrandVars(brandColor) as React.CSSProperties}
    >
      <ChatWidgetHeader
        brokerName={brokerName}
        gradientFrom={gradientFrom}
        gradientTo={gradientTo}
        onMinimize={onMinimize}
      />

      <div className="flex-1 overflow-y-auto" tabIndex={0}>
        {screen === "intake" && (
          <ChatWidgetIntakeForm
            brokerName={brokerName}
            onSubmit={handleIntakeSubmit}
            isSubmitting={isSubmittingIntake}
          />
        )}
        {screen === "topics" && (
          <ChatWidgetTopicGrid
            userName={user?.name ?? "there"}
            topics={topics}
            onTopicSelect={handleTopicSelect}
          />
        )}
        {screen === "chat" && (
          <div className="flex flex-col gap-3 p-4">
            {messages.map((msg) => (
              <React.Fragment key={msg.id}>
                {(msg.content || msg.isStreaming) && (
                  <ChatWidgetMessage
                    role={msg.role}
                    content={msg.content}
                    timestamp={msg.timestamp}
                    isStreaming={msg.isStreaming}
                  />
                )}
                {msg.interactiveCard && (
                  <ChatWidgetInteractiveCard
                    {...msg.interactiveCard}
                    onSlotSelect={onSlotSelect}
                    onQuickReply={onQuickReply}
                    onMeetingTypeSelect={onMeetingTypeSelect}
                  />
                )}
              </React.Fragment>
            ))}
          </div>
        )}
        {screen === "booking" && bookingUrl && (
          <div className="flex flex-col items-center gap-5 px-6 py-10 text-center">
            <div className="flex size-14 items-center justify-center bg-primary/10">
              <CalendarDays className="size-7 text-foreground" />
            </div>
            <div className="flex flex-col gap-1">
              <p className="text-body-large font-semibold text-foreground">
                Book an Appointment
              </p>
              <p className="text-body-medium text-muted-foreground">
                Choose a time that works for you with one of our advisers.
              </p>
            </div>
            <Button
              variant="default"
              className="w-full"
              onClick={() => safeWindowOpen(bookingUrl)}
            >
              Open Booking Page
              <ExternalLink className="size-4" />
            </Button>
          </div>
        )}
      </div>

      {showBackBar && (
        <div className="border-t border-border px-4 py-1.5 text-center">
          <Button variant="ghost" size="sm" onClick={() => setScreen("topics")}>
            <ArrowLeft className="size-3" />
            Change topic
          </Button>
        </div>
      )}
      {screen === "chat" && onInputChange && onSend && (
        <ChatWidgetInputBar
          value={inputValue}
          onChange={onInputChange}
          onSend={onSend}
          disabled={isStreaming}
        />
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// ChatWidget (Root orchestrator)
// ---------------------------------------------------------------------------

export interface ChatWidgetProps {
  brokerName?: string;
  /**
   * Solid brand color (hex) applied to the FAB launcher and the whole window.
   * Omit to inherit the tenant color from ThemeProvider.
   */
  brandColor?: string;
  gradientFrom?: string;
  gradientTo?: string;
  /** ID used to connect to the correct AI agent. */
  agentId?: string;
  /** External booking URL. When provided, "Book a Meeting" shows a direct booking screen instead of chat. */
  bookingUrl?: string;
  position?: "bottom-right" | "bottom-left";
  /** Opens the widget by default — useful for stories. */
  defaultOpen?: boolean;
  /** Callback when a topic is selected. */
  onTopicSelected?: (topicId: string) => void;
  /** Callback when the user sends a message. */
  onMessageSent?: (message: string) => void;
}

export function ChatWidget({
  brokerName = "Your Broker",
  brandColor,
  gradientFrom,
  gradientTo,
  bookingUrl,
  position = "bottom-right",
  defaultOpen = false,
  onTopicSelected,
  onMessageSent,
}: ChatWidgetProps) {
  const [isOpen, setIsOpen] = useState(defaultOpen);
  const [messages, setMessages] = useState<ChatWidgetChatMessage[]>([]);
  const [inputValue, setInputValue] = useState("");

  const handleTopicSelect = useCallback(
    (topicId: string) => {
      if (topicId !== "book_meeting" || !bookingUrl) {
        const topic = DEFAULT_CHAT_WIDGET_TOPICS.find((t) => t.id === topicId);
        if (topic) {
          setMessages([
            {
              id: "welcome",
              role: "bot",
              content: `Great choice! I can help you with ${topic.label.toLowerCase()}. What would you like to know?`,
            },
          ]);
        }
      }
      onTopicSelected?.(topicId);
    },
    [onTopicSelected, bookingUrl],
  );

  const handleSend = useCallback(
    (value: string) => {
      if (!value.trim()) return;
      setMessages((prev) => [
        ...prev,
        { id: `msg-${Date.now()}`, role: "user", content: value },
      ]);
      setInputValue("");
      onMessageSent?.(value);
    },
    [onMessageSent],
  );

  return (
    <div
      className={cn(
        "fixed bottom-6 z-50 flex flex-col items-end gap-3",
        position === "bottom-right" ? "right-6" : "left-6",
      )}
    >
      {isOpen && (
        <ChatWidgetWindow
          isOpen={isOpen}
          brokerName={brokerName}
          brandColor={brandColor}
          gradientFrom={gradientFrom}
          gradientTo={gradientTo}
          bookingUrl={bookingUrl}
          onMinimize={() => setIsOpen(false)}
          messages={messages}
          inputValue={inputValue}
          onInputChange={setInputValue}
          onSend={handleSend}
          onTopicSelect={handleTopicSelect}
        />
      )}
      <ChatWidgetLauncher
        isOpen={isOpen}
        onClick={() => setIsOpen((prev) => !prev)}
        brandColor={brandColor}
      />
    </div>
  );
}
