"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { useLang } from "@/context/LanguageContext";
import { Alert, Button, PageHeader, PageLoader, Select } from "@/components/ui";
import { api, useApi } from "@/lib/client";
import { cn, formatDateTime } from "@/lib/utils";
import { IconMail, IconPlus, IconSend } from "@/components/icons";

interface Thread {
  kind: "STUDENT" | "ADMISSION";
  id: number;
  name: string;
  nameBn: string | null;
  photoUrl?: string | null;
  subtitle: string;
  unread: number;
  total: number;
  lastMessage: {
    id: number;
    sender: string;
    senderName: string;
    body: string;
    createdAt: string;
  } | null;
}

interface Person {
  kind: "STUDENT" | "ADMISSION";
  id: number;
  name: string;
  nameBn: string | null;
  subtitle: string;
}

interface Message {
  id: number;
  studentId: number | null;
  admissionId: number | null;
  sender: string;
  senderName: string;
  body: string;
  createdAt: string;
}

const MAX_LEN = 2000;

function sameDay(a: string, b: string) {
  return a.slice(0, 10) === b.slice(0, 10);
}

function dayLabel(iso: string, t: ReturnType<typeof useLang>["t"]): string {
  const today = new Date().toISOString().slice(0, 10);
  const yesterday = new Date(Date.now() - 86_400_000).toISOString().slice(0, 10);
  const day = iso.slice(0, 10);
  if (day === today) return t.portal.messagesPage.today;
  if (day === yesterday) return t.portal.messagesPage.yesterday;
  return new Date(iso).toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric" });
}

/** compact relative time for the thread list */
function relativeTime(iso: string): string {
  const diff = Date.now() - new Date(iso).getTime();
  const m = Math.floor(diff / 60_000);
  if (m < 1) return "now";
  if (m < 60) return `${m}m`;
  const h = Math.floor(m / 60);
  if (h < 24) return `${h}h`;
  const d = Math.floor(h / 24);
  if (d < 7) return `${d}d`;
  return new Date(iso).toLocaleDateString("en-GB", { day: "numeric", month: "short" });
}

function Avatar({
  name,
  photoUrl,
  size = 38,
  tone = "rgba(36,105,92,0.14)",
  color = "#24695c",
}: {
  name: string;
  photoUrl?: string | null;
  size?: number;
  tone?: string;
  color?: string;
}) {
  return (
    <span
      className="rounded-circle d-flex align-items-center justify-content-center f-w-800 flex-shrink-0 overflow-hidden"
      style={{ width: size, height: size, background: tone, color, fontSize: Math.max(10, Math.round(size * 0.36)) }}
    >
      {photoUrl ? (
        <img src={photoUrl} alt={name} style={{ width: "100%", height: "100%", objectFit: "cover" }} />
      ) : (
        name.slice(0, 2).toUpperCase()
      )}
    </span>
  );
}

