import { useEffect, useMemo, useRef, useState } from "react";
import { createFileRoute, Link } from "@tanstack/react-router";
import { useMutation } from "@tanstack/react-query";
import { Loader2, Send, MessageSquare, Sparkles, RefreshCw, Plus, Check, ArrowRight, X } from "lucide-react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { AppShell } from "@/components/AppShell";
import { PortfolioPrompt } from "@/components/PortfolioPrompt";
import { PageHeader } from "@/components/PageHeader";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { useBriefing } from "@/hooks/useBriefing";
import { useSettings } from "@/hooks/useSettings";
import { askAria, type ChatMessage } from "@/lib/chat.functions";
import { authHeaders } from "@/lib/authHeaders";
import { addCustomAction, useCustomActions, type CustomAction } from "@/lib/customActions";
import { useDismissedActions } from "@/lib/dismissedActions";
import { toast } from "sonner";

export const Route = createFileRoute("/ask")({
  head: () => ({
    meta: [
      { title: "Chat — Your hotel copilot | The Daily Ledger" },
      {
        name: "description",
        content:
          "Chat with your on-site AI copilot about your property, your competitors, Malaysia hotel industry trends, and our eZee & Yanolja Cloud Solution ecosystem.",
      },
      { property: "og:title", content: "Chat — Your hotel copilot" },
      {
        property: "og:description",
        content:
          "Ask anything about your property, competitors, Malaysia hospitality trends, and our products.",
      },
    ],
  }),
  component: AskPage,
});

const SUGGESTIONS_EN = [
  "How is my property performing this week?",
  "Who are my closest competitors and what are they doing?",
  "What's happening in Peninsula Malaysia hotel demand right now?",
  "Suggest 3 revenue actions I can take this week.",
  "How does eZeeM e-Invoice handle LHDN MyInvois compliance?",
];
const SUGGESTIONS_ZH = [
  "本周我的酒店表现如何？",
  "我最近的竞争对手是谁？他们在做什么？",
  "马来西亚半岛酒店需求目前有什么动向？",
  "请给我本周可执行的 3 个增收动作。",
  "eZeeM e-Invoice 如何处理马来西亚 LHDN MyInvois 合规？",
];

