"use client";

import { useEffect, useRef, useState } from "react";
import { useRouter } from "next/navigation";
import toast from "react-hot-toast";

import DashboardSidebar from "@/app/components/astrologer/DashboardSidebar";
import NotificationBell from "@/app/components/notifications/NotificationBell";
import {
  getConsultationRequests,
  getAstrologerActiveConsultation,
  acceptConsultation,
  rejectConsultation,
  getAstrologerWaitlist,
  removeAstrologerWaitlistEntry,
  AstrologerWaitlistEntry,
  ConsultationRequest,
} from "@/app/lib/astrologer";

// Confirmed live (Consultation API Handbook): poll every 3-5s while
// online — expired rows are closed on read, so the queue never offers
// something that can no longer be accepted. The push is the fast
// path; this poll is not optional (a 60s ring can't depend on
// best-effort FCM). The astrologer's own /active is read-only (never
// bills/closes a session as a side effect), so it's safe on the same
// interval.
const POLL_MS = 4000;

type OrdersTab = "REQUEST" | "WAITING" | "QUEUE" | "CHAT" | "CALL";
type MediumFilter = "ALL" | "CHAT" | "AUDIO";

function initials(name?: string) {
  return (
    (name || "?")
      .trim()
      .split(/\s+/)
      .slice(0, 2)
      .map((part) => part.charAt(0).toUpperCase())
      .join("") || "?"
  );
}