export default function PortalMessagesPage() {
  const { t, locale } = useLang();
  const n = t.portal.messagesPage;
  const { data, loading, reload } = useApi<{
    threads: Thread[];
    people: { students: Person[]; admissions: Person[] };
  }>("/api/portal/messages");

  const [selected, setSelected] = useState<Thread | null>(null);
  const [messages, setMessages] = useState<Message[]>([]);
  const [loadingThread, setLoadingThread] = useState(false);
  const [draft, setDraft] = useState("");
  const [sending, setSending] = useState(false);
  const [search, setSearch] = useState("");
  const [pickerOpen, setPickerOpen] = useState(false);
  const [message, setMessage] = useState<{ type: "success" | "error"; text: string } | null>(null);

  const scrollRef = useRef<HTMLDivElement>(null);

  const threadUrl = useMemo(() => {
    if (!selected) return null;
    return selected.kind === "STUDENT"
      ? `/api/portal/messages?studentId=${selected.id}`
      : `/api/portal/messages?admissionId=${selected.id}`;
  }, [selected]);

  // load the selected thread
  useEffect(() => {
    if (!threadUrl) return;
    setLoadingThread(true);
    api<{ messages: Message[] }>(threadUrl)
      .then((res) => setMessages(res.messages))
      .catch(() => setMessages([]))
      .finally(() => setLoadingThread(false));
  }, [threadUrl]);

  // keep the conversation live — poll for new messages from the other side
  useEffect(() => {
    if (!selected || !threadUrl) return;
    const id = setInterval(() => {
      api<{ messages: Message[] }>(threadUrl)
        .then((res) =>
          setMessages((prev) => (prev.length !== res.messages.length ? res.messages : prev))
        )
        .catch(() => undefined);
      reload();
    }, 8000);
    return () => clearInterval(id);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selected?.kind, selected?.id, threadUrl]);

  // auto-scroll to the newest message
  useEffect(() => {
    const el = scrollRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [messages, loadingThread, selected?.id]);

  function startChat(person: Person) {
    setSelected({
      kind: person.kind,
      id: person.id,
      name: person.name,
      nameBn: person.nameBn,
      photoUrl: null,
      subtitle: person.subtitle,
      unread: 0,
      total: 0,
      lastMessage: null,
    });
    setMessages([]);
    setPickerOpen(false);
  }

  async function send() {
    if (!selected || !draft.trim() || draft.trim().length > MAX_LEN) return;
    setSending(true);
    setMessage(null);
    try {
      const res = await api<{ message: Message }>("/api/portal/messages", {
        method: "POST",
        body: JSON.stringify({
          studentId: selected.kind === "STUDENT" ? selected.id : null,
          admissionId: selected.kind === "ADMISSION" ? selected.id : null,
          body: draft.trim(),
        }),
      });
      setMessages((prev) => [...prev, res.message]);
      setDraft("");
      reload();
    } catch {
      setMessage({ type: "error", text: t.common.tryAgain });
    } finally {
      setSending(false);
    }
  }

  const threads = useMemo(() => {
    const all = data?.threads ?? [];
    const q = search.trim().toLowerCase();
    if (!q) return all;
    return all.filter(
      (th) =>
        th.name.toLowerCase().includes(q) ||
        (th.nameBn ?? "").toLowerCase().includes(q) ||
        (th.lastMessage?.body ?? "").toLowerCase().includes(q)
    );
  }, [data, search]);

  const totalUnread = (data?.threads ?? []).reduce((s, th) => s + th.unread, 0);

  return (
    <div>
      <PageHeader title={n.title} subtitle={n.subtitle} />

      {message && (
        <div className="mb-4">
          <Alert type={message.type} onClose={() => setMessage(null)}>{message.text}</Alert>
        </div>
      )}

      {loading ? (
        <PageLoader text={t.common.loading} />
      ) : (
        <div className="row g-4">
          {/* ---------------- Thread list ---------------- */}
          <div className="col-lg-4">
            <div className="card mb-0" style={{ height: "calc(100vh - 250px)", minHeight: 480 }}>
              <div className="card-header d-flex align-items-center justify-content-between py-3">
                <h5 className="f-w-700 mb-0 d-flex align-items-center gap-2 ems-fs-14">
                  <IconMail className="svg-18" />
                  {n.threads}
                  {totalUnread > 0 && (
                    <span className="badge badge-danger">{totalUnread}</span>
                  )}
                </h5>
                <Button
                  size="sm"
                  variant={pickerOpen ? "secondary" : "primary"}
                  onClick={() => setPickerOpen((v) => !v)}
                  title={n.newChat}
                >
                  <IconPlus className="svg-14" />
                </Button>
              </div>
              <div className="px-3 pt-2 pb-1" style={{ borderBottom: `1px solid ${"#e6edef"}` }}>
                <div className="has-search w-100">
                  <span className="fa fa-search form-control-feedback" />
                  <input
                    className="form-control"
                    placeholder={n.searchPlaceholder}
                    value={search}
                    onChange={(e) => setSearch(e.target.value)}
                  />
                </div>
                {pickerOpen && (
                  <div className="py-2">
                    {(() => {
                      const students = data?.people.students ?? [];
                      const admissions = data?.people.admissions ?? [];
                      if (students.length === 0 && admissions.length === 0) {
                        return <p className="ems-fs-12 text-muted mb-1">{n.peopleEmpty}</p>;
                      }
                      return (
                        <Select onChange={(e) => {
                          const kind = e.target.value.split(":")[0];
                          const id = Number(e.target.value.split(":")[1]);
                          const person =
                            kind === "STUDENT"
                              ? students.find((s) => s.id === id)
                              : admissions.find((a) => a.id === id);
                          if (person) startChat(person);
                        }} defaultValue="">
                          <option value="" disabled>
                            {n.pickPerson}
                          </option>
                          {students.length > 0 && (
                            <optgroup label={t.portal.studentsPage.tabStudents}>
                              {students.map((s) => (
                                <option key={`s${s.id}`} value={`STUDENT:${s.id}`}>
                                  {locale === "bn" && s.nameBn ? s.nameBn : s.name} — {s.subtitle}
                                </option>
                              ))}
                            </optgroup>
                          )}
                          {admissions.length > 0 && (
                            <optgroup label={t.portal.admissionsPage.title}>
                              {admissions.map((a) => (
                                <option key={`a${a.id}`} value={`ADMISSION:${a.id}`}>
                                  {a.name} — {a.subtitle}
                                </option>
                              ))}
                            </optgroup>
                          )}
                        </Select>
                      );
                    })()}
                  </div>
                )}
              </div>
              <div className="overflow-auto flex-grow-1" style={{ minHeight: 0 }}>
                {threads.length === 0 && (
                  <p className="text-muted text-center py-4 mb-0 ems-fs-13">{n.noThreads}</p>
                )}
                {threads.map((th) => {
                  const active = selected?.kind === th.kind && selected?.id === th.id;
                  return (
                    <button
                      key={`${th.kind}-${th.id}`}
                      type="button"
                      className={cn(
                        "d-flex w-100 text-start gap-2 p-3 bg-transparent border-0",
                        active ? "ems-chat-thread-active" : "ems-chat-thread"
                      )}
                      onClick={() => setSelected(th)}
                    >
                      <Avatar name={th.name} photoUrl={th.photoUrl} />
                      <div className="flex-fill" style={{ minWidth: 0 }}>
                        <div className="d-flex justify-content-between align-items-center gap-2">
                          <h6 className="mb-0 f-w-700 ems-fs-13 text-truncate">
                            {locale === "bn" && th.nameBn ? th.nameBn : th.name}
                          </h6>
                          {th.unread > 0 ? (
                            <span className="badge badge-danger flex-shrink-0">{th.unread}</span>
                          ) : (
                            <small className="text-muted flex-shrink-0 ems-fs-11">
                              {th.lastMessage ? relativeTime(th.lastMessage.createdAt) : ""}
                            </small>
                          )}
                        </div>
                        <div className="d-flex align-items-center gap-1 mt-1">
                          <span className={`badge ${th.kind === "ADMISSION" ? "badge-warning" : "badge-info"} ems-fs-10`}>
                            {th.kind === "ADMISSION" ? n.applicant : n.studentLabel}
                          </span>
                          <p className="mb-0 ems-fs-12 text-muted text-truncate" style={{ minWidth: 0 }}>
                            {th.lastMessage?.sender === "INSTITUTION" && (
                              <b>{n.you}: </b>
                            )}
                            {th.lastMessage?.body}
                          </p>
                        </div>
                      </div>
                    </button>
                  );
                })}
              </div>
            </div>
          </div>

          {/* ---------------- Chat pane ---------------- */}
          <div className="col-lg-8">
            <div className="card mb-0 d-flex flex-column" style={{ height: "calc(100vh - 250px)", minHeight: 480 }}>
              {!selected ? (
                <div className="card-body d-flex flex-column align-items-center justify-content-center text-center">
                  <span className="ems-stat-icon teal mb-3" style={{ width: 56, height: 56 }}>
                    <IconMail />
                  </span>
                  <p className="text-muted mb-0">{n.selectThread}</p>
                </div>
              ) : (
                <>
                  {/* header */}
                  <div
                    className="d-flex align-items-center gap-2 p-3 flex-shrink-0"
                    style={{ borderBottom: `1px solid ${"#e6edef"}` }}
                  >
                    <Avatar name={selected.name} photoUrl={selected.photoUrl} />
                    <div className="flex-fill" style={{ minWidth: 0 }}>
                      <h6 className="mb-0 f-w-700">
                        {locale === "bn" && selected.nameBn ? selected.nameBn : selected.name}
                      </h6>
                      <p className="mb-0 ems-fs-11 text-muted">
                        {selected.kind === "ADMISSION" ? n.applicant : selected.subtitle}
                        {selected.total > 0 && ` · ${selected.total} ${n.messagesCount}`}
                      </p>
                    </div>
                  </div>

                  {/* messages */}
                  <div
                    ref={scrollRef}
                    className="flex-fill p-3"
                    style={{ overflowY: "auto", background: "#f8faf9", minHeight: 0 }}
                  >
                    {loadingThread ? (
                      <div className="text-center py-4">
                        <span className="spinner-border text-primary" role="status" />
                      </div>
                    ) : messages.length === 0 ? (
                      <p className="text-muted text-center py-4 mb-0 ems-fs-13">{n.noThreads}</p>
                    ) : (
                      messages.map((m, i) => {
                        const own = m.sender === "INSTITUTION";
                        const newDay = i === 0 || !sameDay(messages[i - 1].createdAt, m.createdAt);
                        return (
                          <div key={m.id}>
                            {newDay && (
                              <div className="text-center my-3">
                                <span
                                  className="badge px-3 py-1 ems-fs-11"
                                  style={{ background: "#e6edef", color: "#5f6f6a", fontWeight: 700 }}
                                >
                                  {dayLabel(m.createdAt, t)}
                                </span>
                              </div>
                            )}
                            <div className={`d-flex mb-2 gap-2 ${own ? "justify-content-end" : ""}`}>
                              {!own && (
                                <Avatar name={m.senderName} size={28} tone="rgba(226,198,54,0.25)" color="#8a6d1a" />
                              )}
                              <div
                                className="px-3 py-2"
                                style={{
                                  maxWidth: "72%",
                                  background: own ? "#dcf0e9" : "#fff",
                                  color: own ? "#173c34" : "#242934",
                                  border: own ? "1px solid #c2e2d7" : `1px solid ${"#e6edef"}`,
                                  borderRadius: 14,
                                  borderBottomRightRadius: own ? 4 : 14,
                                  borderBottomLeftRadius: own ? 14 : 4,
                                  boxShadow: "0 1px 2px rgba(28,43,39,0.08)",
                                }}
                              >
                                {!own && (
                                  <p className="mb-1 ems-fs-11 f-w-700" style={{ color: "#24695c" }}>
                                    {m.senderName}
                                  </p>
                                )}
                                <p className="mb-1 ems-fs-13" style={{ wordBreak: "break-word", whiteSpace: "pre-wrap" }}>
                                  {m.body}
                                </p>
                                <p
                                  className="mb-0 ems-fs-10 text-end"
                                  style={{ color: own ? "#5f7a72" : "#9aa7a3" }}
                                  title={formatDateTime(m.createdAt, locale)}
                                >
                                  {new Date(m.createdAt).toLocaleTimeString(locale === "bn" ? "bn-BD" : "en-GB", {
                                    hour: "2-digit",
                                    minute: "2-digit",
                                  })}
                                </p>
                              </div>
                            </div>
                          </div>
                        );
                      })
                    )}
                  </div>

                  {/* composer */}
                  <div className="p-3 flex-shrink-0" style={{ borderTop: `1px solid ${"#e6edef"}` }}>
                    <div className="d-flex gap-2 align-items-end">
                      <div className="flex-fill position-relative">
                        <textarea
                          className="form-control resize-none"
                          rows={1}
                          style={{
                            paddingRight: 64,
                            resize: "none",
                            height: 44,
                            minHeight: 44,
                            maxHeight: 120,
                          }}
                          placeholder={n.typePlaceholder}
                          maxLength={MAX_LEN}
                          value={draft}
                          onChange={(e) => setDraft(e.target.value)}
                          onKeyDown={(e) => {
                            if (e.key === "Enter" && !e.shiftKey) {
                              e.preventDefault();
                              send();
                            }
                          }}
                        />
                        <span
                          className="position-absolute ems-fs-10 text-muted"
                          style={{ right: 10, bottom: 8, pointerEvents: "none" }}
                        >
                          {draft.length}/{MAX_LEN}
                        </span>
                      </div>
                      <Button type="button" loading={sending} disabled={!draft.trim()} onClick={send} title={n.enterHint}>
                        <IconSend className="svg-16" />
                        <span className="ms-1 d-none d-md-inline">{n.send}</span>
                      </Button>
                    </div>
                  </div>
                </>
              )}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
