/**
 * useDashboardCounts Hook
 *
 * Provides a centralized way to fetch entity counts for the dashboard
 * with permission-based filtering and proper error handling.
 */

import { useState, useEffect, useCallback, useRef } from 'react';
import axios from 'axios';
import { hasPermission } from '../helpers/userPermissions';

// User type from auth state (currentUser)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type User = any;

/**
 * Entity configuration for dashboard cards
 */
export interface EntityConfig {
  key: string;
  label: string;
  endpoint: string;
  permission: string;
  href: string;
  icon: string;
}

/**
 * Dashboard entity configurations
 */
export const DASHBOARD_ENTITIES: EntityConfig[] = [
  {
    key: 'users',
    label: 'Users',
    endpoint: '/users/count',
    permission: 'READ_USERS',
    href: '/users/users-list',
    icon: 'mdiAccountGroup',
  },
  {
    key: 'roles',
    label: 'Roles',
    endpoint: '/roles/count',
    permission: 'READ_ROLES',
    href: '/roles/roles-list',
    icon: 'mdiShieldAccountVariantOutline',
  },
  {
    key: 'permissions',
    label: 'Permissions',
    endpoint: '/permissions/count',
    permission: 'READ_PERMISSIONS',
    href: '/permissions/permissions-list',
    icon: 'mdiShieldAccountOutline',
  },
  {
    key: 'projects',
    label: 'Projects',
    endpoint: '/projects/count',
    permission: 'READ_PROJECTS',
    href: '/projects/projects-list',
    icon: 'mdiOfficeBuilding',
  },
  {
    key: 'project_memberships',
    label: 'Project memberships',
    endpoint: '/project_memberships/count',
    permission: 'READ_PROJECT_MEMBERSHIPS',
    href: '/project_memberships/project_memberships-list',
    icon: 'mdiAccountKey',
  },
  {
    key: 'assets',
    label: 'Assets',
    endpoint: '/assets/count',
    permission: 'READ_ASSETS',
    href: '/assets/assets-list',
    icon: 'mdiFolderMultipleImage',
  },
  {
    key: 'asset_variants',
    label: 'Asset variants',
    endpoint: '/asset_variants/count',
    permission: 'READ_ASSET_VARIANTS',
    href: '/asset_variants/asset_variants-list',
    icon: 'mdiImageMultiple',
  },
  {
    key: 'presigned_url_requests',
    label: 'Presigned url requests',
    endpoint: '/presigned_url_requests/count',
    permission: 'READ_PRESIGNED_URL_REQUESTS',
    href: '/presigned_url_requests/presigned_url_requests-list',
    icon: 'mdiLinkLock',
  },
  {
    key: 'tour_pages',
    label: 'Tour pages',
    endpoint: '/tour_pages/count',
    permission: 'READ_TOUR_PAGES',
    href: '/tour_pages/tour_pages-list',
    icon: 'mdiFileDocumentMultiple',
  },
  {
    key: 'project_audio_tracks',
    label: 'Project audio tracks',
    endpoint: '/project_audio_tracks/count',
    permission: 'READ_PROJECT_AUDIO_TRACKS',
    href: '/project_audio_tracks/project_audio_tracks-list',
    icon: 'mdiMusicNote',
  },
  {
    key: 'publish_events',
    label: 'Publish events',
    endpoint: '/publish_events/count',
    permission: 'READ_PUBLISH_EVENTS',
    href: '/publish_events/publish_events-list',
    icon: 'mdiPublish',
  },
  {
    key: 'pwa_caches',
    label: 'Pwa caches',
    endpoint: '/pwa_caches/count',
    permission: 'READ_PWA_CACHES',
    href: '/pwa_caches/pwa_caches-list',
    icon: 'mdiCellphoneLink',
  },
  {
    key: 'access_logs',
    label: 'Access logs',
    endpoint: '/access_logs/count',
    permission: 'READ_ACCESS_LOGS',
    href: '/access_logs/access_logs-list',
    icon: 'mdiClipboardTextOutline',
  },
];

export type EntityCountValue = number | string | null;

export interface DashboardCountsState {
  counts: Record<string, EntityCountValue>;
  loading: boolean;
  error: Error | null;
}

