import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import { tenantService, type TenantResponse, type TenantAccessResponse } from '../api';
import { useAuthUser } from './auth.store';
import { TENANT_ROLES, GLOBAL_USER_ROLES } from '../types/roles';

export interface TenantState {
  // State
  currentTenant: TenantResponse | null;
  parentTenant: TenantResponse | null; // Enterprise parent tenant for child premise navigation
  availableTenants: TenantResponse[] | null;
  currentTenantAccess: TenantAccessResponse | null;
  isLoading: boolean;
  error: string | null;

  // Actions
  setCurrentTenant: (tenant: TenantResponse) => void;
  setAvailableTenants: (tenants: TenantResponse[]) => void;
  switchTenant: (tenantId: string) => Promise<boolean>;
  switchToChildTenant: (childTenant: TenantResponse) => Promise<boolean>; // Switch to child while remembering parent
  restoreParentTenant: () => Promise<boolean>; // Restore parent tenant context
  loadUserTenants: () => Promise<void>;
  loadChildTenants: () => Promise<void>; // Load child tenants for enterprise users
  loadCurrentTenantAccess: () => Promise<void>;
  clearTenants: () => void;
  clearError: () => void;
  setLoading: (loading: boolean) => void;

  // Permission helpers (migrated from BakeryContext)
  hasPermission: (permission: string) => boolean;
  canAccess: (resource: string, action: string) => boolean;
}

