import { useMutation, useQuery } from "@tanstack/react-query";
import {
  queryClient,
  StripeApiPrice,
  StripeApiProduct,
  StripeApiSubscription,
  toast,
} from "@xtablo/shared";
import { useMemo } from "react";
import { supabase } from "../lib/supabase";
import { useUser } from "../providers/UserStoreProvider";
import { useAuthedApi } from "./auth";
import { useOrganization } from "./organization";

export type BillingPlan = "solo" | "team" | "annual";
export type CheckoutPlan = "solo" | "team" | "founder";

export const normalizeBillingPlan = (plan: string | null | undefined): BillingPlan => {
  if (!plan) return "solo";

  if (plan === "annual" || plan === "beta" || plan === "founder" || plan === "infinite") {
    return "annual";
  }
  if (plan === "team" || plan === "standard") return "team";
  return "solo";
};

const hasCompliantPaidPlan = (input: {
  required_plan: "solo" | "team";
  required_team_quantity: number;
  active_subscription_plan: "solo" | "team" | "annual" | null;
  active_subscription_quantity: number;
}) => {
  const {
    required_plan,
    required_team_quantity,
    active_subscription_plan,
    active_subscription_quantity,
  } = input;

  if (!active_subscription_plan) {
    return false;
  }

  if (active_subscription_plan === "annual") {
    return true;
  }

  if (required_plan === "solo") {
    return active_subscription_plan === "solo" || active_subscription_plan === "team";
  }

  if (active_subscription_plan !== "team") {
    return false;
  }

  return active_subscription_quantity >= required_team_quantity;
};

/**
 * Hook to get user's subscription status from Supabase
 * Uses RPC function to access stripe data without modifying stripe schema
 */
export function useSubscription() {
  const user = useUser();

  return useQuery({
    queryKey: ["subscription", user.id],
    queryFn: async () => {
      // Get subscriptions via RPC function
      const { data: subscriptions, error } = await supabase.rpc("get_user_stripe_subscriptions");

      if (error) throw error;

      // Filter for active/trialing/past_due and get the most recent
      const activeSubscription = subscriptions
        ?.filter((s: StripeApiSubscription) =>
          ["active", "trialing", "past_due"].includes(s.status)
        )
        .sort(
          (a: StripeApiSubscription, b: StripeApiSubscription) =>
            b.current_period_end - a.current_period_end
        )[0];

      return activeSubscription || null;
    },
    staleTime: 5 * 60 * 1000, // 5 minutes
  });
}

/**
 * Hook to check if user is paying (uses profile field for instant access)
 */
export function useIsPayingUser() {
  const user = useUser();

  const normalizedPlan = normalizeBillingPlan(user.plan);
  const isPaying = normalizedPlan === "team" || normalizedPlan === "annual";

  // Direct access from user profile (fastest)
  return {
    data: isPaying,
    isLoading: false,
  };
}

export const useIsPastTrial = () => {
  const { data: organizationData, isLoading } = useOrganization();

  const isPastTrial = useMemo(() => {
    if (!organizationData) {
      return false;
    }

    if (!organizationData.is_trial_expired) {
      return false;
    }

    return !hasCompliantPaidPlan({
      required_plan: organizationData.required_plan,
      required_team_quantity: organizationData.required_team_quantity,
      active_subscription_plan: organizationData.active_subscription_plan,
      active_subscription_quantity: organizationData.active_subscription_quantity,
    });
  }, [organizationData]);

  return { isPastTrial, isLoading };
};

/**
 * Hook to get when the organization's trial expires
 * Returns remaining trial days when trial is active, otherwise null.
 */
export const useTrialExpiration = () => {
  const { data: organizationData, isLoading } = useOrganization();

  const daysRemaining = useMemo(() => {
    if (!organizationData || organizationData.is_trial_expired) {
      return null as number | null;
    }

    const trialEnd = new Date(organizationData.trial_ends_at).getTime();
    const now = Date.now();

    const diffMs = trialEnd - now;
    if (diffMs <= 0) {
      return 0;
    }

    return Math.ceil(diffMs / (1000 * 60 * 60 * 24));
  }, [organizationData]);

  return { daysRemaining, isLoading };
};

/**
 * Hook to get available prices for Standard plan from Supabase
 * Uses RPC functions to access stripe data without modifying stripe schema
 */
