import { useAuthSlice } from "@/app/providers";
import { eventQueries } from "@/entities/event";
import type { Order } from "@/entities/order";
import type { Socials } from "@/entities/user";
import { useSendTx } from "@/shared/hooks/sendTx";
import { formatUsdt } from "@/shared/lib/money/usdt";
import { pluralTickets } from "@/shared/lib/pluralDays";
import { getCurrencySymbol } from "@/shared/lib/web3";
import { Loader } from "@/shared/ui/Loader";
import { ResultDialog } from "@/shared/ui/ResultDialog";
import { Button } from "@/shared/ui/button";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useCallback, useEffect, useState } from "react";
import { useNavigate } from "react-router";
import { useActiveAccount } from "thirdweb/react";
import { purchase } from "../api/purchase";

export type ConfirmPaymentProps = {
  order: Order;
  referralAddress?: string;
  onStageChange?: (stage: "checkout" | "pending" | "success" | "error") => void;
};

export const ConfirmPayment: React.FC<ConfirmPaymentProps> = ({
  order,
  referralAddress,
  onStageChange,
}) => {
  const navigate = useNavigate();
  const account = useActiveAccount();
  const { user, startTicketPoll } = useAuthSlice();
  const { sendTx, data: txHash, error } = useSendTx();
  const [hasStartedPayment, setHasStartedPayment] = useState(false);
  const [isSuccess, setIsSuccess] = useState(false);
  const [redirectEventId, setRedirectEventId] = useState<number | null>(null);
  const [createEventTxHash, setCreateEventTxHash] = useState<string | null>(
    null,
  );
  const queryClient = useQueryClient();

  useEffect(() => {
    setHasStartedPayment(false);
  }, [order.type]);

  const resolveCreatedEventId = useCallback(async () => {
    if (!user || order.type !== "create_event") return null;
    const events = await queryClient.fetchQuery(eventQueries.list());
    if (!events) return null;
    const targetPlaceId = Number(order.event.place);
    const eventsArray = Array.isArray(events) ? events : [];
    const matchedEvent = eventsArray.find(
      (event: {
        creator: { address: string };
        title: string;
        startDateTimestamp: number;
        place: { id: number };
        ticketPrice: string;
        daysAmount: number;
        id?: number;
      }) => {
        return (
          event.creator.address === user.address &&
          event.title === order.event.title &&
          event.startDateTimestamp === order.event.startTimeTimeStamp &&
          event.place.id === targetPlaceId &&
          event.ticketPrice === order.event.ticketPrice &&
          event.daysAmount === order.event.daysAmount
        );
      },
    );
    return matchedEvent?.id ?? null;
  }, [order, queryClient, user]);

  const { mutate, isPending } = useMutation({
    mutationFn: (order: Order) => {
      if (!account || !user) {
        return Promise.reject("Account or user are missing");
      }
      return purchase(
        sendTx,
        account,
        order,
        user.socials[0] as Socials,
        referralAddress,
      );
    },
    onSuccess: async (returnedTxHash: string | undefined) => {
      // Show success modal for all order types
      setIsSuccess(true);
      onStageChange?.("success");

      if (order.type === "buy_ticket") {
        // Ticket becomes visible only after the backend indexer syncs it to DB.
        // Start polling current user until ticket(s) show up (or timeout).
        const boughtCount = order.ticket.allocations.reduce(
          (sum, a) => sum + a.count,
          0,
        );
        const baseline = (user?.tickets ?? []).filter(
          (t) => t.eventId === order.ticket.eventId,
        ).length;
        startTicketPoll({
          eventId: order.ticket.eventId,
          targetCount: baseline + boughtCount,
        });
        setRedirectEventId(order.ticket.eventId);
        return;
      }
      if (order.type === "update_event") {
        setRedirectEventId(order.event.id);
        return;
      }
      if (order.type === "create_event") {
        // Store the txHash for navigation to waiting page
        const txHashToUse = returnedTxHash || (txHash as string | null);
        if (txHashToUse) {
          setCreateEventTxHash(txHashToUse);
        }
        return;
      }
    },
    onError: (e) => {
      setHasStartedPayment(false);
      onStageChange?.("error");
      console.error(e);
    },
  });

  if (!user) return null;
  if (user.socials.length === 0)
    return (
      <div className="flex flex-col items-center gap-2 py-5">
        <p className="text-lg">No socials are provided</p>
        <Button onClick={() => navigate("/socials")}>Set socials</Button>
      </div>
    );

  const handleConfirm = async () => {
    // For create_event, navigate to the waiting page first
    if (order.type === "create_event" && createEventTxHash) {
      navigate(`/txhash/${createEventTxHash}`, { replace: true });
      return;
    }

    let nextRedirectId = redirectEventId;
    if (order.type === "create_event" && nextRedirectId == null) {
      const createdId = await resolveCreatedEventId();
      if (createdId != null) {
        setRedirectEventId(createdId);
        nextRedirectId = createdId;
      }
    }

    if (nextRedirectId != null) {
      queryClient.invalidateQueries({
        queryKey: ["events", "lists", nextRedirectId],
      });
      queryClient.invalidateQueries({
        queryKey: ["events", nextRedirectId, "attendees"],
      });
      navigate(`/events/${nextRedirectId}`, { replace: true });
      return;
    }

    navigate("/", { replace: true });
  };

  const successMessage =
    order.type === "buy_ticket"
      ? "Your will recieve your ticket within several minutes."
      : order.type === "create_event"
        ? "Your event request has been submitted. Click proceed to track the confirmation."
        : "Your order will be published within several minutes.";

  // Calculate total price and ticket count for display
  const { totalPrice, totalTickets } =
    order.type === "buy_ticket"
      ? {
          totalPrice: order.ticket.allocations.reduce((sum, a) => {
            return sum + BigInt(a.count) * a.finalPricePerTicket;
          }, 0n),
          totalTickets: order.ticket.allocations.reduce(
            (sum, a) => sum + a.count,
            0,
          ),
        }
      : { totalPrice: null, totalTickets: null };

  return (
    <article className="card border-primary/30">
      {error && <PaymentFailed cause={error} />}
      {isPending || hasStartedPayment ? (
        <div className="flex flex-col items-center gap-3 py-10">
          <Loader />
          <p className="text-sm text-muted-foreground text-center">
            Processing transaction. Confirm in your wallet if prompted.
          </p>
        </div>
      ) : (
        <div className="flex justify-center py-6">
          <span>
            <Button
              onClick={() => {
                setHasStartedPayment(true);
                onStageChange?.("pending");
                mutate(order);
              }}
              className="mx-auto"
            >
              {error
                ? "Try again"
                : totalPrice !== null
                  ? `Pay ${formatUsdt(totalPrice)} (${pluralTickets(totalTickets)})`
                  : "Confirm"}
              {totalPrice !== null && (
                <img
                  src={getCurrencySymbol()}
                  className="h-4 aspect-square inline ml-1"
                  alt="currency"
                />
              )}
            </Button>
          </span>
        </div>
      )}
      <ResultDialog
        open={isSuccess}
        setOpen={setIsSuccess}
        title="Payment successful!"
        body={successMessage}
        onConfirm={handleConfirm}
        txHash={txHash as string}
      />
    </article>
  );
};

type PaymentFailedProps = {
  cause: Error;
};

function PaymentFailed({ cause }: PaymentFailedProps) {
  let errorMessage = "Unexpected failure of transaction sending";
  if (cause.message.includes("Not enough tokens")) {
    errorMessage = "Not enough tokens";
  }
  return (
    <div>
      <img
        className="aspect-square h-40 mx-auto my-7"
        src="/icons/price_1.svg"
        alt="purchase"
      />
      <h2 className="text-muted font-semibold text-lg text-center">
        Error during transaction
      </h2>
      <p className="text-muted/70 text-md text-center">{errorMessage}</p>
    </div>
  );
}

Graph