function AskPage() {
  const { hotel, isHotelLoading, isBriefingLoading, refresh } = useBriefing({ skipBriefing: true });
  const { lang } = useSettings();
  const [messages, setMessages] = useState<ChatMessage[]>([]);
  const [input, setInput] = useState("");
  const scrollerRef = useRef<HTMLDivElement | null>(null);

  const mutation = useMutation({
    mutationFn: async (next: ChatMessage[]) => {
      const res = await askAria({
        data: {
          messages: next,
          language: lang,
          hotel: hotel
            ? {
                hotel_name: hotel.hotel_name,
                location: hotel.location,
                rooms: hotel.rooms,
                star_rating: hotel.star_rating ?? null,
                segment: hotel.segment ?? null,
                property_type: hotel.property_type ?? null,
                radius_km: hotel.radius_km,
                currency: hotel.currency,
                ezee_products: hotel.ezee_products ?? [],
              }
            : null,
        },
        headers: await authHeaders(),
      });
      return res.reply;
    },
    onSuccess: (reply) => {
      setMessages((prev) => [...prev, { role: "assistant", content: reply }]);
    },
    onError: (err: Error) => {
      setMessages((prev) => [
        ...prev,
        {
          role: "assistant",
          content:
            (lang === "zh" ? "抱歉，出现错误：" : "Sorry, something went wrong: ") +
            err.message,
        },
      ]);
    },
  });

  useEffect(() => {
    scrollerRef.current?.scrollTo({
      top: scrollerRef.current.scrollHeight,
      behavior: "smooth",
    });
  }, [messages, mutation.isPending]);

  function send(text: string) {
    const trimmed = text.trim();
    if (!trimmed || mutation.isPending) return;
    const next: ChatMessage[] = [...messages, { role: "user", content: trimmed }];
    setMessages(next);
    setInput("");
    mutation.mutate(next);
  }

  function reset() {
    setMessages([]);
    setInput("");
  }

  if (isHotelLoading) {
    return (
      <div className="flex min-h-dvh items-center justify-center">
        <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
      </div>
    );
  }
  if (!hotel) return <PortfolioPrompt pageTitle={lang === "zh" ? "聊天" : "Chat"} />;

  const suggestions = lang === "zh" ? SUGGESTIONS_ZH : SUGGESTIONS_EN;

  return (
    <AppShell hotel={hotel} isLoading={isBriefingLoading} onRefresh={refresh}>
      <PageHeader
        eyebrow={lang === "zh" ? "聊天" : "Chat"}
        title={lang === "zh" ? "您的酒店智能助手" : "Your hotel copilot"}
        subtitle={
          lang === "zh"
            ? "向 Aria 询问任何关于您酒店、竞争对手、马来西亚（半岛地区为主）酒店行业动态，以及我们产品生态的问题。"
            : "Ask Aria anything about your property, your competitors, Malaysia hotel industry news (focused on Peninsula Malaysia), and our product ecosystem."
        }
      />

      <div className="flex h-[calc(100dvh-26rem)] min-h-[360px] flex-col gap-4 rounded-2xl border bg-card/60 p-4 shadow-[var(--shadow-elegant)] backdrop-blur-sm sm:h-[calc(100dvh-20rem)] sm:p-5 lg:h-[calc(100dvh-14rem)]">
        <div ref={scrollerRef} className="flex-1 space-y-4 overflow-y-auto pr-1">
          {messages.length === 0 ? (
            <div className="flex h-full flex-col items-center justify-center gap-4 text-center">
              <div className="flex h-12 w-12 items-center justify-center rounded-full bg-brand-soft text-brand">
                <Sparkles className="h-5 w-5" />
              </div>
              <div className="max-w-md text-sm text-muted-foreground">
                {lang === "zh"
                  ? "您好！我是 Aria，您的酒店智能助手。可以问我关于您的酒店、竞争对手、马来西亚酒店行业，或我们产品生态的任何问题。"
                  : "Hi! I'm Aria, your hotel copilot. Ask me anything about your property, competitors, Malaysia's hotel industry, or our product ecosystem."}
              </div>
              <div className="flex flex-wrap justify-center gap-2">
                {suggestions.map((s) => (
                  <button
                    key={s}
                    onClick={() => send(s)}
                    className="rounded-full border bg-background px-3 py-1.5 text-xs text-foreground transition hover:bg-brand-soft/40"
                  >
                    {s}
                  </button>
                ))}
              </div>
            </div>
          ) : (
            messages.map((m, i) => (
              <div
                key={i}
                className={`flex ${m.role === "user" ? "justify-end" : "justify-start"}`}
              >
                <div
                  className={`max-w-[85%] rounded-2xl px-4 py-2.5 text-sm shadow-sm ${
                    m.role === "user"
                      ? "bg-brand text-primary-foreground"
                      : "border bg-background text-foreground"
                  }`}
                >
                  {m.role === "assistant" ? (
                    <>
                      <div className="prose prose-sm max-w-none break-words dark:prose-invert prose-p:my-2 prose-ul:my-2 prose-headings:mb-2 prose-headings:mt-3 prose-a:text-brand">
                        <ReactMarkdown remarkPlugins={[remarkGfm]}>{m.content}</ReactMarkdown>
                      </div>
                      <ChatActionExtractor content={m.content} lang={lang} />
                    </>
                  ) : (
                    <p className="whitespace-pre-wrap">{m.content}</p>
                  )}
                </div>
              </div>
            ))
          )}
          {mutation.isPending ? (
            <div className="flex justify-start">
              <div className="flex items-center gap-2 rounded-2xl border bg-background px-4 py-2.5 text-sm text-muted-foreground">
                <Loader2 className="h-4 w-4 animate-spin" />
                <span>{lang === "zh" ? "Aria 正在思考…" : "Aria is thinking…"}</span>
              </div>
            </div>
          ) : null}
        </div>

        <form
          onSubmit={(e) => {
            e.preventDefault();
            send(input);
          }}
          className="flex items-end gap-2 border-t pt-3"
        >
          <Textarea
            value={input}
            onChange={(e) => setInput(e.target.value)}
            onKeyDown={(e) => {
              if (e.key === "Enter" && !e.shiftKey) {
                e.preventDefault();
                send(input);
              }
            }}
            rows={1}
            placeholder={
              lang === "zh"
                ? "向 Aria 提问…（Enter 发送 / Shift+Enter 换行）"
                : "Ask Aria anything… (Enter to send, Shift+Enter for newline)"
            }
            className="min-h-[44px] resize-none"
          />
          <Button type="submit" size="icon" disabled={mutation.isPending || !input.trim()}>
            {mutation.isPending ? (
              <Loader2 className="h-4 w-4 animate-spin" />
            ) : (
              <Send className="h-4 w-4" />
            )}
          </Button>
          {messages.length > 0 ? (
            <Button
              type="button"
              size="icon"
              variant="ghost"
              onClick={reset}
              aria-label={lang === "zh" ? "重置对话" : "Reset conversation"}
            >
              <RefreshCw className="h-4 w-4" />
            </Button>
          ) : null}
        </form>

        <div className="flex items-center gap-1.5 text-[11px] text-muted-foreground">
          <MessageSquare className="h-3 w-3" />
          {lang === "zh"
            ? "答案结合您的酒店资料、马来西亚（半岛）行业动态，以及我们的产品知识库。"
            : "Answers blend your property profile, Peninsula Malaysia industry context, and our product knowledge base."}
        </div>
      </div>
    </AppShell>
  );
}

