/**
 * Payment Store
 * Zustand store for payments, subscriptions, and billing state management
 */

import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
import type {
  PricingPlan,
  Subscription,
  SubscriptionWithPlan,
  Payment,
  PaymentMethod,
  Invoice,
  Wallet,
  WalletTransaction,
  BillingInfo,
  UsageStats,
  SubscriptionPreview,
  PlanInterval,
} from '../types/payment.types';
import { paymentService } from '../services/payment.service';

// ============================================================================
// State Interface
// ============================================================================

interface PaymentState {
  // Plans
  plans: PricingPlan[];
  loadingPlans: boolean;

  // Subscription
  currentSubscription: SubscriptionWithPlan | null;
  subscriptionHistory: Subscription[];
  loadingSubscription: boolean;

  // Checkout
  subscriptionPreview: SubscriptionPreview | null;
  loadingPreview: boolean;
  processingPayment: boolean;

  // Payment Methods
  paymentMethods: PaymentMethod[];
  loadingPaymentMethods: boolean;

  // Payments & Invoices
  payments: Payment[];
  invoices: Invoice[];
  loadingPayments: boolean;
  loadingInvoices: boolean;

  // Billing Info
  billingInfo: BillingInfo | null;
  loadingBillingInfo: boolean;

  // Usage
  usageStats: UsageStats | null;
  loadingUsage: boolean;

  // Wallet
  wallet: Wallet | null;
  walletTransactions: WalletTransaction[];
  loadingWallet: boolean;
  loadingTransactions: boolean;

  // Coupon
  couponValidation: { valid: boolean; discount: number; discountType: 'percent' | 'amount'; message?: string } | null;
  validatingCoupon: boolean;

  // General
  error: string | null;

  // Plan Actions
  fetchPlans: () => Promise<void>;
  getPlanBySlug: (slug: string) => Promise<PricingPlan | null>;

  // Subscription Actions
  fetchCurrentSubscription: () => Promise<void>;
  fetchSubscriptionHistory: () => Promise<void>;
  previewSubscription: (planId: string, interval: PlanInterval, couponCode?: string) => Promise<void>;
  createCheckoutSession: (planId: string, interval: PlanInterval) => Promise<string>;
  cancelSubscription: (immediately?: boolean) => Promise<void>;
  reactivateSubscription: () => Promise<void>;
  changeSubscriptionPlan: (newPlanId: string, newInterval: PlanInterval) => Promise<void>;

  // Payment Method Actions
  fetchPaymentMethods: () => Promise<void>;
  addPaymentMethod: (paymentMethodId: string) => Promise<void>;
  setDefaultPaymentMethod: (paymentMethodId: string) => Promise<void>;
  removePaymentMethod: (paymentMethodId: string) => Promise<void>;

  // Payment & Invoice Actions
  fetchPayments: (limit?: number) => Promise<void>;
  fetchInvoices: (limit?: number) => Promise<void>;
  downloadInvoice: (invoiceId: string) => Promise<void>;

  // Billing Info Actions
  fetchBillingInfo: () => Promise<void>;
  updateBillingInfo: (info: BillingInfo) => Promise<void>;

  // Usage Actions
  fetchUsageStats: () => Promise<void>;

  // Wallet Actions
  fetchWallet: () => Promise<void>;
  fetchWalletTransactions: (limit?: number, type?: string) => Promise<void>;
  depositToWallet: (amount: number, paymentMethodId: string) => Promise<void>;
  withdrawFromWallet: (amount: number, accountId: string) => Promise<void>;

  // Coupon Actions
  validateCoupon: (code: string, planId: string) => Promise<boolean>;
  clearCouponValidation: () => void;

  // Utility
  clearError: () => void;
  openBillingPortal: () => Promise<void>;
}

// ============================================================================
// Initial State
// ============================================================================