export const useTenantStore = create<TenantState>()(
  persist(
    (set, get) => ({
      // Initial state
      currentTenant: null,
      parentTenant: null,
      availableTenants: null,
      currentTenantAccess: null,
      isLoading: false,
      error: null,

      // Actions
      setCurrentTenant: (tenant: TenantResponse) => {
        set({ currentTenant: tenant, currentTenantAccess: null });
        // Update API client with new tenant ID
        if (tenant) {
          tenantService.setCurrentTenant(tenant);
          // Load tenant access info
          get().loadCurrentTenantAccess();
        }
      },

      setAvailableTenants: (tenants: TenantResponse[]) => {
        set({ availableTenants: tenants });
      },

      switchTenant: async (tenantId: string): Promise<boolean> => {
        try {
          set({ isLoading: true, error: null });

          const { availableTenants } = get();

          // Find tenant in available tenants
          const targetTenant = availableTenants?.find(t => t.id === tenantId);
          if (!targetTenant) {
            throw new Error('Tenant not found in available tenants');
          }

          // Switch tenant (frontend-only operation)
          get().setCurrentTenant(targetTenant);
          set({ isLoading: false });
          return true;
        } catch (error) {
          set({
            isLoading: false,
            error: error instanceof Error ? error.message : 'Failed to switch tenant',
          });
          return false;
        }
      },

      switchToChildTenant: async (childTenant: TenantResponse): Promise<boolean> => {
        try {
          set({ isLoading: true, error: null });

          const { currentTenant, availableTenants } = get();

          console.log('[Tenant Store] Switching to child tenant:', {
            from: currentTenant?.id,
            fromName: currentTenant?.name,
            to: childTenant.id,
            toName: childTenant.name
          });

          // Store current tenant as parent (for enterprise users navigating to child premises)
          if (currentTenant) {
            set({ parentTenant: currentTenant });
            console.log('[Tenant Store] Stored parent tenant:', currentTenant.id);
          }

          // Add child to availableTenants if not already present
          if (availableTenants && !availableTenants.find(t => t.id === childTenant.id)) {
            set({ availableTenants: [...availableTenants, childTenant] });
          }

          // CRITICAL: Directly update API client BEFORE updating state
          console.log('[Tenant Store] Directly updating API client with child tenant ID:', childTenant.id);
          const { apiClient } = await import('../api/client');
          apiClient.setTenantId(childTenant.id);

          // Verify the API client was updated
          const verifiedTenantId = apiClient.getTenantId();
          console.log('[Tenant Store] Verified API client tenant ID:', verifiedTenantId);

          if (verifiedTenantId !== childTenant.id) {
            console.error('[Tenant Store] API client tenant ID mismatch! Expected:', childTenant.id, 'Got:', verifiedTenantId);
            set({ isLoading: false, error: 'Failed to update API client tenant ID' });
            return false;
          }

          // Now update the store state
          // IMPORTANT: We've already updated the API client above, so we just update the state
          // We DON'T call setCurrentTenant action because that would trigger tenantService.setCurrentTenant
          // which would call apiClient.setTenantId again
          set({ currentTenant: childTenant, currentTenantAccess: null });

          console.log('[Tenant Store] Switch complete. Current tenant is now:', get().currentTenant?.id);
          console.log('[Tenant Store] Final API client tenant ID verification:', apiClient.getTenantId());

          set({ isLoading: false });
          return true;
        } catch (error) {
          console.error('[Tenant Store] Failed to switch to child tenant:', error);
          set({
            isLoading: false,
            error: error instanceof Error ? error.message : 'Failed to switch to child tenant',
          });
          return false;
        }
      },

      restoreParentTenant: async (): Promise<boolean> => {
        try {
          const { parentTenant } = get();

          if (!parentTenant) {
            console.warn('[Tenant Store] No parent tenant to restore');
            return false;
          }

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

          console.log('[Tenant Store] Restoring parent tenant:', parentTenant.id, parentTenant.name);

          // CRITICAL: Directly update API client BEFORE updating state
          const { apiClient } = await import('../api/client');
          apiClient.setTenantId(parentTenant.id);

          // Verify the API client was updated
          const verifiedTenantId = apiClient.getTenantId();
          console.log('[Tenant Store] Verified API client tenant ID after restore:', verifiedTenantId);

          if (verifiedTenantId !== parentTenant.id) {
            console.error('[Tenant Store] API client tenant ID mismatch! Expected:', parentTenant.id, 'Got:', verifiedTenantId);
            set({ isLoading: false, error: 'Failed to update API client tenant ID' });
            return false;
          }

          // Now update the store state
          set({ currentTenant: parentTenant, currentTenantAccess: null });

          // Clear parent tenant reference
          set({ parentTenant: null, isLoading: false });

          console.log('[Tenant Store] Parent tenant restored successfully');
          return true;
        } catch (error) {
          console.error('[Tenant Store] Failed to restore parent tenant:', error);
          set({
            isLoading: false,
            error: error instanceof Error ? error.message : 'Failed to restore parent tenant',
          });
          return false;
        }
      },

      loadUserTenants: async (): Promise<void> => {
        try {
          set({ isLoading: true, error: null });
          
          // Get current user to determine user ID
          const authState = JSON.parse(localStorage.getItem('auth-storage') || '{}')?.state;
          const user = authState?.user;
          
          if (!user?.id) {
            throw new Error('User not authenticated');
          }
          
          const response = await tenantService.getUserTenants(user.id);
          
          if (response) {
            const tenants = Array.isArray(response) ? response : [response];
            
            set({ 
              availableTenants: tenants,
              isLoading: false 
            });
            
            // If no current tenant is set, set the first one as current
            const { currentTenant } = get();
            if (!currentTenant && tenants.length > 0) {
              get().setCurrentTenant(tenants[0]);
            }
          } else {
            // No tenants found - this is fine for users who haven't completed onboarding
            set({ 
              availableTenants: [],
              isLoading: false,
              error: null 
            });
          }
        } catch (error) {
          // Handle 404 gracefully - user might not have created any tenants yet
          if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
            set({
              availableTenants: [],
              isLoading: false,
              error: null,
            });
          } else {
            set({
              isLoading: false,
              error: error instanceof Error ? error.message : 'Failed to load tenants',
            });
          }
        }
      },

      loadChildTenants: async (): Promise<void> => {
        try {
          const { currentTenant, availableTenants } = get();

          if (!currentTenant) {
            console.warn('No current tenant to load children for');
            return;
          }

          // Fetch child tenants
          const children = await tenantService.getChildTenants(currentTenant.id);

          if (children && children.length > 0) {
            // Add child tenants to availableTenants if not already present
            const currentAvailable = availableTenants || [];
            const newTenants = children.filter(
              child => !currentAvailable.find(t => t.id === child.id)
            );

            if (newTenants.length > 0) {
              set({ availableTenants: [...currentAvailable, ...newTenants] });
            }
          }
        } catch (error) {
          console.warn('Failed to load child tenants:', error);
          // Don't set error state - this is optional enhancement
        }
      },

      loadCurrentTenantAccess: async (): Promise<void> => {
        try {
          const { currentTenant } = get();
          if (!currentTenant) return;

          const accessInfo = await tenantService.getCurrentUserTenantAccess(currentTenant.id);
          set({ currentTenantAccess: accessInfo });
        } catch (error) {
          // Don't set error state for access loading failures - just log
          console.warn('Failed to load tenant access:', error);
          set({ currentTenantAccess: null });
        }
      },

      clearTenants: () => {
        set({
          currentTenant: null,
          parentTenant: null,
          availableTenants: null,
          currentTenantAccess: null,
          error: null,
        });
        tenantService.clearCurrentTenant();
      },

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

      setLoading: (loading: boolean) => {
        set({ isLoading: loading });
      },

      // Permission helpers (migrated from BakeryContext)
      hasPermission: (permission: string): boolean => {
        const { currentTenant, currentTenantAccess } = get();
        if (!currentTenant || !currentTenantAccess || !currentTenantAccess.has_access) {
          return false;
        }
        
        // Check if user has specific permission in their tenant permissions array
        if (currentTenantAccess.permissions?.includes(permission)) {
          return true;
        }
        
        // Check if user has broader permissions that include this one
        if (currentTenantAccess.permissions?.includes('*') || 
            currentTenantAccess.permissions?.includes('admin')) {
          return true;
        }
        
        // Role-based fallback for common permissions based on tenant role
        const tenantRole = currentTenantAccess.role;
        switch (tenantRole) {
          case TENANT_ROLES.OWNER:
          case TENANT_ROLES.ADMIN:
            return true;
          case TENANT_ROLES.MEMBER:
            // Members can read and write but not delete or manage users
            return !permission.includes('delete') && !permission.includes('admin');
          case TENANT_ROLES.VIEWER:
            // Viewers can only read
            return permission.includes('read') || permission.includes('view');
          default:
            return false;
        }
      },

      canAccess: (resource: string, action: string): boolean => {
        const { hasPermission } = get();
        
        // Check specific permission
        if (hasPermission(`${resource}:${action}`)) return true;
        
        // Check wildcard permissions
        if (hasPermission(`${resource}:*`)) return true;
        
        return false;
      },
    }),
    {
      name: 'tenant-storage',
      storage: createJSONStorage(() => localStorage),
      partialize: (state) => ({
        currentTenant: state.currentTenant,
        parentTenant: state.parentTenant,
        availableTenants: state.availableTenants,
        currentTenantAccess: state.currentTenantAccess,
      }),
      onRehydrateStorage: () => (state) => {
        // Initialize API client with stored tenant when store rehydrates
        if (state?.currentTenant) {
          import('../api').then(({ apiClient }) => {
            apiClient.setTenantId(state.currentTenant!.id);
          });
        }
      },
    }
  )
);