export interface UseDashboardCountsReturn extends DashboardCountsState {
  refetch: () => Promise<void>;
  getCount: (key: string) => EntityCountValue;
  getVisibleEntities: () => EntityConfig[];
}

const LOADING_MESSAGE = 'Loading...';

/**
 * Hook for fetching dashboard entity counts with permission-based filtering
 *
 * @param currentUser - The current authenticated user
 * @returns Dashboard counts state and helper functions
 *
 * @example
 * ```typescript
 * const { counts, loading, getVisibleEntities, getCount } = useDashboardCounts(currentUser);
 *
 * // Get visible entities for the user's permissions
 * const entities = getVisibleEntities();
 *
 * // Get count for a specific entity
 * const userCount = getCount('users'); // number | 'Loading...' | null
 * ```
 */
export function useDashboardCounts(
  currentUser: User | null,
): UseDashboardCountsReturn {
  const [state, setState] = useState<DashboardCountsState>({
    counts: {},
    loading: false,
    error: null,
  });

  // Track if component is mounted
  const mountedRef = useRef(true);

  // Initialize counts with loading message for permitted entities
  const initializeCounts = useCallback(
    (user: User | null): Record<string, EntityCountValue> => {
      const initial: Record<string, EntityCountValue> = {};
      for (const entity of DASHBOARD_ENTITIES) {
        if (hasPermission(user, entity.permission)) {
          initial[entity.key] = LOADING_MESSAGE;
        } else {
          initial[entity.key] = null;
        }
      }
      return initial;
    },
    [],
  );

  // Fetch counts from API
  const fetchCounts = useCallback(async () => {
    if (!currentUser) {
      setState({
        counts: initializeCounts(null),
        loading: false,
        error: null,
      });
      return;
    }

    setState((prev) => ({
      ...prev,
      counts: initializeCounts(currentUser),
      loading: true,
      error: null,
    }));

    try {
      // Build array of fetch promises for permitted entities
      const fetchPromises = DASHBOARD_ENTITIES.map(async (entity) => {
        if (!hasPermission(currentUser, entity.permission)) {
          return { key: entity.key, count: null, error: null };
        }

        try {
          const response = await axios.get(entity.endpoint);
          return {
            key: entity.key,
            count: response.data.count as number,
            error: null,
          };
        } catch (err) {
          return {
            key: entity.key,
            count: null,
            error: err instanceof Error ? err.message : 'Failed to fetch',
          };
        }
      });

      // Use Promise.allSettled for resilience - don't fail if some counts fail
      const results = await Promise.allSettled(fetchPromises);

      if (!mountedRef.current) return;

      const newCounts: Record<string, EntityCountValue> = {};

      results.forEach((result) => {
        if (result.status === 'fulfilled') {
          const { key, count, error } = result.value;
          newCounts[key] = error ? error : count;
        } else {
          // This shouldn't happen since we catch errors inside the promise
          // but handle it for completeness - silently ignore
        }
      });

      setState({
        counts: newCounts,
        loading: false,
        error: null,
      });
    } catch (err) {
      if (!mountedRef.current) return;

      setState((prev) => ({
        ...prev,
        loading: false,
        error: err instanceof Error ? err : new Error('Failed to fetch counts'),
      }));
    }
  }, [currentUser, initializeCounts]);

  // Fetch counts when user changes
  useEffect(() => {
    mountedRef.current = true;
    fetchCounts();

    return () => {
      mountedRef.current = false;
    };
  }, [fetchCounts]);

  // Get count for a specific entity
  const getCount = useCallback(
    (key: string): EntityCountValue => {
      return state.counts[key] ?? null;
    },
    [state.counts],
  );

  // Get entities visible to the current user
  const getVisibleEntities = useCallback((): EntityConfig[] => {
    return DASHBOARD_ENTITIES.filter((entity) =>
      hasPermission(currentUser, entity.permission),
    );
  }, [currentUser]);

  return {
    counts: state.counts,
    loading: state.loading,
    error: state.error,
    refetch: fetchCounts,
    getCount,
    getVisibleEntities,
  };
}

export default useDashboardCounts;
