import { useEffect, useMemo, useState } from "react";
import { useMutation, useQuery } from "@tanstack/react-query";
import { PlugZap, ArrowUpRight, ShieldCheck, RefreshCcw } from "lucide-react";
import { motion } from "framer-motion";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { toast } from "@/hooks/use-toast";
import { apiRequest, getQueryFn } from "@/lib/queryClient";
import type { User } from "@shared/schema";
import LoginRequiredDialog from "./LoginRequiredDialog";

type BrokerConnectDialogProps = {
  layout?: "desktop" | "mobile";
  open?: boolean;
  onOpenChange?: (open: boolean) => void;
};

type SessionUser = Pick<User, "id" | "username">;

type BrokerStatusResponse = {
  connected: boolean;
  broker?: string;
  connected_at?: string;
  userName?: string;
  brokerUserId?: string;
  authState?: string;
};

const CALLBACK_STORAGE_KEY = "zerodha:callback";
const CALLBACK_MAX_AGE_MS = 5 * 60 * 1000;

export default function BrokerConnectDialog({
  layout = "desktop",
  open,
  onOpenChange,
}: BrokerConnectDialogProps) {
  const [connectOpenInternal, setConnectOpenInternal] = useState(false);
  const isControlled = open !== undefined;
  const connectOpen = isControlled ? open : connectOpenInternal;
  const setConnectOpen = (nextOpen: boolean) => {
    if (!isControlled) {
      setConnectOpenInternal(nextOpen);
    }
    onOpenChange?.(nextOpen);
  };
  const [loginPromptOpen, setLoginPromptOpen] = useState(false);
  const [apiKey, setApiKey] = useState("");
  const [apiSecret, setApiSecret] = useState("");
  const [holdings, setHoldings] = useState<any[]>([]);

  const { data: sessionUser, refetch: refetchSessionUser } = useQuery<SessionUser | null>({
    queryKey: ["/me"],
    queryFn: getQueryFn<SessionUser | null>({ on401: "returnNull" }),
    staleTime: 0,
    refetchOnMount: "always",
  });

  const { data: brokerStatus, refetch: refetchStatus } = useQuery<BrokerStatusResponse | null>({
    queryKey: ["/broker/status"],
    queryFn: getQueryFn<BrokerStatusResponse>({ on401: "returnNull" }),
    staleTime: 0,
    refetchOnMount: "always",
  });

  const loginUrlMutation = useMutation({
    mutationFn: async () => {
      if (!apiKey.trim()) {
        throw new Error("API key is required");
      }
      if (!apiSecret.trim()) {
        throw new Error("API secret is required");
      }
      const redirectUrl = `${window.location.origin}/login`;
      const res = await apiRequest("POST", "/broker/zerodha/login", {
        apiKey,
        apiSecret,
        redirectUrl,
      });
      return res.json() as Promise<{ loginUrl: string }>;
    },
    onSuccess: ({ loginUrl }) => {
      window.open(loginUrl, "_blank", "noopener,noreferrer");
      toast({
        title: "Continue in Zerodha",
        description: "Log in and return here. We will connect your broker automatically.",
      });
    },
    onError: (err: any) =>
      toast({ title: "Could not start Zerodha login", description: err?.message || "Try again." }),
  });

  const reconnectSavedMutation = useMutation({
    mutationFn: async () => {
      const res = await apiRequest("GET", "/broker/login-url");
      return res.json() as Promise<{ loginUrl: string }>;
    },
    onSuccess: ({ loginUrl }) => {
      window.open(loginUrl, "_blank", "noopener,noreferrer");
      toast({
        title: "Continue in Zerodha",
        description: "Log in and return here. We will reconnect your broker automatically.",
      });
    },
    onError: (err: any) => {
      const message = String(err?.message || "");
      if (message.includes("400:") && message.includes("Broker credentials not configured")) {
        toast({
          title: "Enter Zerodha API credentials",
          description: "Saved credentials are missing. Enter the API key and secret once to reconnect.",
        });
        return;
      }
      toast({
        title: "Could not reconnect Zerodha",
        description: err?.message || "Try again.",
      });
    },
  });

  const holdingsMutation = useMutation({
    mutationFn: async () => {
      const res = await apiRequest("GET", "/zerodha/holdings");
      return res.json() as Promise<{ holdings: any[] }>;
    },
    onSuccess: (data) => {
      setHoldings(data?.holdings || []);
      toast({ title: "Holdings fetched", description: "Latest positions pulled from Zerodha." });
    },
    onError: (err: any) =>
      toast({
        title: "Could not fetch holdings",
        description: err?.message || "Check your Zerodha session and try again.",
      }),
  });

  const disconnectMutation = useMutation({
    mutationFn: async () => {
      const res = await apiRequest("POST", "/broker/disconnect");
      return res.json() as Promise<{ connected: boolean }>;
    },
    onSuccess: () => {
      refetchStatus();
      toast({ title: "Broker disconnected", description: "Your broker has been unlinked." });
    },
    onError: (err: any) =>
      toast({
        title: "Disconnect failed",
        description: err?.message || "Try again.",
      }),
  });

  const connected = !!brokerStatus?.connected;
  const canReconnectWithSavedZerodha =
    connected && (brokerStatus?.broker || "").trim().toUpperCase() === "ZERODHA";
  const connectedAt = brokerStatus?.connected_at
    ? new Date(brokerStatus.connected_at)
    : null;
  const triggerClassName = useMemo(() => {
    const layoutClasses =
      layout === "mobile" ? "w-full justify-center shimmer" : "px-4 rounded-xl shimmer";
    return connected
      ? `${layoutClasses} disabled:opacity-100 disabled:cursor-default`
      : layoutClasses;
  }, [connected, layout]);

  const handleConnectClick = async () => {
    if (connected) {
      return;
    }
    const latest = await refetchSessionUser();
    if (!latest.data) {
      setLoginPromptOpen(true);
      return;
    }
    setConnectOpen(true);
  };

  useEffect(() => {
    const consumeCallback = (rawValue?: string) => {
      const value = rawValue || localStorage.getItem(CALLBACK_STORAGE_KEY);
      if (!value) return;
      localStorage.removeItem(CALLBACK_STORAGE_KEY);

      try {
        const payload = JSON.parse(value) as {
          status?: "success" | "error";
          message?: string;
          ts?: number;
        };
        if (payload.ts && Date.now() - payload.ts > CALLBACK_MAX_AGE_MS) {
          return;
        }
        if (payload.status === "success") {
          refetchStatus();
          toast({
            title: "Zerodha connected",
            description: "Your broker connection has been completed.",
          });
          setConnectOpen(false);
        } else if (payload.status === "error") {
          toast({
            title: "Zerodha login failed",
            description: payload.message || "Please retry the login.",
          });
        }
      } catch {
        return;
      }
    };

    consumeCallback();

    const handleStorage = (event: StorageEvent) => {
      if (event.key !== CALLBACK_STORAGE_KEY || !event.newValue) {
        return;
      }
      consumeCallback(event.newValue);
    };

    window.addEventListener("storage", handleStorage);
    return () => window.removeEventListener("storage", handleStorage);
  }, [refetchStatus]);

  return (
    <>
      <Dialog open={connectOpen} onOpenChange={setConnectOpen}>
        <Button
          variant={connected ? "secondary" : "secondary"}
          className={triggerClassName}
          disabled={connected}
          onClick={handleConnectClick}
        >
          <PlugZap className="h-4 w-4" />
          {connected ? "Broker connected" : "Connect broker"}
        </Button>
        <DialogContent className="sm:max-w-2xl border-border/70 bg-gradient-to-br from-background via-background to-muted/30">
          <motion.div
            className="space-y-4"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            transition={{ duration: 0.6, ease: "easeOut" }}
          >
            <DialogHeader className="space-y-2">
              <DialogTitle>Connect your broker</DialogTitle>
              <DialogDescription>
                Link your brokerage to pull positions and keep your dashboard in sync.
              </DialogDescription>
            </DialogHeader>

            <div className="space-y-4 rounded-xl border border-border/70 bg-card/70 p-4">
            <div className="flex flex-col gap-3 rounded-lg border border-border/60 bg-gradient-to-r from-primary/10 via-background to-background px-3 py-3">
              <div className="flex items-center gap-3">
                <div className="rounded-full bg-primary/15 p-2 text-primary">
                  <PlugZap className="h-4 w-4" />
                </div>
                <div className="text-sm leading-tight">
                  <p className="font-medium">Secure brokerage linking</p>
                  <p className="text-muted-foreground">
                    Start in Zerodha and we will complete the connection automatically.
                  </p>
                </div>
                <Badge variant={connected ? "secondary" : "outline"} className="ml-auto">
                  {connected ? "Connected" : "Not connected"}
                </Badge>
              </div>
            {connected && (
                <div className="flex items-center gap-2 text-xs text-muted-foreground">
                  <ShieldCheck className="h-4 w-4 text-primary" />
                  <span>
                    {brokerStatus?.userName
                      ? `Linked as ${brokerStatus.userName}`
                      : `Linked to ${brokerStatus?.broker || "broker"}`}{" "}
                    -{" "}
                    {connectedAt
                      ? connectedAt.toLocaleString()
                      : "just now"}
                  </span>
                </div>
              )}
            </div>

            <motion.div
              className="space-y-3 rounded-lg border border-border/60 bg-background/60 p-4 shadow-sm"
              whileHover={{
                y: -6,
                boxShadow: "0 20px 40px rgba(0,0,0,0.18)",
              }}
              transition={{ type: "spring", stiffness: 300, damping: 24 }}
            >
              <div className="flex items-center justify-between">
                <div>
                  <p className="text-sm font-semibold">Zerodha</p>
                  <p className="text-xs text-muted-foreground">
                    Provide your Kite API key & secret to launch the login and connect your account.
                  </p>
                </div>
                <Badge variant="secondary">Live</Badge>
              </div>

              <div className="grid gap-3 md:grid-cols-2">
                <div className="space-y-1.5">
                  <Label htmlFor="zerodha-api-key">API key</Label>
                  <Input
                    id="zerodha-api-key"
                    placeholder="Enter Zerodha API key"
                    value={apiKey}
                    onChange={(e) => setApiKey(e.target.value)}
                  />
                </div>
                <div className="space-y-1.5">
                  <Label htmlFor="zerodha-api-secret">API secret</Label>
                  <Input
                    id="zerodha-api-secret"
                    placeholder="Enter Zerodha API secret"
                    type="password"
                    value={apiSecret}
                    onChange={(e) => setApiSecret(e.target.value)}
                  />
                </div>
              </div>

              <div className="flex flex-wrap gap-2">
                <Button
                  variant="outline"
                  onClick={() => loginUrlMutation.mutate()}
                  disabled={loginUrlMutation.isPending}
                >
                  <ArrowUpRight className="h-4 w-4" />
                  {loginUrlMutation.isPending ? "Opening Zerodha..." : "Open Zerodha login"}
                </Button>
                {canReconnectWithSavedZerodha ? (
                  <Button
                    variant="secondary"
                    onClick={() => reconnectSavedMutation.mutate()}
                    disabled={reconnectSavedMutation.isPending}
                  >
                    <RefreshCcw className="h-4 w-4" />
                    {reconnectSavedMutation.isPending ? "Opening Zerodha..." : "Reconnect saved Zerodha"}
                  </Button>
                ) : null}
                {connected ? (
                  <Button
                    variant="secondary"
                    onClick={() => holdingsMutation.mutate()}
                    disabled={holdingsMutation.isPending}
                  >
                    <RefreshCcw className="h-4 w-4" />
                    {holdingsMutation.isPending ? "Fetching..." : "Fetch holdings"}
                  </Button>
                ) : null}
                {connected ? (
                  <Button
                    variant="outline"
                    onClick={() => disconnectMutation.mutate()}
                    disabled={disconnectMutation.isPending}
                  >
                    {disconnectMutation.isPending ? "Disconnecting..." : "Disconnect broker"}
                  </Button>
                ) : null}
              </div>

              <p className="text-xs text-muted-foreground">
                After you log in with your Zerodha account, we will connect automatically. Keep this tab open
                until the login completes.
              </p>
              <p className="text-xs text-muted-foreground">
                Zerodha access tokens expire daily. After the first setup, reconnect can use your saved API key
                and secret without re-entering them.
              </p>
            </motion.div>

            <div className="space-y-2 rounded-lg border border-dashed border-border/50 p-4 text-sm text-muted-foreground">
              <p className="font-medium text-foreground">Other brokers</p>
              <div className="flex flex-wrap gap-2">
                <Badge variant="outline">Groww (coming soon)</Badge>
                <Badge variant="outline">Angel One (coming soon)</Badge>
                <Badge variant="outline">ICICI Direct (coming soon)</Badge>
                <Badge variant="outline">HDFC Securities (coming soon)</Badge>
              </div>
            </div>

            {connected && (
              <div className="space-y-2 rounded-lg border border-border/60 bg-background/80 p-4">
                <div className="flex items-center gap-2">
                  <ShieldCheck className="h-4 w-4 text-primary" />
                  <p className="text-sm font-semibold">Latest holdings</p>
                </div>
                {holdings.length === 0 ? (
                  <p className="text-xs text-muted-foreground">
                    No holdings pulled yet. Click &ldquo;Fetch holdings&rdquo; after connecting.
                  </p>
                ) : (
                  <div className="grid gap-2">
                    {holdings.map((item, idx) => (
                      <div
                        key={`${item.tradingsymbol || item.instrument_token || idx}`}
                        className="flex items-center justify-between rounded-md border border-border/50 bg-card/40 px-3 py-2 text-sm"
                      >
                        <div>
                          <p className="font-medium">
                            {item.tradingsymbol || item.symbol || "Instrument"}
                          </p>
                          <p className="text-xs text-muted-foreground">
                            Qty: {item.quantity ?? item.qty ?? "-"} | Avg:{" "}
                            {item.average_price ?? item.avg_price ?? "-"}
                          </p>
                        </div>
                        <Badge variant="secondary">
                          {item.exchange || item.exchange_type || "N/A"}
                        </Badge>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            )}
          </div>
          </motion.div>
        </DialogContent>
      </Dialog>
      <LoginRequiredDialog
        open={loginPromptOpen}
        onOpenChange={setLoginPromptOpen}
        context="connect your broker"
      />
    </>
  );
}