const initialState = {
  // Plans
  plans: [],
  loadingPlans: false,

  // Subscription
  currentSubscription: null,
  subscriptionHistory: [],
  loadingSubscription: false,

  // Checkout
  subscriptionPreview: null,
  loadingPreview: false,
  processingPayment: false,

  // Payment Methods
  paymentMethods: [],
  loadingPaymentMethods: false,

  // Payments & Invoices
  payments: [],
  invoices: [],
  loadingPayments: false,
  loadingInvoices: false,

  // Billing Info
  billingInfo: null,
  loadingBillingInfo: false,

  // Usage
  usageStats: null,
  loadingUsage: false,

  // Wallet
  wallet: null,
  walletTransactions: [],
  loadingWallet: false,
  loadingTransactions: false,

  // Coupon
  couponValidation: null,
  validatingCoupon: false,

  // General
  error: null,
};

// ============================================================================
// Store
// ============================================================================

export const usePaymentStore = create<PaymentState>()(
  devtools(
    (set, get) => ({
      ...initialState,

      // ========================================================================
      // Plan Actions
      // ========================================================================

      fetchPlans: async () => {
        set({ loadingPlans: true, error: null });

        try {
          const plans = await paymentService.getPlans();
          set({ plans, loadingPlans: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch plans';
          set({ error: errorMessage, loadingPlans: false });
          console.error('Error fetching plans:', error);
        }
      },

      getPlanBySlug: async (slug: string) => {
        try {
          return await paymentService.getPlanBySlug(slug);
        } catch (error) {
          console.error('Error fetching plan by slug:', error);
          return null;
        }
      },

      // ========================================================================
      // Subscription Actions
      // ========================================================================

      fetchCurrentSubscription: async () => {
        set({ loadingSubscription: true, error: null });

        try {
          const subscription = await paymentService.getCurrentSubscription();
          set({ currentSubscription: subscription, loadingSubscription: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch subscription';
          set({ error: errorMessage, loadingSubscription: false });
          console.error('Error fetching subscription:', error);
        }
      },

      fetchSubscriptionHistory: async () => {
        try {
          const history = await paymentService.getSubscriptionHistory();
          set({ subscriptionHistory: history });
        } catch (error) {
          console.error('Error fetching subscription history:', error);
        }
      },

      previewSubscription: async (planId: string, interval: PlanInterval, couponCode?: string) => {
        set({ loadingPreview: true, error: null });

        try {
          const preview = await paymentService.previewSubscriptionChange(planId, interval, couponCode);
          set({ subscriptionPreview: preview, loadingPreview: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to preview subscription';
          set({ error: errorMessage, loadingPreview: false });
          console.error('Error previewing subscription:', error);
        }
      },

      createCheckoutSession: async (planId: string, interval: PlanInterval) => {
        set({ processingPayment: true, error: null });

        try {
          const session = await paymentService.createCheckoutSession(planId, interval);
          set({ processingPayment: false });
          return session.url;
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to create checkout session';
          set({ error: errorMessage, processingPayment: false });
          console.error('Error creating checkout session:', error);
          throw error;
        }
      },

      cancelSubscription: async (immediately = false) => {
        const state = get();
        if (!state.currentSubscription) {
          set({ error: 'No active subscription' });
          return;
        }

        set({ processingPayment: true, error: null });

        try {
          const updated = await paymentService.cancelSubscription(
            state.currentSubscription.id,
            immediately
          );
          set({
            currentSubscription: { ...state.currentSubscription, ...updated },
            processingPayment: false,
          });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to cancel subscription';
          set({ error: errorMessage, processingPayment: false });
          console.error('Error canceling subscription:', error);
          throw error;
        }
      },

      reactivateSubscription: async () => {
        const state = get();
        if (!state.currentSubscription) {
          set({ error: 'No subscription to reactivate' });
          return;
        }

        set({ processingPayment: true, error: null });

        try {
          const updated = await paymentService.reactivateSubscription(state.currentSubscription.id);
          set({
            currentSubscription: { ...state.currentSubscription, ...updated },
            processingPayment: false,
          });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to reactivate subscription';
          set({ error: errorMessage, processingPayment: false });
          console.error('Error reactivating subscription:', error);
          throw error;
        }
      },

      changeSubscriptionPlan: async (newPlanId: string, newInterval: PlanInterval) => {
        const state = get();
        if (!state.currentSubscription) {
          set({ error: 'No active subscription' });
          return;
        }

        set({ processingPayment: true, error: null });

        try {
          await paymentService.changeSubscriptionPlan(
            state.currentSubscription.id,
            newPlanId,
            newInterval
          );
          // Refresh subscription data
          await get().fetchCurrentSubscription();
          set({ processingPayment: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to change subscription';
          set({ error: errorMessage, processingPayment: false });
          console.error('Error changing subscription:', error);
          throw error;
        }
      },

      // ========================================================================
      // Payment Method Actions
      // ========================================================================

      fetchPaymentMethods: async () => {
        set({ loadingPaymentMethods: true, error: null });

        try {
          const methods = await paymentService.getPaymentMethods();
          set({ paymentMethods: methods, loadingPaymentMethods: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch payment methods';
          set({ error: errorMessage, loadingPaymentMethods: false });
          console.error('Error fetching payment methods:', error);
        }
      },

      addPaymentMethod: async (paymentMethodId: string) => {
        set({ error: null });

        try {
          await paymentService.addPaymentMethod(paymentMethodId);
          await get().fetchPaymentMethods();
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to add payment method';
          set({ error: errorMessage });
          console.error('Error adding payment method:', error);
          throw error;
        }
      },

      setDefaultPaymentMethod: async (paymentMethodId: string) => {
        set({ error: null });

        try {
          await paymentService.setDefaultPaymentMethod(paymentMethodId);
          await get().fetchPaymentMethods();
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to set default payment method';
          set({ error: errorMessage });
          console.error('Error setting default payment method:', error);
          throw error;
        }
      },

      removePaymentMethod: async (paymentMethodId: string) => {
        set({ error: null });

        try {
          await paymentService.removePaymentMethod(paymentMethodId);
          await get().fetchPaymentMethods();
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to remove payment method';
          set({ error: errorMessage });
          console.error('Error removing payment method:', error);
          throw error;
        }
      },

      // ========================================================================
      // Payment & Invoice Actions
      // ========================================================================

      fetchPayments: async (limit = 20) => {
        set({ loadingPayments: true, error: null });

        try {
          const result = await paymentService.getPaymentHistory(limit);
          set({ payments: result.payments, loadingPayments: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch payments';
          set({ error: errorMessage, loadingPayments: false });
          console.error('Error fetching payments:', error);
        }
      },

      fetchInvoices: async (limit = 20) => {
        set({ loadingInvoices: true, error: null });

        try {
          const result = await paymentService.getInvoices(limit);
          set({ invoices: result.invoices, loadingInvoices: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch invoices';
          set({ error: errorMessage, loadingInvoices: false });
          console.error('Error fetching invoices:', error);
        }
      },

      downloadInvoice: async (invoiceId: string) => {
        try {
          const blob = await paymentService.downloadInvoice(invoiceId);
          const url = window.URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = url;
          a.download = `invoice-${invoiceId}.pdf`;
          document.body.appendChild(a);
          a.click();
          window.URL.revokeObjectURL(url);
          document.body.removeChild(a);
        } catch (error) {
          console.error('Error downloading invoice:', error);
          throw error;
        }
      },

      // ========================================================================
      // Billing Info Actions
      // ========================================================================

      fetchBillingInfo: async () => {
        set({ loadingBillingInfo: true, error: null });

        try {
          const info = await paymentService.getBillingInfo();
          set({ billingInfo: info, loadingBillingInfo: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch billing info';
          set({ error: errorMessage, loadingBillingInfo: false });
          console.error('Error fetching billing info:', error);
        }
      },

      updateBillingInfo: async (info: BillingInfo) => {
        set({ error: null });

        try {
          const updated = await paymentService.updateBillingInfo(info);
          set({ billingInfo: updated });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to update billing info';
          set({ error: errorMessage });
          console.error('Error updating billing info:', error);
          throw error;
        }
      },

      // ========================================================================
      // Usage Actions
      // ========================================================================

      fetchUsageStats: async () => {
        set({ loadingUsage: true, error: null });

        try {
          const stats = await paymentService.getUsageStats();
          set({ usageStats: stats, loadingUsage: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch usage stats';
          set({ error: errorMessage, loadingUsage: false });
          console.error('Error fetching usage stats:', error);
        }
      },

      // ========================================================================
      // Wallet Actions
      // ========================================================================

      fetchWallet: async () => {
        set({ loadingWallet: true, error: null });

        try {
          const result = await paymentService.getWallet();
          set({
            wallet: result.wallet,
            walletTransactions: result.recentTransactions,
            loadingWallet: false,
          });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch wallet';
          set({ error: errorMessage, loadingWallet: false });
          console.error('Error fetching wallet:', error);
        }
      },

      fetchWalletTransactions: async (limit = 20, type?: string) => {
        set({ loadingTransactions: true, error: null });

        try {
          const result = await paymentService.getWalletTransactions(limit, 0, type);
          set({ walletTransactions: result.transactions, loadingTransactions: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch transactions';
          set({ error: errorMessage, loadingTransactions: false });
          console.error('Error fetching wallet transactions:', error);
        }
      },

      depositToWallet: async (amount: number, paymentMethodId: string) => {
        set({ processingPayment: true, error: null });

        try {
          await paymentService.depositToWallet(amount, paymentMethodId);
          await get().fetchWallet();
          set({ processingPayment: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to deposit';
          set({ error: errorMessage, processingPayment: false });
          console.error('Error depositing to wallet:', error);
          throw error;
        }
      },

      withdrawFromWallet: async (amount: number, accountId: string) => {
        set({ processingPayment: true, error: null });

        try {
          await paymentService.withdrawFromWallet(amount, { type: 'bank_account', accountId });
          await get().fetchWallet();
          set({ processingPayment: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to withdraw';
          set({ error: errorMessage, processingPayment: false });
          console.error('Error withdrawing from wallet:', error);
          throw error;
        }
      },

      // ========================================================================
      // Coupon Actions
      // ========================================================================

      validateCoupon: async (code: string, planId: string) => {
        set({ validatingCoupon: true, error: null });

        try {
          const result = await paymentService.validateCoupon(code, planId);
          set({ couponValidation: result, validatingCoupon: false });
          return result.valid;
        } catch (error) {
          set({ couponValidation: null, validatingCoupon: false });
          console.error('Error validating coupon:', error);
          return false;
        }
      },

      clearCouponValidation: () => {
        set({ couponValidation: null });
      },

      // ========================================================================
      // Utility Actions
      // ========================================================================

      clearError: () => {
        set({ error: null });
      },

      openBillingPortal: async () => {
        try {
          const result = await paymentService.createPortalSession();
          window.location.href = result.url;
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to open billing portal';
          set({ error: errorMessage });
          console.error('Error opening billing portal:', error);
        }
      },
    }),
    {
      name: 'payment-store',
    }
  )
);

// ============================================================================
// Selectors
// ============================================================================

export const usePlans = () => usePaymentStore((state) => state.plans);
export const useCurrentSubscription = () => usePaymentStore((state) => state.currentSubscription);
export const useSubscriptionPreview = () => usePaymentStore((state) => state.subscriptionPreview);
export const usePaymentMethods = () => usePaymentStore((state) => state.paymentMethods);
export const usePayments = () => usePaymentStore((state) => state.payments);
export const useInvoices = () => usePaymentStore((state) => state.invoices);
export const useBillingInfo = () => usePaymentStore((state) => state.billingInfo);
export const useUsageStats = () => usePaymentStore((state) => state.usageStats);
export const useWallet = () => usePaymentStore((state) => state.wallet);
export const useWalletTransactions = () => usePaymentStore((state) => state.walletTransactions);
export const useCouponValidation = () => usePaymentStore((state) => state.couponValidation);
export const usePaymentError = () => usePaymentStore((state) => state.error);
export const useProcessingPayment = () => usePaymentStore((state) => state.processingPayment);
export const useLoadingPlans = () => usePaymentStore((state) => state.loadingPlans);
export const useLoadingSubscription = () => usePaymentStore((state) => state.loadingSubscription);

export default usePaymentStore;