// Extract bullet/numbered suggestions from an AI reply and offer to add them
// to the user's Action Plan. We capture surrounding context so the saved
// action has a real "why", not just a one-liner duplicated as title.
type ExtractedSuggestion = {
  raw: string;
  title: string;
  why: string;
  category: CustomAction["category"];
  urgency: CustomAction["urgency"];
};

function inferCategory(text: string): CustomAction["category"] {
  const t = text.toLowerCase();
  if (/\b(price|pricing|adr|rate|revpar|discount|tariff|yield)\b/.test(t)) return "Pricing";
  if (/\b(ota|booking\.com|agoda|expedia|channel|distribution|allotment|inventory)\b/.test(t)) return "Distribution";
  if (/\b(guest|review|loyalty|repeat|experience|service|feedback|hospitality)\b/.test(t)) return "Guest";
  if (/\b(staff|sop|operation|housekeeping|maintenance|workflow|process|training)\b/.test(t)) return "Operations";
  return "Marketing";
}

function inferUrgency(text: string): CustomAction["urgency"] {
  const t = text.toLowerCase();
  if (/\b(today|now|immediately|asap|urgent|tonight)\b/.test(t)) return "today";
  if (/\b(this month|next month|long[- ]term|quarter|strategic)\b/.test(t)) return "this_month";
  return "this_week";
}