// Selectors for common use cases
// Note: For getting tenant ID, prefer using useTenantId() from hooks/useTenantId.ts
export const useCurrentTenant = () => useTenantStore((state) => state.currentTenant);
export const useParentTenant = () => useTenantStore((state) => state.parentTenant);
export const useAvailableTenants = () => useTenantStore((state) => state.availableTenants);
export const useCurrentTenantAccess = () => useTenantStore((state) => state.currentTenantAccess);
export const useTenantLoading = () => useTenantStore((state) => state.isLoading);
export const useTenantError = () => useTenantStore((state) => state.error);

// Hook for tenant actions
export const useTenantActions = () => useTenantStore((state) => ({
  setCurrentTenant: state.setCurrentTenant,
  setAvailableTenants: state.setAvailableTenants,
  switchTenant: state.switchTenant,
  switchToChildTenant: state.switchToChildTenant,
  restoreParentTenant: state.restoreParentTenant,
  loadUserTenants: state.loadUserTenants,
  loadChildTenants: state.loadChildTenants,
  loadCurrentTenantAccess: state.loadCurrentTenantAccess,
  clearTenants: state.clearTenants,
  clearError: state.clearError,
  setLoading: state.setLoading,
}));

// Hook for tenant permissions (replaces useBakeryPermissions)
export const useTenantPermissions = () => useTenantStore((state) => ({
  hasPermission: state.hasPermission,
  canAccess: state.canAccess,
}));

// Combined hook for convenience
export const useTenant = () => {
  const currentTenant = useCurrentTenant();
  const parentTenant = useParentTenant();
  const availableTenants = useAvailableTenants();
  const currentTenantAccess = useCurrentTenantAccess();
  const isLoading = useTenantLoading();
  const error = useTenantError();
  const actions = useTenantActions();
  const permissions = useTenantPermissions();

  return {
    currentTenant,
    parentTenant,
    availableTenants,
    currentTenantAccess,
    isLoading,
    error,
    ...actions,
    ...permissions,
  };
};