import React, { useEffect, useState } from 'react';
import { Avatar, Box, MenuItem, Text, config } from 'folds';
import { Icon, Icons } from '../icons';
import { useAtomValue } from 'jotai';
import { sessionsAtom, Session } from '../../state/sessions';
import { setLocalStorageItem } from '../../state/utils/atomWithLocalStorage';
import { getMxIdServer, mxcUrlToHttp } from '../../utils/matrix';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useUserProfile } from '../../hooks/useUserProfile';
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
import { UserAvatar } from '../user-avatar';

type AccountSwitcherProps = {
  currentUserId?: string;
};

/**
 * Loads and displays an avatar for a session that is not the active client.
 * Fetches the profile directly via the homeserver REST API using stored credentials.
 */
function OtherSessionAvatar({ session }: { session: Session }) {
  const [src, setSrc] = useState<string | undefined>();

  useEffect(() => {
    const load = async () => {
      try {
        const res = await fetch(
          `${session.baseUrl}/_matrix/client/v3/profile/${encodeURIComponent(session.userId)}`,
          { headers: { Authorization: `Bearer ${session.accessToken}` } }
        );
        if (!res.ok) return;
        const data = await res.json();
        if (data.avatar_url) {
          const match = (data.avatar_url as string).match(/^mxc:\/\/([^/]+)\/(.+)$/);
          if (match) {
            setSrc(
              `${session.baseUrl}/_matrix/media/v3/thumbnail/${match[1]}/${match[2]}?width=32&height=32&method=crop`
            );
          }
        }
      } catch {
        // ignore — avatar just won't show
      }
    };
    load();
  }, [session.userId, session.baseUrl, session.accessToken]);

  return (
    <Avatar size="300" style={{ width: '1.75rem', height: '1.75rem', minWidth: '1.75rem' }}>
      <UserAvatar
        userId={session.userId}
        src={src}
        alt={session.userId}
        renderFallback={() => <Icon size="100" src={Icons.User} filled />}
      />
    </Avatar>
  );
}

const deleteAllMatrixDatabases = async (): Promise<void> => {
  console.log('[AccountSwitcher] Deleting all Matrix IndexedDB databases...');
  
  // List of known Matrix database names/patterns to delete
  const dbsToDelete = [
    'matrix-js-sdk::matrix-sdk-crypto',  // Shared crypto store (causes conflicts)
  ];
  
  // Try to get all databases if the API is available
  try {
    if ('databases' in indexedDB) {
      const allDbs = await (indexedDB as any).databases();
      const matrixDbs = allDbs
        .map((db: any) => db.name)
        .filter((name: string) => 
          name && (
            name.startsWith('matrix-js-sdk') || 
            name.includes('@@') || 
            name.startsWith('sync@@') || 
            name.startsWith('crypto@@')
          )
        );
      dbsToDelete.push(...matrixDbs);
      console.log('[AccountSwitcher] Found Matrix databases:', matrixDbs);
    }
  } catch (e) {
    console.warn('[AccountSwitcher] Could not enumerate databases:', e);
  }
  
  // Delete each database with timeout
  const deletePromises = dbsToDelete.map(async (dbName) => {
    try {
      const deletePromise = new Promise<void>((resolve, reject) => {
        const request = indexedDB.deleteDatabase(dbName);
        request.onsuccess = () => {
          console.log(`[AccountSwitcher] ✅ Deleted database: ${dbName}`);
          resolve();
        };
        request.onerror = () => {
          console.warn(`[AccountSwitcher] ⚠️  Failed to delete: ${dbName}`, request.error);
          resolve(); // Don't reject, just continue
        };
        request.onblocked = () => {
          console.warn(`[AccountSwitcher] ⚠️  Delete blocked: ${dbName}`);
          resolve(); // Don't reject, reload will handle it
        };
      });
      
      // Add 1-second timeout per database
      const timeoutPromise = new Promise<void>((resolve) => {
        setTimeout(() => {
          console.warn(`[AccountSwitcher] ⏱️  Delete timeout: ${dbName}`);
          resolve();
        }, 1000);
      });
      
      await Promise.race([deletePromise, timeoutPromise]);
    } catch (error) {
      console.warn(`[AccountSwitcher] Error deleting ${dbName}:`, error);
    }
  });
  
  await Promise.all(deletePromises);
  console.log('[AccountSwitcher] ✅ Database cleanup complete');
};

