import { createContext, useContext, useState, useCallback, useEffect, type ReactNode } from 'react';
import { BrowserProvider, formatEther } from 'ethers';
import type { AuthState, WalletInfo, PortalUser, UserRole, Permission } from '../types/portal';

interface AuthContextType extends AuthState {
  connectWallet: (provider: 'metamask' | 'walletconnect' | 'coinbase') => Promise<void>;
  disconnect: () => void;
  error: string | null;
}

const AuthContext = createContext<AuthContextType | null>(null);

const ROLE_PERMISSIONS: Record<UserRole, Permission[]> = {
  admin: [
    'accounts.view', 'accounts.manage', 'accounts.create',
    'transactions.view', 'transactions.create', 'transactions.approve', 'transactions.execute',
    'treasury.view', 'treasury.manage', 'treasury.rebalance',
    'compliance.view', 'compliance.manage', 'compliance.override',
    'reports.view', 'reports.generate', 'reports.export',
    'settlements.view', 'settlements.approve',
    'admin.users', 'admin.settings', 'admin.audit',
  ],
  treasurer: [
    'accounts.view', 'accounts.manage',
    'transactions.view', 'transactions.create', 'transactions.approve',
    'treasury.view', 'treasury.manage', 'treasury.rebalance',
    'reports.view', 'reports.generate', 'reports.export',
    'settlements.view', 'settlements.approve',
  ],
  analyst: [
    'accounts.view', 'transactions.view', 'treasury.view',
    'reports.view', 'reports.generate', 'settlements.view',
  ],
  compliance_officer: [
    'accounts.view', 'transactions.view', 'treasury.view',
    'compliance.view', 'compliance.manage',
    'reports.view', 'reports.generate', 'reports.export',
    'settlements.view',
  ],
  auditor: [
    'accounts.view', 'transactions.view', 'treasury.view',
    'compliance.view', 'reports.view', 'reports.export',
    'settlements.view', 'admin.audit',
  ],
  viewer: ['accounts.view', 'transactions.view', 'treasury.view', 'reports.view', 'settlements.view'],
};

const AUTH_STORAGE_KEY = 'solace-auth';

function generateUser(address: string): PortalUser {
  return {
    id: `usr-${address.slice(2, 10)}`,
    displayName: `${address.slice(0, 6)}...${address.slice(-4)}`,
    role: 'admin',
    permissions: ROLE_PERMISSIONS['admin'],
    institution: 'Solace Bank Group PLC',
    department: 'Treasury Operations',
    lastLogin: new Date(),
    walletAddress: address,
  };
}

export function AuthProvider({ children }: { children: ReactNode }) {
  const [state, setState] = useState<AuthState>({
    isAuthenticated: false,
    wallet: null,
    user: null,
    loading: true,
  });
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const saved = localStorage.getItem(AUTH_STORAGE_KEY);
    if (saved) {
      try {
        const parsed = JSON.parse(saved);
        setState({
          isAuthenticated: true,
          wallet: parsed.wallet,
          user: { ...parsed.user, lastLogin: new Date(parsed.user.lastLogin) },
          loading: false,
        });
        return;
      } catch { /* ignore */ }
    }
    setState(prev => ({ ...prev, loading: false }));
  }, []);

  const connectWallet = useCallback(async (providerType: 'metamask' | 'walletconnect' | 'coinbase') => {
    setError(null);
    setState(prev => ({ ...prev, loading: true }));

    try {
      let address: string;
      let chainId: number;
      let balance: string;

      const ethereum = (window as unknown as Record<string, unknown>).ethereum as {
        request: (args: { method: string; params?: unknown[] }) => Promise<unknown>;
        isMetaMask?: boolean;
        isCoinbaseWallet?: boolean;
        chainId?: string;
      } | undefined;

      if (ethereum && (providerType === 'metamask' || providerType === 'coinbase')) {
        const accounts = await ethereum.request({ method: 'eth_requestAccounts' }) as string[];
        if (!accounts || accounts.length === 0) throw new Error('No accounts returned');

        const provider = new BrowserProvider(ethereum as never);
        const signer = await provider.getSigner();
        address = await signer.getAddress();
        const network = await provider.getNetwork();
        chainId = Number(network.chainId);
        const bal = await provider.getBalance(address);
        balance = formatEther(bal);
      } else {
        // Demo mode — simulate wallet connection for environments without MetaMask
        await new Promise(resolve => setTimeout(resolve, 1200));
        address = '0x' + Array.from({ length: 40 }, () => Math.floor(Math.random() * 16).toString(16)).join('');
        chainId = 1;
        balance = (Math.random() * 100).toFixed(4);
      }

      const wallet: WalletInfo = { address, chainId, balance, provider: providerType };
      const user = generateUser(address);

      const newState: AuthState = { isAuthenticated: true, wallet, user, loading: false };
      setState(newState);
      localStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify({ wallet, user }));
    } catch (err) {
      const msg = err instanceof Error ? err.message : 'Failed to connect wallet';
      setError(msg);
      setState(prev => ({ ...prev, loading: false }));
    }
  }, []);

  const disconnect = useCallback(() => {
    setState({ isAuthenticated: false, wallet: null, user: null, loading: false });
    localStorage.removeItem(AUTH_STORAGE_KEY);
  }, []);

  return (
    <AuthContext.Provider value={{ ...state, connectWallet, disconnect, error }}>
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error('useAuth must be used within AuthProvider');
  return ctx;
}
