import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import axios from 'axios';

const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000';

export type UserPlan = 'free' | 'basic' | 'premium' | 'max' | 'business';

interface AuthUser {
  userId: string;
  email: string;
  role?: string;
  plan?: UserPlan;
  planBillingCycle?: 'monthly' | 'yearly';
}

interface AuthState {
  token: string | null;
  user: AuthUser | null;
  isAuthenticated: boolean;
  hasHydrated: boolean;
  registrationPending: boolean;
  registrationEmail: string;
  setHasHydrated: (v: boolean) => void;
  register: (email: string, password: string) => Promise<void>;
  clearRegistrationPending: () => void;
  resendVerification: (email: string) => Promise<void>;
  login: (email: string, password: string) => Promise<void>;
  loginWithGoogle: (credential: string) => Promise<void>;
  loginWithApple: (identityToken: string) => Promise<void>;
  updatePlan: (plan: UserPlan, billingCycle?: 'monthly' | 'yearly') => Promise<void>;
  /**
   * Ask the server to create a checkout.
   * Creem:  returns { checkoutUrl } — the browser should redirect there.
   * Paddle: returns { priceId }    — used with the Paddle JS overlay.
   */
  createCheckout: (plan: UserPlan, billingCycle: 'monthly' | 'yearly') => Promise<{ checkoutUrl?: string; priceId?: string }>;
  /** Verify a completed Creem checkout (called from the /payment/success page). */
  verifyCheckout: (params: {
    checkoutId: string;
    orderId?: string;
    customerId?: string;
    subscriptionId?: string;
    productId?: string;
    requestId?: string;
    signature?: string;
    rawQuery?: string;
  }) => Promise<void>;
  /** Send the Paddle transaction ID to the server for verification and plan activation. */
  verifyTransaction: (transactionId: string) => Promise<void>;
  /**
   * Update an existing subscription (plan or billing cycle change).
   * Creem:  may return { checkoutUrl } if no subscription ID is stored yet.
   * Paddle: silently patches the subscription (no checkout UI needed).
   */
  updateSubscription: (plan: UserPlan, billingCycle: 'monthly' | 'yearly') => Promise<{ checkoutUrl?: string }>;
  logout: () => void;
  checkAuth: () => Promise<void>;
}

async function verifyAndStore(
  token: string,
  set: (partial: Partial<AuthState>) => void
) {
  const verify = await axios.post(`${API_URL}/api/auth/verify`, { token });
  if (verify.data.valid) {
    set({ token, user: verify.data.user, isAuthenticated: true });
  } else {
    throw new Error('Token verification failed');
  }
}

export const useAuthStore = create<AuthState>()(
  persist(
    (set, get) => ({
      token: null,
      user: null,
      isAuthenticated: false,
      hasHydrated: false,
      registrationPending: false,
      registrationEmail: '',
      setHasHydrated: (v) => set({ hasHydrated: v }),

      register: async (email, password) => {
        await axios.post(`${API_URL}/api/auth/register`, { email, password });
        set({ registrationPending: true, registrationEmail: email });
      },

      clearRegistrationPending: () => {
        set({ registrationPending: false, registrationEmail: '' });
      },

      resendVerification: async (email) => {
        await axios.post(`${API_URL}/api/auth/resend-verification`, { email });
      },

      login: async (email, password) => {
        const res = await axios.post(`${API_URL}/api/auth/login`, { email, password });
        await verifyAndStore(res.data.token, set);
      },

      loginWithGoogle: async (credential) => {
        const res = await axios.post(`${API_URL}/api/auth/google`, { credential });
        await verifyAndStore(res.data.token, set);
      },

      loginWithApple: async (identityToken) => {
        const res = await axios.post(`${API_URL}/api/auth/apple`, { identityToken });
        await verifyAndStore(res.data.token, set);
      },

      updatePlan: async (plan, billingCycle) => {
        const { token } = get();
        const res = await axios.post(
          `${API_URL}/api/auth/plan`,
          { plan, billingCycle },
          { headers: { Authorization: `Bearer ${token}` } }
        );
        await verifyAndStore(res.data.token, set);
      },

      createCheckout: async (plan, billingCycle) => {
        const { token } = get();
        const res = await axios.post(
          `${API_URL}/api/payment/create-checkout`,
          { plan, billingCycle },
          { headers: { Authorization: `Bearer ${token}` } }
        );
        // Creem returns { checkoutUrl }; Paddle returns { priceId }
        return res.data as { checkoutUrl?: string; priceId?: string };
      },

      verifyCheckout: async (params) => {
        const { token } = get();
        const res = await axios.post(
          `${API_URL}/api/payment/verify-checkout`,
          params,
          { headers: { Authorization: `Bearer ${token}` } }
        );
        await verifyAndStore(res.data.token, set);
      },

      verifyTransaction: async (transactionId) => {
        const { token } = get();
        const res = await axios.post(
          `${API_URL}/api/payment/verify-transaction`,
          { transactionId },
          { headers: { Authorization: `Bearer ${token}` } }
        );
        await verifyAndStore(res.data.token, set);
      },

      updateSubscription: async (plan, billingCycle) => {
        const { token } = get();
        const res = await axios.post(
          `${API_URL}/api/payment/update-subscription`,
          { plan, billingCycle },
          { headers: { Authorization: `Bearer ${token}` } }
        );
        // Creem may return { checkoutUrl } when no subscription ID is stored yet
        if (res.data.checkoutUrl) {
          return { checkoutUrl: res.data.checkoutUrl };
        }
        await verifyAndStore(res.data.token, set);
        return {};
      },

      logout: () => {
        set({ token: null, user: null, isAuthenticated: false });
      },

      checkAuth: async () => {
        const { token } = get();
        if (!token) {
          set({ isAuthenticated: false });
          return;
        }
        try {
          const verify = await axios.post(`${API_URL}/api/auth/verify`, { token });
          if (!verify.data.valid) {
            set({ token: null, user: null, isAuthenticated: false });
          }
        } catch {
          set({ token: null, user: null, isAuthenticated: false });
        }
      },
    }),
    {
      name: 'cahoo-auth-storage',
      partialize: (state) => ({
        token: state.token,
        user: state.user,
        isAuthenticated: state.isAuthenticated,
      }),
      onRehydrateStorage: () => (state) => {
        state?.setHasHydrated(true);
      },
    }
  )
);