export function useStripePrices() {
  return useQuery({
    queryKey: ["stripe-prices"],
    queryFn: async () => {
      // Get products via RPC
      const { data: products, error: productsError } = await supabase.rpc("get_stripe_products");

      if (productsError) throw productsError;

      // Filter for Standard product
      const standardProducts =
        products?.filter((p: StripeApiProduct) => p.name === "Standard") || [];

      if (standardProducts.length === 0) return [];

      const productIds = standardProducts.map((p: StripeApiProduct) => p.id);

      // Get prices via RPC
      const { data: allPrices, error: pricesError } = await supabase.rpc("get_stripe_prices");

      if (pricesError) throw pricesError;

      // Filter for Standard product prices and sort
      const prices = allPrices
        ?.filter((price: StripeApiPrice) => productIds.includes(price.product))
        .sort((a: StripeApiPrice, b: StripeApiPrice) => a.unit_amount - b.unit_amount);

      // Attach product to each price
      return (
        prices?.map((price: StripeApiPrice) => ({
          ...price,
          product: standardProducts.find((p: StripeApiProduct) => p.id === price.product),
        })) || []
      );
    },
    staleTime: 10 * 60 * 1000, // 10 minutes
  });
}

/**
 * Hook to create a Stripe checkout session
 */
export function useCreateCheckoutSession() {
  const api = useAuthedApi();

  const { mutate, isPending } = useMutation({
    mutationFn: async ({
      plan,
      priceId,
      successUrl,
      cancelUrl,
    }: {
      plan?: CheckoutPlan;
      priceId?: string;
      successUrl?: string;
      cancelUrl?: string;
    }) => {
      if (!plan && !priceId) {
        throw new Error("A checkout plan or priceId is required");
      }

      const response = await api.post("/api/v1/stripe/create-checkout-session", {
        plan,
        priceId,
        successUrl,
        cancelUrl,
      });

      if (!response.data.url) {
        throw new Error("No checkout URL returned");
      }

      // Use the URL directly for redirect
      window.location.href = response.data.url;

      return response.data;
    },
    onError: (error: Error) => {
      toast.add({
        title: "Erreur",
        description: error.message || "Impossible de créer la session de paiement",
        type: "error",
        position: "top-center",
      });
    },
  });

  return { mutate, isPending };
}

/**
 * Hook to create a Stripe customer portal session
 */
export function useCreatePortalSession() {
  const api = useAuthedApi();

  const { mutate, isPending } = useMutation({
    mutationFn: async (returnUrl?: string) => {
      const response = await api.post("/api/v1/stripe/create-portal-session", {
        returnUrl,
      });

      if (!response.data.url) {
        throw new Error("No portal URL returned");
      }

      // Redirect to Stripe Customer Portal
      window.location.href = response.data.url;

      return response.data;
    },
    onError: (error: Error) => {
      toast.add({
        title: "Erreur",
        description: error.message || "Impossible d'ouvrir le portail client",
        type: "error",
        position: "top-center",
      });
    },
  });

  return { mutate, isPending };
}

/**
 * Hook to cancel subscription at period end
 */
export function useCancelSubscription() {
  const api = useAuthedApi();

  const { mutate, isPending } = useMutation({
    mutationFn: async () => {
      const response = await api.post("/api/v1/stripe/cancel-subscription");
      return response.data;
    },
    onSuccess: () => {
      toast.add({
        title: "Abonnement annulé",
        description: "Votre abonnement sera annulé à la fin de la période en cours",
        type: "success",
        position: "top-center",
      });
      queryClient.invalidateQueries({ queryKey: ["subscription"] });
      queryClient.invalidateQueries({ queryKey: ["is-paying"] });
      queryClient.invalidateQueries({ queryKey: ["user"] });
      queryClient.invalidateQueries({ queryKey: ["organization"] });
    },
    onError: (error: Error) => {
      toast.add({
        title: "Erreur",
        description: error.message || "Impossible d'annuler l'abonnement",
        type: "error",
        position: "top-center",
      });
    },
  });

  return { mutate, isPending };
}

/**
 * Hook to reactivate a canceled subscription
 */
export function useReactivateSubscription() {
  const api = useAuthedApi();

  const { mutate, isPending } = useMutation({
    mutationFn: async () => {
      const response = await api.post("/api/v1/stripe/reactivate-subscription");
      return response.data;
    },
    onSuccess: () => {
      toast.add({
        title: "Abonnement réactivé",
        description: "Votre abonnement a été réactivé avec succès",
        type: "success",
        position: "top-center",
      });
      queryClient.invalidateQueries({ queryKey: ["subscription"] });
      queryClient.invalidateQueries({ queryKey: ["is-paying"] });
      queryClient.invalidateQueries({ queryKey: ["user"] });
      queryClient.invalidateQueries({ queryKey: ["organization"] });
    },
    onError: (error: Error) => {
      toast.add({
        title: "Erreur",
        description: error.message || "Impossible de réactiver l'abonnement",
        type: "error",
        position: "top-center",
      });
    },
  });

  return { mutate, isPending };
}
