/**
 * Admin Context - Centralized state management for admin panel
 */

import { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react'
import { useAccount, usePublicClient } from 'wagmi'
import { AdminAction, AuditLog, AdminPreferences, TransactionRequestStatus } from '../types/admin'
import { SecureStorage } from '../utils/encryption'
import { STORAGE_KEYS, DEFAULTS } from '../utils/constants'
import { generateSecureId } from '../utils/security'

interface AdminContextType {
  // Admin actions
  adminActions: AdminAction[]
  createAdminAction: (action: Omit<AdminAction, 'id' | 'status' | 'createdAt'> | AdminAction) => AdminAction
  updateAdminAction: (id: string, updates: Partial<AdminAction>) => void
  
  // Audit logs
  auditLogs: AuditLog[]
  addAuditLog: (log: Omit<AuditLog, 'id' | 'timestamp'>) => void
  exportAuditLogs: () => string
  
  // Preferences
  preferences: AdminPreferences
  updatePreferences: (updates: Partial<AdminPreferences>) => void
  
  // Impersonation
  impersonationAddress: string | null
  setImpersonationAddress: (address: string | null) => void
  isImpersonating: boolean
  
  // Admin check
  isAdmin: boolean
  checkAdminStatus: (address: string, contractAddress: string) => Promise<boolean>
}

const AdminContext = createContext<AdminContextType | undefined>(undefined)

const secureStorage = new SecureStorage()

const defaultPreferences: AdminPreferences = {
  defaultExecutionMethod: DEFAULTS.EXECUTION_METHOD as any,
  showAdvancedOptions: false,
  autoApprove: false,
  theme: 'dark',
}

export function AdminProvider({ children }: { children: ReactNode }) {
  const { address } = useAccount()
  const publicClient = usePublicClient()
  const [adminActions, setAdminActions] = useState<AdminAction[]>([])
  const [auditLogs, setAuditLogs] = useState<AuditLog[]>([])
  const [preferences, setPreferences] = useState<AdminPreferences>(defaultPreferences)
  const [impersonationAddress, setImpersonationAddress] = useState<string | null>(null)

  // Load from storage
  useEffect(() => {
    const loadData = async () => {
      try {
        const storedActions = await secureStorage.getItem(STORAGE_KEYS.TRANSACTIONS)
        if (storedActions) {
          setAdminActions(JSON.parse(storedActions))
        }

        const storedLogs = await secureStorage.getItem(STORAGE_KEYS.AUDIT_LOGS)
        if (storedLogs) {
          const logs = JSON.parse(storedLogs)
          // Keep only last 1000 logs
          setAuditLogs(logs.slice(-1000))
        }

        const storedPrefs = await secureStorage.getItem(STORAGE_KEYS.ADMIN_PREFERENCES)
        if (storedPrefs) {
          setPreferences({ ...defaultPreferences, ...JSON.parse(storedPrefs) })
        }

        const storedImpersonation = sessionStorage.getItem(STORAGE_KEYS.IMPERSONATION_ADDRESS)
        if (storedImpersonation) {
          setImpersonationAddress(storedImpersonation)
        }
      } catch (error) {
        console.error('Failed to load admin data:', error)
      }
    }
    loadData()
  }, [])

  // Save to storage
  useEffect(() => {
    const saveData = async () => {
      try {
        await secureStorage.setItem(STORAGE_KEYS.TRANSACTIONS, JSON.stringify(adminActions))
      } catch (error) {
        console.error('Failed to save admin actions:', error)
      }
    }
    saveData()
  }, [adminActions])

  useEffect(() => {
    const saveLogs = async () => {
      try {
        await secureStorage.setItem(STORAGE_KEYS.AUDIT_LOGS, JSON.stringify(auditLogs))
      } catch (error) {
        console.error('Failed to save audit logs:', error)
      }
    }
    saveLogs()
  }, [auditLogs])

  useEffect(() => {
    const savePrefs = async () => {
      try {
        await secureStorage.setItem(STORAGE_KEYS.ADMIN_PREFERENCES, JSON.stringify(preferences))
      } catch (error) {
        console.error('Failed to save preferences:', error)
      }
    }
    savePrefs()
  }, [preferences])

  useEffect(() => {
    if (impersonationAddress) {
      sessionStorage.setItem(STORAGE_KEYS.IMPERSONATION_ADDRESS, impersonationAddress)
    } else {
      sessionStorage.removeItem(STORAGE_KEYS.IMPERSONATION_ADDRESS)
    }
  }, [impersonationAddress])

  const createAdminAction = useCallback(
    (action: Omit<AdminAction, 'id' | 'status' | 'createdAt'> | AdminAction): AdminAction => {
      // If status is already provided, use it; otherwise default to PENDING
      const hasStatus = 'status' in action
      const newAction: AdminAction = {
        ...action,
        id: hasStatus && 'id' in action ? action.id : generateSecureId(),
        status: hasStatus && 'status' in action ? action.status : TransactionRequestStatus.PENDING,
        createdAt: hasStatus && 'createdAt' in action ? action.createdAt : Date.now(),
      }
      setAdminActions((prev) => {
        // Update if exists, otherwise add
        const existingIndex = prev.findIndex((a) => a.id === newAction.id)
        if (existingIndex >= 0) {
          const updated = [...prev]
          updated[existingIndex] = newAction
          return updated
        }
        return [...prev, newAction]
      })
      return newAction
    },
    []
  )

  const updateAdminAction = useCallback((id: string, updates: Partial<AdminAction>) => {
    setAdminActions((prev) =>
      prev.map((action) => (action.id === id ? { ...action, ...updates } : action))
    )
  }, [])

  const addAuditLog = useCallback(
    (log: Omit<AuditLog, 'id' | 'timestamp'>) => {
      const newLog: AuditLog = {
        ...log,
        id: generateSecureId(),
        timestamp: Date.now(),
      }
      setAuditLogs((prev) => [...prev, newLog].slice(-1000)) // Keep last 1000
    },
    []
  )

  const exportAuditLogs = useCallback(() => {
    return JSON.stringify(auditLogs, null, 2)
  }, [auditLogs])

  const updatePreferences = useCallback((updates: Partial<AdminPreferences>) => {
    setPreferences((prev) => ({ ...prev, ...updates }))
  }, [])

  const checkAdminStatus = useCallback(
    async (address: string, contractAddress: string): Promise<boolean> => {
      if (!publicClient || !address) return false

      try {
        // Read admin() function from contract
        const admin = await publicClient.readContract({
          address: contractAddress as `0x${string}`,
          abi: [
            {
              inputs: [],
              name: 'admin',
              outputs: [{ name: '', type: 'address' }],
              stateMutability: 'view',
              type: 'function',
            },
          ],
          functionName: 'admin',
        })

        return (admin as string).toLowerCase() === address.toLowerCase()
      } catch (error) {
        console.error('Failed to check admin status:', error)
        return false
      }
    },
    [publicClient]
  )

  const isAdmin = address ? true : false // Simplified - will be enhanced with actual checks

  return (
    <AdminContext.Provider
      value={{
        adminActions,
        createAdminAction,
        updateAdminAction,
        auditLogs,
        addAuditLog,
        exportAuditLogs,
        preferences,
        updatePreferences,
        impersonationAddress,
        setImpersonationAddress,
        isImpersonating: !!impersonationAddress,
        isAdmin,
        checkAdminStatus,
      }}
    >
      {children}
    </AdminContext.Provider>
  )
}

export function useAdmin() {
  const context = useContext(AdminContext)
  if (context === undefined) {
    throw new Error('useAdmin must be used within AdminProvider')
  }
  return context
}