export default function AstrologerOrdersPage() {
  const router = useRouter();
  const [checked, setChecked] = useState(false);
  const [astrologerToken, setAstrologerToken] = useState<string | null>(null);
  const tokenRef = useRef<string | null>(null);

  const [activeTab, setActiveTab] = useState<OrdersTab>("REQUEST");
  const [mediumFilter, setMediumFilter] = useState<MediumFilter>("ALL");

  const [items, setItems] = useState<ConsultationRequest[]>([]);
  const [itemSeconds, setItemSeconds] = useState<Record<number, number>>({});
  const [actingId, setActingId] = useState<number | null>(null);

  const [activeSession, setActiveSession] = useState<any | null>(null);

  // Customers queued for this astrologer (WAITING / NOTIFIED /
  // CONNECTING) — distinct from "Waiting", which is the one accepted
  // session waiting for its customer to join.
  const [waitlist, setWaitlist] = useState<AstrologerWaitlistEntry[]>([]);
  const [removingQueueId, setRemovingQueueId] = useState<number | null>(null);

  // The mockup's "Incoming call" full-screen sheet (matches the
  // handbook's own description of CONSULTATION_REQUEST: "full-screen
  // incoming sheet, over the lock screen"). Declining here only
  // dismisses the sheet — it does NOT call /reject — so the request
  // stays in the list underneath, matching the sheet's own copy.
  const [alertItem, setAlertItem] = useState<ConsultationRequest | null>(null);
  const seenIdsRef = useRef<Set<number>>(new Set());
  const dismissedIdsRef = useRef<Set<number>>(new Set());

  useEffect(() => {
    const token = localStorage.getItem("astrologerToken");

    if (!token) {
      router.replace("/astrologer/signin");
      return;
    }

    tokenRef.current = token;
    setAstrologerToken(token);
    setChecked(true);
  }, [router]);

  useEffect(() => {
    if (!checked) return;

    let cancelled = false;

    const poll = async () => {
      const token = tokenRef.current;
      if (!token) return;

      // allSettled, not all — getConsultationRequests()/
      // getAstrologerActiveConsultation() reject (axios throws on any
      // non-2xx) rather than resolving with success:false, so Promise.all
      // would let one endpoint's failure silently kill the other's
      // result on every poll.
      const [requestsResult, activeResult, waitlistResult] = await Promise.allSettled([
        getConsultationRequests(token),
        getAstrologerActiveConsultation(token),
        getAstrologerWaitlist(token),
      ]);

      if (cancelled) return;

      if (requestsResult.status === "rejected") {
        console.error("Consultation requests poll failed:", requestsResult.reason);
      }
      if (activeResult.status === "rejected") {
        console.error("Astrologer active-consultation poll failed:", activeResult.reason);
      }

      if (waitlistResult.status === "fulfilled" && waitlistResult.value?.success) {
        setWaitlist(waitlistResult.value.entries);
      }

      const requestsResponse = requestsResult.status === "fulfilled" ? requestsResult.value : null;
      const activeResponse = activeResult.status === "fulfilled" ? activeResult.value : null;

      if (
        requestsResponse?.success &&
        Array.isArray(requestsResponse.data?.items ?? requestsResponse.items)
      ) {
        const nextItems: ConsultationRequest[] =
          requestsResponse.data?.items ?? requestsResponse.items;

        setItems(nextItems);

        setItemSeconds((previous) => {
          const next = { ...previous };
          nextItems.forEach((item) => {
            if (item.seconds_to_expiry != null) {
              next[item.consultation_id] = Number(item.seconds_to_expiry);
            }
          });
          return next;
        });

        // Full-screen alert only while nothing is already live — an
        // astrologer already on a call/chat can't accept a second one
        // anyway (accept marks them busy server-side).
        //
        // Confirmed live: /astrologer/consultation/active has no
        // has_active field — "nothing active" and "something active"
        // both return status:true with the same message, and the real
        // signal is consultation_id being non-zero (0 + status:"" when
        // empty). has_active was copied from the customer /active
        // shape, which does document it; that assumption never held
        // here.
        const activeData = activeResponse?.data ?? activeResponse;
        const isBusy = activeResponse?.success && !!activeData?.consultation_id;

        if (!isBusy && !alertItem) {
          const fresh = nextItems.find(
            (item) =>
              !seenIdsRef.current.has(item.consultation_id) &&
              !dismissedIdsRef.current.has(item.consultation_id),
          );

          if (fresh) setAlertItem(fresh);
        }

        nextItems.forEach((item) => seenIdsRef.current.add(item.consultation_id));
      }

      if (activeResponse?.success) {
        const data = activeResponse.data ?? activeResponse;
        setActiveSession(data?.consultation_id ? data : null);
      }
    };

    poll();
    const interval = setInterval(poll, POLL_MS);

    return () => {
      cancelled = true;
      clearInterval(interval);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [checked]);

  // Local 1s ticker for every countdown shown on this page — never
  // recompute from a raw timestamp on the device clock (confirmed live
  // elsewhere in this app that drifts badly); count down the server's
  // own seconds_to_expiry instead.
  useEffect(() => {
    const interval = setInterval(() => {
      setItemSeconds((previous) => {
        const next: Record<number, number> = {};
        Object.entries(previous).forEach(([id, seconds]) => {
          next[Number(id)] = Math.max(0, seconds - 1);
        });
        return next;
      });
    }, 1000);

    return () => clearInterval(interval);
  }, []);

  useEffect(() => {
    setItems((previous) =>
      previous.filter((item) => (itemSeconds[item.consultation_id] ?? 1) > 0),
    );
  }, [itemSeconds]);

  const handleAccept = async (item: ConsultationRequest) => {
    const token = tokenRef.current;
    if (!token) return;

    const consultationId = item.consultation_id;

    try {
      setActingId(consultationId);
      setAlertItem(null);
      const response = await acceptConsultation(consultationId, token, item);

      if (!response.success) {
        // Confirmed live: these specific messages are meant to be
        // dismissed silently, not toasted — the request just isn't
        // there anymore.
        const silent = [
          "this consultation is no longer available",
          "you are already in a consultation",
          "the customer no longer has sufficient balance",
        ];

        if (!silent.some((m) => (response.message || "").toLowerCase().includes(m))) {
          toast.error(response.message || "Unable to accept this request.");
        }

        setItems((prev) => prev.filter((i) => i.consultation_id !== consultationId));
        return;
      }

      router.push(`/astrologer/consultation/${consultationId}`);
    } finally {
      setActingId(null);
    }
  };

  const handleReject = async (consultationId: number) => {
    const token = tokenRef.current;
    if (!token) return;

    try {
      setActingId(consultationId);
      await rejectConsultation(consultationId, "Not available right now", token);
      setItems((prev) => prev.filter((i) => i.consultation_id !== consultationId));
    } finally {
      setActingId(null);
    }
  };

  const handleRemoveFromQueue = async (entry: AstrologerWaitlistEntry) => {
    const token = tokenRef.current;
    if (!token) return;

    try {
      setRemovingQueueId(entry.id);
      const response = await removeAstrologerWaitlistEntry(entry.id, token);

      if (!response.success) {
        toast.error(response.message || "Unable to remove this customer.");
        return;
      }

      setWaitlist((prev) => prev.filter((e) => e.id !== entry.id));
    } catch (error: any) {
      toast.error(error?.response?.data?.message || "Unable to remove this customer.");
    } finally {
      setRemovingQueueId(null);
    }
  };

  const dismissAlert = (item: ConsultationRequest) => {
    dismissedIdsRef.current.add(item.consultation_id);
    setAlertItem(null);
  };

  if (!checked) return null;

  const filteredItems = items.filter(
    (item) => mediumFilter === "ALL" || item.medium === mediumFilter,
  );

  const waitingCount = activeSession?.status === "ACCEPTED" ? 1 : 0;
  const chatCount =
    activeSession?.status === "ONGOING" && activeSession?.medium === "CHAT" ? 1 : 0;
  const callCount =
    activeSession?.status === "ONGOING" && activeSession?.medium === "AUDIO" ? 1 : 0;

  const activeSessionId = activeSession?.consultation_id ?? activeSession?.id ?? null;

  const tabs: { key: OrdersTab; label: string; count: number }[] = [
    { key: "REQUEST", label: "Request", count: items.length },
    { key: "WAITING", label: "Waiting", count: waitingCount },
    { key: "QUEUE", label: "Queue", count: waitlist.length },
    { key: "CHAT", label: "Chat", count: chatCount },
    { key: "CALL", label: "Call", count: callCount },
  ];

  return (
    <div className="astrologer-dashboard-shell">
      <DashboardSidebar active="Orders" />

      <main className="astrologer-dashboard-main">
        <div className="astrologer-dashboard-topbar">
          <div className="astrologer-dashboard-name">Orders</div>
          <div className="astrologer-dashboard-actions">
            <NotificationBell
              audience="astrologer"
              token={astrologerToken}
              notificationsHref="/astrologer/notifications"
              dark
            />
          </div>
        </div>

        <div className="orders-tabs">
          {tabs.map((tab) => (
            <button
              key={tab.key}
              type="button"
              className={`orders-tab ${activeTab === tab.key ? "active" : ""}`}
              onClick={() => setActiveTab(tab.key)}
            >
              {tab.label}
              <span className="orders-tab-count">{tab.count}</span>
            </button>
          ))}
        </div>

        {activeTab === "REQUEST" && (
          <>
            <div className="orders-medium-pills">
              <button
                type="button"
                className={`orders-medium-pill ${mediumFilter === "ALL" ? "active" : ""}`}
                onClick={() => setMediumFilter("ALL")}
              >
                All
              </button>
              <button
                type="button"
                className={`orders-medium-pill ${mediumFilter === "CHAT" ? "active" : ""}`}
                onClick={() => setMediumFilter("CHAT")}
              >
                Chat
              </button>
              <button
                type="button"
                className={`orders-medium-pill ${mediumFilter === "AUDIO" ? "active" : ""}`}
                onClick={() => setMediumFilter("AUDIO")}
              >
                Call
              </button>
              <button
                type="button"
                className="orders-medium-pill"
                disabled
                title="Video isn't offered on this app yet"
              >
                Video
              </button>
            </div>

            {filteredItems.length === 0 ? (
              <div className="astrologer-panel card-bg-primary">
                <p className="astrologer-empty-hint mb-0">
                  No pending chat or call requests right now. New requests will
                  show up here as soon as a user reaches out.
                </p>
              </div>
            ) : (
              <div className="waiting-request-list">
                {filteredItems.map((item) => {
                  const seconds =
                    itemSeconds[item.consultation_id] ?? item.seconds_to_expiry ?? 0;
                  const displayName = item.consultee_name || item.user_name || "User";

                  return (
                    <div key={item.consultation_id} className="waiting-request-card">
                      <div className="waiting-request-top">
                        <div className="waiting-user-avatar">{initials(displayName)}</div>

                        <div className="waiting-request-info">
                          <div className="waiting-user-name">{displayName}</div>
                          <div className="waiting-request-topic">
                            <span>{item.medium === "CHAT" ? "💬" : "📞"}</span>
                            {item.medium === "CHAT" ? "Chat consultation" : "Call consultation"}
                          </div>
                          {item.consultee_birth_place && (
                            <div className="waiting-request-time">
                              <span>📍</span>
                              {item.consultee_birth_place}
                            </div>
                          )}
                        </div>

                        <div className={`waiting-expiry ${seconds <= 10 ? "danger" : ""}`}>
                          {seconds}s
                        </div>
                      </div>

                      <div className="waiting-request-meta">
                        {item.is_free_chat ? (
                          <span className="waiting-free-badge">
                            FREE {item.free_minutes ?? 0} min · you earn ₹{item.estimated_earning ?? 0}
                          </span>
                        ) : (
                          <span>
                            ₹{item.rate_per_minute ?? 0}/min · you earn ₹{item.estimated_earning ?? 0}
                          </span>
                        )}
                      </div>

                      <div className="waiting-request-actions">
                        <button
                          type="button"
                          className="waiting-decline-btn"
                          disabled={actingId === item.consultation_id}
                          onClick={() => handleReject(item.consultation_id)}
                        >
                          {actingId === item.consultation_id ? "..." : "Decline"}
                        </button>

                        <button
                          type="button"
                          className="waiting-accept-btn"
                          disabled={actingId === item.consultation_id}
                          onClick={() => handleAccept(item)}
                        >
                          <span>{item.medium === "CHAT" ? "💬" : "📞"}</span>
                          {actingId === item.consultation_id ? "Accepting..." : "Accept"}
                        </button>
                      </div>
                    </div>
                  );
                })}
              </div>
            )}
          </>
        )}

        {activeTab === "WAITING" && (
          <div className="astrologer-panel card-bg-primary">
            {waitingCount === 0 ? (
              <p className="astrologer-empty-hint mb-0">
                No one is waiting right now. Once you accept a request, it'll
                show up here until the customer joins.
              </p>
            ) : (
              <div className="d-flex align-items-center gap-3">
                <div className="waiting-user-avatar">
                  {initials(activeSession?.user_name)}
                </div>
                <div className="flex-fill">
                  <div className="waiting-user-name">{activeSession?.user_name}</div>
                  <div className="terms-text-color small">
                    Waiting for the customer to join · held for{" "}
                    {activeSession?.seconds_to_join_end ?? "--"}s
                  </div>
                </div>
                {activeSessionId && (
                  <button
                    type="button"
                    className="btn btn-warning fw-bold"
                    onClick={() => router.push(`/astrologer/consultation/${activeSessionId}`)}
                  >
                    View
                  </button>
                )}
              </div>
            )}
          </div>
        )}

        {activeTab === "QUEUE" && (
          <div className="astrologer-panel card-bg-primary">
            {waitlist.length === 0 ? (
              <p className="astrologer-empty-hint mb-0">
                No customers are in your waiting queue. When you&apos;re busy,
                customers can join it and you&apos;ll see them here in order.
              </p>
            ) : (
              <div className="d-flex flex-column gap-3">
                {waitlist.map((entry) => (
                  <div key={entry.id} className="d-flex align-items-center gap-3">
                    <div className="waiting-user-avatar">{initials(entry.name)}</div>
                    <div className="flex-fill">
                      <div className="waiting-user-name">{entry.name}</div>
                      <div className="terms-text-color small">
                        {entry.position != null ? `#${entry.position} · ` : ""}
                        {entry.type ? `${entry.type === "CHAT" ? "Chat" : "Call"} · ` : ""}
                        {entry.status === "NOTIFIED"
                          ? "Notified — their turn"
                          : entry.status === "CONNECTING"
                            ? "Connecting now"
                            : "Waiting"}
                      </div>
                    </div>
                    <button
                      type="button"
                      className="waiting-decline-btn"
                      onClick={() => handleRemoveFromQueue(entry)}
                      disabled={removingQueueId === entry.id}
                    >
                      {removingQueueId === entry.id ? "Removing..." : "Remove"}
                    </button>
                  </div>
                ))}
              </div>
            )}
          </div>
        )}

        {(activeTab === "CHAT" || activeTab === "CALL") && (
          <div className="astrologer-panel card-bg-primary">
            {(activeTab === "CHAT" ? chatCount : callCount) === 0 ? (
              <p className="astrologer-empty-hint mb-0">
                No active {activeTab === "CHAT" ? "chats" : "calls"} right now.
                Your account can only run one live session at a time, so this
                fills in the moment you're on one.
              </p>
            ) : (
              <div className="d-flex align-items-center gap-3">
                <div className="waiting-user-avatar">
                  {initials(activeSession?.user_name)}
                </div>
                <div className="flex-fill">
                  <div className="waiting-user-name">{activeSession?.user_name}</div>
                  <div className="terms-text-color small">Ongoing {activeTab.toLowerCase()}</div>
                </div>
                {activeSessionId && (
                  <button
                    type="button"
                    className="btn btn-warning fw-bold"
                    onClick={() => router.push(`/astrologer/consultation/${activeSessionId}`)}
                  >
                    {activeTab === "CHAT" ? "Open chat" : "Open call"}
                  </button>
                )}
              </div>
            )}
          </div>
        )}
      </main>

      {alertItem && (
        <div className="incoming-alert-overlay">
          <span className="incoming-alert-pill">
            {alertItem.medium === "CHAT" ? "Incoming chat" : "Incoming call"}
          </span>

          <div className="incoming-alert-avatar">
            {initials(alertItem.consultee_name || alertItem.user_name)}
          </div>

          <div className="incoming-alert-name">
            {alertItem.consultee_name || alertItem.user_name || "User"}
          </div>

          <div className="incoming-alert-meta">
            {alertItem.medium === "CHAT" ? "Chat consultation" : "Call consultation"}
            {alertItem.rate_per_minute ? ` · ₹${alertItem.rate_per_minute}/min` : ""}
          </div>

          <div className="incoming-alert-countdown">
            Auto-declines in {itemSeconds[alertItem.consultation_id] ?? alertItem.seconds_to_expiry ?? 0}s
          </div>

          <div className="incoming-alert-actions">
            <button
              type="button"
              className="incoming-alert-btn decline"
              onClick={() => dismissAlert(alertItem)}
            >
              <span className="incoming-alert-btn-circle">✕</span>
              Decline
            </button>

            <button
              type="button"
              className="incoming-alert-btn accept"
              onClick={() => handleAccept(alertItem)}
            >
              <span className="incoming-alert-btn-circle">
                {alertItem.medium === "CHAT" ? "💬" : "📞"}
              </span>
              Accept
            </button>
          </div>

          <p className="incoming-alert-note">
            Declining keeps your availability on — the request stays in the
            list below in case you'd rather answer it from there.
          </p>
        </div>
      )}
    </div>
  );
}