export function AccountSwitcher({ currentUserId }: AccountSwitcherProps) {
  const sessions = useAtomValue(sessionsAtom);
  const mx = useMatrixClient();
  const useAuthentication = useMediaAuthentication();
  const currentProfile = useUserProfile(currentUserId ?? '');
  const currentAvatarUrl = currentProfile.avatarUrl
    ? mxcUrlToHttp(mx, currentProfile.avatarUrl, useAuthentication, 32, 32, 'crop') ?? undefined
    : undefined;
  
  const handleSwitchAccount = async (session: Session) => {
    if (session.userId === currentUserId) return;
    
    console.log('[AccountSwitcher] Switching account from', currentUserId, 'to', session.userId);
    
    // Stop the current client before switching
    if (mx) {
      console.log('[AccountSwitcher] Stopping current Matrix client...');
      try {
        mx.stopClient();
        console.log('[AccountSwitcher] Matrix client stopped');
      } catch (error) {
        console.error('[AccountSwitcher] Error stopping client:', error);
      }
    }
    
    // Set the new current session
    setLocalStorageItem('currentSessionUserId', session.userId);
    
    // Delete all Matrix databases to prevent conflicts
    await deleteAllMatrixDatabases();
    
    // Small delay to ensure cleanup is complete
    await new Promise(resolve => setTimeout(resolve, 100));
    
    // Reload the page to initialize the new session
    console.log('[AccountSwitcher] Reloading page...');
    window.location.reload();
  };

  // If no current user, don't show anything
  if (!currentUserId) {
    return null;
  }

  // Filter out other sessions (not current)
  const otherSessions = sessions.filter(s => s.userId !== currentUserId);
  const hasMultipleAccounts = sessions.length > 1;

  return (
    <Box direction="Column" gap="200">
      <Text size="L400" style={{ paddingInline: config.space.S200, paddingBlock: config.space.S100 }}>
        {hasMultipleAccounts ? 'Switch Account' : 'Accounts'}
      </Text>
      
      {/* Show current account */}
      {currentUserId && (
        <MenuItem
          key={currentUserId}
          size="300"
          radii="300"
          variant="SurfaceVariant"
          disabled
          style={{ paddingInline: config.space.S200 }}
          after={<Icon size="100" src={Icons.Check} filled />}
        >
          <Box gap="200" alignItems="Center">
            <Avatar size="300" style={{ width: '1.75rem', height: '1.75rem', minWidth: '1.75rem' }}>
              <UserAvatar
                userId={currentUserId}
                src={currentAvatarUrl}
                alt={currentUserId}
                renderFallback={() => <Icon size="100" src={Icons.User} filled />}
              />
            </Avatar>
            <Box direction="Column" style={{ gap: '2px' }}>
              <Text size="T300" truncate>
                {currentUserId}
              </Text>
              {getMxIdServer(currentUserId) && (
                <Text size="T200" priority="300" truncate>
                  {getMxIdServer(currentUserId)}
                </Text>
              )}
            </Box>
          </Box>
        </MenuItem>
      )}
      
      {/* Show other accounts if any */}
      {otherSessions.map((session) => {
        const server = getMxIdServer(session.userId);
        
        return (
          <MenuItem
            key={session.userId}
            size="300"
            radii="300"
            onClick={() => handleSwitchAccount(session)}
            variant="Surface"
            style={{ paddingInline: config.space.S200 }}
          >
            <Box gap="200" alignItems="Center">
              <OtherSessionAvatar session={session} />
              <Box direction="Column" style={{ gap: '2px' }}>
                <Text size="T300" truncate>
                  {session.userId}
                </Text>
                {server && (
                  <Text size="T200" priority="300" truncate>
                    {server}
                  </Text>
                )}
              </Box>
            </Box>
          </MenuItem>
        );
      })}
    </Box>
  );
}
