import { useState, useEffect } from 'react';
import { Shield, UserPlus, X, Search } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { supabase } from '@/integrations/supabase/client';
import { useAuth } from '@/hooks/useAuth';
import { useUserRole } from '@/hooks/useUserRole';
import { handleError, handleSuccess, getErrorMessage } from '@/lib/errorHandler';
import { logger } from '@/lib/logger';

// Type-safe role definitions
const VALID_ROLES = ['admin', 'moderator', 'user'] as const;
type ValidRole = typeof VALID_ROLES[number];

/**
 * Type guard to validate role strings
 * Prevents unsafe casting and ensures type safety
 */
function isValidRole(role: string): role is ValidRole {
  return VALID_ROLES.includes(role as ValidRole);
}

/**
 * Get display label for a role
 */
function getRoleLabel(role: string): string {
  const labels: Record<ValidRole, string> = {
    admin: 'Administrator',
    moderator: 'Moderator',
    user: 'User',
  };
  return isValidRole(role) ? labels[role] : role;
}
interface ProfileSearchResult {
  user_id: string;
  username: string;
  display_name?: string;
}

interface UserRole {
  id: string;
  user_id: string;
  role: string;
  granted_at: string;
  profiles?: {
    username: string;
    display_name?: string;
  };
}
export function UserRoleManager() {
  const [userRoles, setUserRoles] = useState<UserRole[]>([]);
  const [loading, setLoading] = useState(true);
  const [searchTerm, setSearchTerm] = useState('');
  const [newUserSearch, setNewUserSearch] = useState('');
  const [newRole, setNewRole] = useState('');
  const [searchResults, setSearchResults] = useState<ProfileSearchResult[]>([]);
  const [actionLoading, setActionLoading] = useState<string | null>(null);
  const {
    user
  } = useAuth();
  const {
    isAdmin,
    isSuperuser,
    permissions
  } = useUserRole();
  const fetchUserRoles = async () => {
    try {
      const {
        data,
        error
      } = await supabase.from('user_roles').select(`
          id,
          user_id,
          role,
          granted_at
        `).order('granted_at', {
        ascending: false
      });
      if (error) throw error;

      // Get unique user IDs
      const userIds = [...new Set((data || []).map(r => r.user_id))];

      // Fetch user profiles with emails (for admins)
      let profiles: Array<{ user_id: string; username: string; display_name?: string }> | null = null;
      const { data: allProfiles, error: rpcError } = await supabase
        .rpc('get_users_with_emails');
      
      if (rpcError) {
        logger.warn('Failed to fetch users with emails, using basic profiles', { error: getErrorMessage(rpcError) });
        const { data: basicProfiles } = await supabase
          .from('profiles')
          .select('user_id, username, display_name')
          .in('user_id', userIds);
        profiles = basicProfiles as typeof profiles;
      } else {
        profiles = allProfiles?.filter(p => userIds.includes(p.user_id)) || null;
      }
      const profileMap = new Map(profiles?.map(p => [p.user_id, p]) || []);

      // Combine data with profiles
      const userRolesWithProfiles = (data || []).map(role => ({
        ...role,
        profiles: profileMap.get(role.user_id)
      }));
      setUserRoles(userRolesWithProfiles);
    } catch (error: unknown) {
      handleError(error, {
        action: 'Load User Roles',
        userId: user?.id
      });
    } finally {
      setLoading(false);
    }
  };
  const searchUsers = async (search: string) => {
    if (!search.trim()) {
      setSearchResults([]);
      return;
    }
    try {
      let data;
      const { data: allUsers, error: rpcError } = await supabase
        .rpc('get_users_with_emails');
      
      if (rpcError) {
        logger.warn('Failed to fetch users with emails, using basic profiles', { error: getErrorMessage(rpcError) });
        const { data: basicProfiles, error: profilesError } = await supabase
          .from('profiles')
          .select('user_id, username, display_name')
          .ilike('username', `%${search}%`);
        
        if (profilesError) throw profilesError;
        data = basicProfiles?.slice(0, 10);
      } else {
        // Filter by search term
        data = allUsers?.filter(user => 
          user.username.toLowerCase().includes(search.toLowerCase()) ||
          user.display_name?.toLowerCase().includes(search.toLowerCase())
        ).slice(0, 10);
      }

      // Filter out users who already have roles
      const existingUserIds = userRoles.map(ur => ur.user_id);
      const filteredResults = (data || []).filter(profile => !existingUserIds.includes(profile.user_id));
      setSearchResults(filteredResults);
    } catch (error: unknown) {
      logger.error('User search failed', { error: getErrorMessage(error) });
    }
  };
  useEffect(() => {
    fetchUserRoles();
  }, []);
  useEffect(() => {
    const debounceTimer = setTimeout(() => {
      searchUsers(newUserSearch);
    }, 300);
    return () => clearTimeout(debounceTimer);
  }, [newUserSearch, userRoles]);
  const grantRole = async (userId: string, role: ValidRole) => {
    if (!isAdmin()) return;
    
    // Double-check role validity before database operation
    if (!isValidRole(role)) {
      handleError(new Error('Invalid role'), {
        action: 'Grant Role',
        userId: user?.id,
        metadata: { targetUserId: userId, attemptedRole: role }
      });
      return;
    }
    
    setActionLoading('grant');
    try {
      const {
        error
      } = await supabase.from('user_roles').insert([{
        user_id: userId,
        role,
        granted_by: user?.id
      }]);
      
      if (error) throw error;
      
      handleSuccess('Role Granted', `User has been granted ${getRoleLabel(role)} role`);
      setNewUserSearch('');
      setNewRole('');
      setSearchResults([]);
      fetchUserRoles();
    } catch (error: unknown) {
      handleError(error, {
        action: 'Grant Role',
        userId: user?.id,
        metadata: { targetUserId: userId, role }
      });
    } finally {
      setActionLoading(null);
    }
  };
  const revokeRole = async (roleId: string) => {
    if (!isAdmin()) return;
    setActionLoading(roleId);
    try {
      const {
        error
      } = await supabase.from('user_roles').delete().eq('id', roleId);
      if (error) throw error;
      handleSuccess('Role Revoked', 'User role has been revoked');
      fetchUserRoles();
    } catch (error: unknown) {
      handleError(error, {
        action: 'Revoke Role',
        userId: user?.id,
        metadata: { roleId }
      });
    } finally {
      setActionLoading(null);
    }
  };
  if (!isAdmin()) {
    return <div className="text-center py-8">
        <Shield className="w-12 h-12 text-muted-foreground mx-auto mb-4" />
        <h3 className="text-lg font-semibold mb-2">Access Denied</h3>
        <p className="text-muted-foreground">
          Only administrators can manage user roles.
        </p>
      </div>;
  }
  if (loading) {
    return <div className="flex items-center justify-center p-8">
        <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-primary"></div>
      </div>;
  }
  const filteredRoles = userRoles.filter(role => role.profiles?.username?.toLowerCase().includes(searchTerm.toLowerCase()) || role.profiles?.display_name?.toLowerCase().includes(searchTerm.toLowerCase()) || role.role.toLowerCase().includes(searchTerm.toLowerCase()));
  return <div className="space-y-6">
      {/* Add new role */}
      <Card>
        
        <CardContent className="space-y-4">
          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
            <div>
              <Label htmlFor="user-search">Search Users</Label>
              <div className="relative">
                <Search className="absolute left-3 top-3 w-4 h-4 text-muted-foreground" />
                <Input id="user-search" placeholder="Search by username or display name..." value={newUserSearch} onChange={e => setNewUserSearch(e.target.value)} className="pl-10" />
              </div>
              
              {searchResults.length > 0 && <div className="mt-2 border rounded-lg bg-background">
                  {searchResults.map(profile => <div key={profile.user_id} className="p-3 hover:bg-muted/50 cursor-pointer border-b last:border-b-0" onClick={() => {
                setNewUserSearch(profile.display_name || profile.username);
                setSearchResults([profile]);
              }}>
                      <div className="font-medium">
                        {profile.display_name || profile.username}
                      </div>
                      {profile.display_name && <div className="text-sm text-muted-foreground">
                          @{profile.username}
                        </div>}
                    </div>)}
                </div>}
            </div>
            
            <div>
              <Label htmlFor="role-select">Role</Label>
              <Select value={newRole} onValueChange={setNewRole}>
                <SelectTrigger>
                  <SelectValue placeholder="Select a role" />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="moderator">Moderator</SelectItem>
                  {isSuperuser() && <SelectItem value="admin">Administrator</SelectItem>}
                </SelectContent>
              </Select>
            </div>
          </div>
          
          <Button onClick={() => {
          const selectedUser = searchResults.find(p => (p.display_name || p.username) === newUserSearch);
          
          // Type-safe validation before calling grantRole
          if (selectedUser && newRole && isValidRole(newRole)) {
            grantRole(selectedUser.user_id, newRole);
          } else if (selectedUser && newRole) {
            // This should never happen due to Select component constraints,
            // but provides safety in case of UI bugs
            handleError(new Error('Invalid role selected'), {
              action: 'Grant Role',
              userId: user?.id,
              metadata: { selectedUser: selectedUser?.user_id, newRole }
            });
          }
        }} disabled={!newRole || !isValidRole(newRole) || !searchResults.find(p => (p.display_name || p.username) === newUserSearch) || actionLoading === 'grant'} className="w-full md:w-auto">
            {actionLoading === 'grant' ? 'Granting...' : 'Grant Role'}
          </Button>
        </CardContent>
      </Card>

      {/* Search existing roles */}
      <div>
        <Label htmlFor="role-search">Search Existing Roles</Label>
        <div className="relative">
          <Search className="absolute left-3 top-3 w-4 h-4 text-muted-foreground" />
          <Input id="role-search" placeholder="Search users with roles..." value={searchTerm} onChange={e => setSearchTerm(e.target.value)} className="pl-10" />
        </div>
      </div>

      {/* User roles list */}
      <div className="space-y-3">
        {filteredRoles.length === 0 ? <div className="text-center py-8">
            <Shield className="w-12 h-12 text-muted-foreground mx-auto mb-4" />
            <h3 className="text-lg font-semibold mb-2">No roles found</h3>
            <p className="text-muted-foreground">
              {searchTerm ? 'No users match your search criteria.' : 'No user roles have been granted yet.'}
            </p>
          </div> : filteredRoles.map(userRole => <Card key={userRole.id}>
              <CardContent className="flex items-center justify-between p-4">
                <div className="flex items-center gap-3">
                  <div>
                    <div className="font-medium">
                      {userRole.profiles?.display_name || userRole.profiles?.username}
                    </div>
                    {userRole.profiles?.display_name && <div className="text-sm text-muted-foreground">
                        @{userRole.profiles.username}
                      </div>}
                  </div>
                  <Badge variant={userRole.role === 'admin' ? 'default' : 'secondary'}>
                    {userRole.role}
                  </Badge>
                </div>
                
                {/* Only show revoke button if current user can manage this role */}
                {(isSuperuser() || isAdmin() && !['admin', 'superuser'].includes(userRole.role)) && <Button variant="outline" size="sm" onClick={() => revokeRole(userRole.id)} disabled={actionLoading === userRole.id}>
                    <X className="w-4 h-4" />
                  </Button>}
              </CardContent>
            </Card>)}
      </div>
    </div>;
}