function extractSuggestions(content: string): ExtractedSuggestion[] {
  const lines = content.split(/\r?\n/);
  const out: ExtractedSuggestion[] = [];
  // Track the most recent non-bullet line (heading or intro paragraph) so
  // we can attach it as additional rationale on the saved action.
  let lastContext = "";
  for (let i = 0; i < lines.length; i++) {
    const raw = lines[i].trim();
    const bullet = raw.match(/^(?:[-*•]|\d+[.)])\s+(.+)$/);
    if (!bullet) {
      if (/^#{1,6}\s/.test(raw)) lastContext = raw.replace(/^#{1,6}\s+/, "").trim();
      else if (raw.length > 0) lastContext = raw.replace(/[*_`]/g, "").trim();
      continue;
    }
    let text = bullet[1]
      .replace(/^\*\*([^*]+)\*\*\s*[:：]\s*/, "$1: ")
      .replace(/^\*\*([^*]+)\*\*\s*/, "$1 — ")
      .replace(/\*\*/g, "")
      .trim();
    if (text.length < 12 || text.length > 600) continue;

    // Look ahead for indented sub-bullets that elaborate this item.
    const sub: string[] = [];
    for (let j = i + 1; j < lines.length; j++) {
      const next = lines[j];
      if (/^\s{2,}(?:[-*•]|\d+[.)])\s+/.test(next)) {
        sub.push(next.trim().replace(/^(?:[-*•]|\d+[.)])\s+/, "").replace(/\*\*/g, ""));
      } else if (next.trim() === "") continue;
      else break;
    }

    // Split title vs detail on first ": ", " — ", or " - "
    let title = text;
    let detail = "";
    const sep = text.match(/^(.{6,90}?)(?:\s*[:：]\s+|\s+[—–-]\s+)(.+)$/);
    if (sep) {
      title = sep[1].trim().replace(/[.;,]+$/, "");
      detail = sep[2].trim();
    } else if (text.length > 90) {
      const dot = text.search(/[.!?]\s/);
      if (dot > 20 && dot < 100) {
        title = text.slice(0, dot).trim();
        detail = text.slice(dot + 1).trim();
      }
    }
    if (title.length > 100) title = title.slice(0, 97) + "…";

    const whyParts = [detail, sub.length ? sub.map((s) => `• ${s}`).join("\n") : "", lastContext]
      .map((s) => s.trim())
      .filter((s) => s && s !== title);
    const why = whyParts.join("\n\n") || text;

    out.push({
      raw: text,
      title,
      why,
      category: inferCategory(`${title} ${why}`),
      urgency: inferUrgency(`${title} ${why}`),
    });
    if (out.length >= 6) break;
  }
  return out;
}

function ChatActionExtractor({ content, lang }: { content: string; lang: "en" | "zh" }) {
  const suggestions = useMemo(() => extractSuggestions(content), [content]);
  const { items } = useCustomActions();
  const dismissed = useDismissedActions();
  const [justAdded, setJustAdded] = useState<Record<string, boolean>>({});
  if (suggestions.length === 0) return null;

  const isAdded = (s: ExtractedSuggestion) =>
    justAdded[s.raw] || items.some((a) => a.title === s.title && a.source_label === "From chat");
  const dismissKey = (s: ExtractedSuggestion) => `chat:${s.raw.slice(0, 80)}`;

  const handleAdd = (s: ExtractedSuggestion) => {
    addCustomAction({
      title: s.title,
      why: s.why,
      category: s.category,
      urgency: s.urgency,
      source_label: "From chat",
    });
    setJustAdded((p) => ({ ...p, [s.raw]: true }));
    toast.success(lang === "zh" ? "已加入行动计划" : "Added to Action Plan");
  };

  const visible = suggestions.filter((s) => !dismissed.has(dismissKey(s)));
  if (visible.length === 0) return null;

  return (
    <div className="mt-3 space-y-1.5 border-t pt-3">
      <div className="mb-1.5 text-[10px] font-medium uppercase tracking-wider text-muted-foreground">
        {lang === "zh" ? "加入行动计划" : "Add to Action Plan"}
      </div>
      {visible.map((s) => {
        const added = isAdded(s);
        return (
          <div key={s.raw} className="flex items-start gap-2">
            <Button
              size="sm"
              variant={added ? "outline" : "secondary"}
              onClick={() => !added && handleAdd(s)}
              disabled={added}
              className="h-7 shrink-0 gap-1 px-2 text-[11px]"
            >
              {added ? <Check className="h-3 w-3" /> : <Plus className="h-3 w-3" />}
              {added ? (lang === "zh" ? "已加入" : "Added") : (lang === "zh" ? "加入" : "Add")}
            </Button>
            <div className="flex-1 space-y-0.5">
              <div className="text-xs font-medium leading-snug text-foreground">{s.title}</div>
              {s.why && s.why !== s.title ? (
                <div className="text-[11px] leading-relaxed text-muted-foreground line-clamp-2">{s.why}</div>
              ) : null}
            </div>
            <Button
              size="sm"
              variant="ghost"
              className="h-7 shrink-0 gap-1 px-2 text-[11px] text-muted-foreground"
              onClick={() => dismissed.dismiss(dismissKey(s))}
              title={lang === "zh" ? "忽略" : "Dismiss"}
            >
              <X className="h-3 w-3" />
            </Button>
          </div>
        );
      })}
      <div className="pt-1">
        <Link to="/actions" className="inline-flex items-center gap-1 text-[11px] text-brand hover:underline">
          {lang === "zh" ? "前往行动计划" : "Open Action Plan"} <ArrowRight className="h-3 w-3" />
        </Link>
      </div>
    </div>
  );
}
