import React, { createContext, useContext, ReactNode, useState, useEffect } from 'react';
import { ApiPromise } from '@pezkuwi/api';
import { useApi, useAccounts } from '@pezkuwi/react-hooks';
import { keyring } from '@pezkuwi/ui-keyring';
import { web3Accounts, web3Enable } from '@pezkuwi/extension-dapp';
import type { InjectedAccountWithMeta } from '@pezkuwi/extension-inject/types';
import type { KeyringAddress } from '@pezkuwi/ui-keyring/types';

interface PezkuwiContextType {
  api: ApiPromise | null;
  isApiReady: boolean;
  isConnected: boolean;
  accounts: InjectedAccountWithMeta[];
  selectedAccount: InjectedAccountWithMeta | null;
  setSelectedAccount: (account: InjectedAccountWithMeta | null) => void;
  connectWallet: () => Promise<void>;
  disconnectWallet: () => void;
  error: string | null;
  sudoKey: string | null;
}

const PezkuwiContext = createContext<PezkuwiContextType | undefined>(undefined);

interface PezkuwiProviderProps {
  children: ReactNode;
  endpoint?: string;
}

export const PezkuwiProvider: React.FC<PezkuwiProviderProps> = ({ children }) => {
  const { api, isApiReady } = useApi();
  const { allAccounts } = useAccounts();
  
  const [accounts, setAccounts] = useState<InjectedAccountWithMeta[]>([]);
  const [selectedAccount, setSelectedAccount] = useState<InjectedAccountWithMeta | null>(null);
  const [sudoKey, setSudoKey] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);

  // Sync accounts from keyring whenever allAccounts changes (which signals an update)
  useEffect(() => {
    const loadAccounts = () => {
        const keyringAccounts = keyring.getAccounts();
        const mappedAccounts: InjectedAccountWithMeta[] = keyringAccounts.map((acc: KeyringAddress) => ({
            address: acc.address,
            meta: {
                name: acc.meta.name,
                source: acc.meta.source as string,
                genesisHash: acc.meta.genesisHash as string
            },
            type: acc.type
        }));
        setAccounts(mappedAccounts);
    };

    loadAccounts();
    // Subscribe to keyring changes if possible, or depend on allAccounts trigger
    const sub = keyring.accounts.subject.subscribe(() => loadAccounts());
    return () => sub.unsubscribe();
  }, [allAccounts]);

  useEffect(() => {
    // If accounts exist but none selected, select the first one
    if (accounts.length > 0 && !selectedAccount) {
        // Try to restore from local storage
        const savedAddress = localStorage.getItem('selectedWallet');
        const found = accounts.find(a => a.address === savedAddress);
        if (found) {
            setSelectedAccount(found);
        } else {
            setSelectedAccount(accounts[0]);
        }
    } else if (accounts.length === 0) {
        setSelectedAccount(null);
    }
  }, [accounts, selectedAccount]);

  useEffect(() => {
    const fetchSudo = async () => {
        if (api && isApiReady && api.query.sudo) {
            try {
                const key = await api.query.sudo.key();
                setSudoKey(key.toString());
            } catch (e) {
                console.warn('Sudo key fetch failed', e);
            }
        }
    };
    fetchSudo();
  }, [api, isApiReady]);


  const handleSetSelectedAccount = (account: InjectedAccountWithMeta | null) => {
    setSelectedAccount(account);
    if (account) {
      localStorage.setItem('selectedWallet', account.address);
      window.dispatchEvent(new Event('walletChanged'));
    } else {
      localStorage.removeItem('selectedWallet');
      window.dispatchEvent(new Event('walletChanged'));
    }
  };

  const connectWallet = async () => {
    try {
      const extensions = await web3Enable('pezkuwi-js/apps');
      
      if (extensions.length === 0) {
        setError("No extension found. Please install Pezkuwi.js Extension.");
        return;
      }

      const injectedAccounts = await web3Accounts();
      
      if (injectedAccounts.length === 0) {
        setError("No accounts found in your wallet. Please create an account.");
        return;
      }

      // Accounts are automatically loaded into keyring by web3Accounts -> keyring interaction in polkadot-js,
      // but we can manually ensure they are available or wait for the subscription to update.
      
      // If API is not ready (offline mode), manually update state so UI reflects connection
      if (!isApiReady) {
         const mappedAccounts: InjectedAccountWithMeta[] = injectedAccounts.map(acc => ({
             address: acc.address,
             meta: {
                 name: acc.meta.name,
                 source: acc.meta.source,
                 genesisHash: acc.meta.genesisHash || null
             },
             type: acc.type
         }));
         setAccounts(mappedAccounts);
         
         // Select the first account if none selected
         if (mappedAccounts.length > 0 && !selectedAccount) {
             handleSetSelectedAccount(mappedAccounts[0]);
         }
      }
      
      setError(null);
    } catch (err) {
      console.error("Failed to connect wallet:", err);
      setError("Failed to connect wallet. Please try again.");
    }
  };

  const disconnectWallet = () => {
    setSelectedAccount(null);
    localStorage.removeItem('selectedWallet');
  };

  const value: PezkuwiContextType = {
    api: api || null,
    isApiReady,
    isConnected: isApiReady,
    accounts,
    selectedAccount,
    setSelectedAccount: handleSetSelectedAccount,
    connectWallet,
    disconnectWallet,
    error,
    sudoKey
  };

  return (
    <PezkuwiContext.Provider value={value}>
      {children}
    </PezkuwiContext.Provider>
  );
};

export const usePezkuwi = (): PezkuwiContextType => {
  const context = useContext(PezkuwiContext);
  if (!context) {
    throw new Error('usePezkuwi must be used within PezkuwiProvider');
  }
  return context;
};