import apiService from './apiService';

export interface WorkflowTransition {
  name: string;
  action: string;
  next_state: string;
  allowed: string;
  condition?: string;
  state: string;
}

export interface WorkflowState {
  state: string;
  doc_status: string;
  update_field?: string;
  update_value?: string;
  allow_edit: string;
  style?: string;
}

export interface WorkflowInfo {
  workflow_name: string;
  workflow_state: string;
  workflow_state_field: string;
  transitions: WorkflowTransition[];
  states: WorkflowState[];
}

// Cache for current user and roles
let cachedUser: string | null = null;
let cachedRoles: string[] | null = null;

/**
 * Set current user manually (call this from your AuthContext or login handler)
 */
export const setCurrentUser = (user: string, roles?: string[]) => {
  cachedUser = user;
  if (roles) {
    cachedRoles = roles;
  }
  console.log('[Workflow] User set manually:', user, 'Roles:', roles);
};

/**
 * Clear cached user (call this on logout)
 */
export const clearCurrentUser = () => {
  cachedUser = null;
  cachedRoles = null;
};

/**
 * Get current logged in user and roles using apiService.getUserDetails()
 */
export const getCurrentUserAndRoles = async (): Promise<{ user: string; roles: string[] }> => {
  try {
    // Check cache first
    if (cachedUser && cachedRoles) {
      console.log('[Workflow] Using cached user:', cachedUser, 'roles:', cachedRoles);
      return { user: cachedUser, roles: cachedRoles };
    }

    // Use the existing getUserDetails() from apiService
    const userDetails = await apiService.getUserDetails();
    
    if (userDetails && userDetails.email) {
      const user = userDetails.email || userDetails.user_id;
      const roles = userDetails.roles || [];
      
      // Cache for future use
      cachedUser = user;
      cachedRoles = roles;
      
      console.log('[Workflow] User from getUserDetails():', user);
      console.log('[Workflow] Roles from getUserDetails():', roles);
      
      return { user, roles };
    }

    console.warn('[Workflow] getUserDetails() returned no user');
    return { user: '', roles: [] };
  } catch (error) {
    console.error('[Workflow] Error getting user details:', error);
    return { user: '', roles: [] };
  }
};

/**
 * Get current logged in user
 */
export const getCurrentUser = async (): Promise<string> => {
  const { user } = await getCurrentUserAndRoles();
  return user;
};

/**
 * Get current user's roles
 */
export const getCurrentUserRoles = async (): Promise<string[]> => {
  const { roles } = await getCurrentUserAndRoles();
  return roles;
};

/**
 * Check if current user has System Manager role
 */
export const isSystemManager = async (): Promise<boolean> => {
  try {
    const roles = await getCurrentUserRoles();
    const isSysManager = roles.includes('System Manager');
    console.log('[Workflow] Is System Manager:', isSysManager, 'Roles:', roles);
    return isSysManager;
  } catch (error) {
    console.error('[Workflow] Error checking System Manager role:', error);
    return false;
  }
};

/**
 * Evaluate a workflow condition against document data
 * Supports simple Python-like conditions used in Frappe workflows
 */
export const evaluateCondition = (condition: string | undefined, doc: Record<string, any>): boolean => {
  if (!condition || condition.trim() === '') {
    return true; // No condition means always valid
  }

  try {
    console.log('[Workflow] Evaluating condition:', condition);
    console.log('[Workflow] Document data for condition:', {
      asset_type: doc.asset_type,
      site_name: doc.site_name,
      need_procurement: doc.need_procurement,
      custom_assign_to_contractor: doc.custom_assign_to_contractor,
      docstatus: doc.docstatus,
    });

    // Create a safe evaluation context
    let evalCondition = condition;

    // Replace Python-style operators with JavaScript equivalents
    evalCondition = evalCondition.replace(/\band\b/g, '&&');
    evalCondition = evalCondition.replace(/\bor\b/g, '||');
    evalCondition = evalCondition.replace(/\bnot\s+/g, '!');
    evalCondition = evalCondition.replace(/\bTrue\b/g, 'true');
    evalCondition = evalCondition.replace(/\bFalse\b/g, 'false');
    evalCondition = evalCondition.replace(/\bNone\b/g, 'null');

    // Replace doc.field_name with actual values
    evalCondition = evalCondition.replace(/doc\.(\w+)/g, (match, fieldName) => {
      const value = doc[fieldName];
      
      // Handle undefined, null, or empty string as falsy
      if (value === undefined || value === null || value === '') {
        return 'false'; // Use false for falsy check compatibility
      }
      if (typeof value === 'string') {
        return `"${value.replace(/"/g, '\\"')}"`;
      }
      if (typeof value === 'boolean') {
        return value ? 'true' : 'false';
      }
      if (typeof value === 'number') {
        return String(value);
      }
      return JSON.stringify(value);
    });

    // Handle == 1 and == 0 for boolean-like comparisons
    evalCondition = evalCondition.replace(/== 1/g, '=== 1');
    evalCondition = evalCondition.replace(/== 0/g, '=== 0');
    evalCondition = evalCondition.replace(/!= 1/g, '!== 1');
    evalCondition = evalCondition.replace(/!= 0/g, '!== 0');

    // Fix negation of false (from empty fields) - !false should be true
    // This handles cases like "not doc.site_name" where site_name is empty
    
    console.log('[Workflow] Transformed condition:', evalCondition);

    // Evaluate the condition safely
    const result = new Function(`return (${evalCondition})`)();
    
    console.log('[Workflow] Condition result:', result);
    return Boolean(result);
  } catch (error) {
    console.error('[Workflow] Error evaluating condition:', condition, error);
    // If we can't evaluate, default to false for safety
    return false;
  }
};

/**
 * Get workflow info for a doctype
 */
export const getWorkflowInfo = async (doctype: string): Promise<WorkflowInfo | null> => {
  try {
    console.log('[Workflow] Getting workflow info for doctype:', doctype);
    
    // First get the workflow name for this doctype
    const workflowResponse = await apiService.apiCall<any>(
      `/api/resource/Workflow?filters=[["document_type","=","${doctype}"],["is_active","=",1]]&fields=["name","workflow_state_field"]&limit=1`
    );
    
    console.log('[Workflow] Workflow response:', workflowResponse);
    
    if (!workflowResponse?.data || workflowResponse.data.length === 0) {
      console.warn('[Workflow] No active workflow found for doctype:', doctype);
      return null;
    }
    
    const workflowName = workflowResponse.data[0].name;
    console.log('[Workflow] Found workflow:', workflowName);
    
    // Get full workflow details
    const fullWorkflow = await apiService.apiCall<any>(
      `/api/resource/Workflow/${encodeURIComponent(workflowName)}`
    );
    
    console.log('[Workflow] Full workflow data:', fullWorkflow?.data);
    console.log('[Workflow] Transitions count:', fullWorkflow?.data?.transitions?.length);
    console.log('[Workflow] States count:', fullWorkflow?.data?.states?.length);
    
    return {
      workflow_name: fullWorkflow.data.name,
      workflow_state: '',
      workflow_state_field: fullWorkflow.data.workflow_state_field,
      transitions: fullWorkflow.data.transitions || [],
      states: fullWorkflow.data.states || [],
    };
  } catch (error) {
    console.error('[Workflow] Error fetching workflow info:', error);
    return null;
  }
};

/**
 * Get all transitions for current state (for System Manager)
 * Now includes condition evaluation and proper deduplication
 */
export const getAllTransitionsForState = async (
  doctype: string,
  currentState: string,
  docData?: Record<string, any>
): Promise<WorkflowTransition[]> => {
  try {
    console.log('[Workflow] Getting all transitions for state:', currentState);
    
    const workflowInfo = await getWorkflowInfo(doctype);
    if (!workflowInfo) {
      console.warn('[Workflow] No workflow info found');
      return [];
    }
    
    console.log('[Workflow] All transitions from workflow:', workflowInfo.transitions.length);
    
    // Filter transitions that start from the current state
    let filteredTransitions = workflowInfo.transitions.filter(t => t.state === currentState);
    console.log('[Workflow] Transitions for state', currentState, ':', filteredTransitions.length);
    
    // If document data is provided, evaluate conditions
    if (docData) {
      filteredTransitions = filteredTransitions.filter(t => {
        const conditionMet = evaluateCondition(t.condition, docData);
        console.log(`[Workflow] Transition "${t.action}" (allowed: ${t.allowed}) condition "${t.condition || 'none'}" = ${conditionMet}`);
        return conditionMet;
      });
      console.log('[Workflow] Transitions after condition evaluation:', filteredTransitions.length);
    }
    
    // Deduplicate transitions with same action AND same next_state
    // This handles cases where multiple roles can trigger the same action
    const seenActions = new Set<string>();
    const uniqueTransitions: WorkflowTransition[] = [];
    
    for (const transition of filteredTransitions) {
      const key = `${transition.action}::${transition.next_state}`;
      if (!seenActions.has(key)) {
        seenActions.add(key);
        uniqueTransitions.push(transition);
      } else {
        console.log(`[Workflow] Skipping duplicate: ${transition.action} → ${transition.next_state} (allowed: ${transition.allowed})`);
      }
    }
    
    console.log('[Workflow] Unique transitions after deduplication:', uniqueTransitions.length);
    return uniqueTransitions;
  } catch (error) {
    console.error('[Workflow] Error fetching all transitions:', error);
    return [];
  }
};

/**
 * Get available workflow transitions for a document
 * System Manager gets all transitions for the current state (with conditions evaluated)
 * Other users get transitions based on their role
 */
export const getWorkflowTransitions = async (
  doctype: string,
  docname: string,
  currentState?: string,
  docData?: Record<string, any>
): Promise<WorkflowTransition[]> => {
  try {
    console.log('[Workflow] getWorkflowTransitions called with:', { doctype, docname, currentState });
    
    // Check if user is System Manager
    const isSysManager = await isSystemManager();
    const userRoles = await getCurrentUserRoles();
    console.log('[Workflow] User is System Manager:', isSysManager);
    console.log('[Workflow] User roles:', userRoles);
    
    if (isSysManager && currentState) {
      console.log('[Workflow] System Manager detected, getting all transitions for state:', currentState);
      
      // System Manager gets all transitions for current state (already deduplicated in getAllTransitionsForState)
      const uniqueTransitions = await getAllTransitionsForState(doctype, currentState, docData);
      
      console.log('[Workflow] Final transitions for System Manager:', uniqueTransitions.map(t => `${t.action} → ${t.next_state}`));
      return uniqueTransitions;
    }
    
    // For non-System Manager users, use Frappe's built-in permission check
    console.log('[Workflow] Non-System Manager, using Frappe API');
    
    const response = await apiService.apiCall<any>(
      '/api/method/frappe.model.workflow.get_transitions',
      {
        method: 'POST',
        body: JSON.stringify({
          doc: JSON.stringify({ doctype, name: docname }),
        }),
      }
    );
    
    console.log('[Workflow] Frappe transitions raw response:', response);
    
    // Handle different response structures
    let transitions: WorkflowTransition[] = [];
    
    if (Array.isArray(response)) {
      transitions = response;
    } else if (response?.message && Array.isArray(response.message)) {
      transitions = response.message;
    } else if (response?.data && Array.isArray(response.data)) {
      transitions = response.data;
    } else if (response?.data?.message && Array.isArray(response.data.message)) {
      transitions = response.data.message;
    }
    
    console.log('[Workflow] Parsed transitions:', transitions);
    console.log('[Workflow] Transitions count:', transitions.length);
    
    // If Frappe API didn't return transitions but we have docData, try local filtering
    if (transitions.length === 0 && currentState && docData) {
      console.log('[Workflow] Frappe API returned no transitions, trying local filtering');
      
      const workflowInfo = await getWorkflowInfo(doctype);
      if (workflowInfo) {
        // Filter by state, role, and conditions
        const localTransitions = workflowInfo.transitions.filter(t => {
          // Check state
          if (t.state !== currentState) return false;
          
          // Check role
          if (!userRoles.includes(t.allowed)) return false;
          
          // Check condition
          if (!evaluateCondition(t.condition, docData)) return false;
          
          return true;
        });
        
        // Deduplicate
        const seenActions = new Set<string>();
        const uniqueTransitions: WorkflowTransition[] = [];
        
        for (const transition of localTransitions) {
          const key = `${transition.action}::${transition.next_state}`;
          if (!seenActions.has(key)) {
            seenActions.add(key);
            uniqueTransitions.push(transition);
          }
        }
        
        console.log('[Workflow] Local filtered transitions:', uniqueTransitions);
        return uniqueTransitions;
      }
    }
    
    return transitions;
  } catch (error) {
    console.error('[Workflow] Error fetching workflow transitions:', error);
    return [];
  }
};

/**
 * Apply a workflow action to a document
 * System Manager can apply any action, others follow normal workflow rules
 */
export const applyWorkflowAction = async (
  doctype: string,
  docname: string,
  action: string,
  nextState?: string
): Promise<any> => {
  try {
    console.log('[Workflow] Applying action:', { doctype, docname, action, nextState });
    
    // Check if user is System Manager
    const isSysManager = await isSystemManager();
    
    if (isSysManager && nextState) {
      // System Manager can directly update workflow state
      // First try normal workflow action
      try {
        const response = await apiService.apiCall<any>(
          '/api/method/frappe.model.workflow.apply_workflow',
          {
            method: 'POST',
            body: JSON.stringify({
              doc: JSON.stringify({ doctype, name: docname }),
              action: action,
            }),
          }
        );
        console.log('[Workflow] Action applied successfully via workflow API');
        return response?.message;
      } catch (workflowError) {
        // If normal workflow fails, System Manager can force update
        console.log('[Workflow] Normal workflow failed, System Manager forcing state change...');
        
        const updateResponse = await apiService.apiCall<any>(
          `/api/resource/${doctype}/${encodeURIComponent(docname)}`,
          {
            method: 'PUT',
            body: JSON.stringify({
              workflow_state: nextState,
            }),
          }
        );
        console.log('[Workflow] Force update response:', updateResponse);
        return updateResponse?.data;
      }
    }
    
    // Normal workflow action for non-System Manager
    const response = await apiService.apiCall<any>(
      '/api/method/frappe.model.workflow.apply_workflow',
      {
        method: 'POST',
        body: JSON.stringify({
          doc: JSON.stringify({ doctype, name: docname }),
          action: action,
        }),
      }
    );
    
    console.log('[Workflow] Action applied successfully');
    return response?.message;
  } catch (error) {
    console.error('[Workflow] Error applying workflow action:', error);
    throw error;
  }
};

/**
 * Check if user can edit document based on workflow state
 * System Manager can always edit
 */
export const canUserEditDocument = async (
  doctype: string,
  docname: string,
  workflowState: string
): Promise<boolean> => {
  try {
    // System Manager can always edit
    const isSysManager = await isSystemManager();
    if (isSysManager) {
      console.log('[Workflow] System Manager can always edit');
      return true;
    }
    
    const workflowInfo = await getWorkflowInfo(doctype);
    if (!workflowInfo) return true; // No workflow, allow edit
    
    const userRoles = await getCurrentUserRoles();
    
    // Find all state entries that match the current state
    const matchingStates = workflowInfo.states.filter(s => s.state === workflowState);
    
    if (matchingStates.length === 0) return true;
    
    // Check if user has any of the roles that can edit in this state
    const canEdit = matchingStates.some(stateInfo => userRoles.includes(stateInfo.allow_edit));
    console.log('[Workflow] Can user edit:', canEdit, 'User roles:', userRoles, 'Allowed roles:', matchingStates.map(s => s.allow_edit));
    return canEdit;
  } catch (error) {
    console.error('[Workflow] Error checking edit permission:', error);
    return false;
  }
};

/**
 * Get workflow state style/color
 */
export const getWorkflowStateStyle = (state: string): { bg: string; text: string; border: string } => {
  const stateStyles: Record<string, { bg: string; text: string; border: string }> = {
    'Draft': { 
      bg: 'bg-gray-100 dark:bg-gray-700', 
      text: 'text-gray-800 dark:text-gray-200',
      border: 'border-gray-300 dark:border-gray-600'
    },
    'Sent To Maintenance manger': { 
      bg: 'bg-blue-100 dark:bg-blue-900/30', 
      text: 'text-blue-800 dark:text-blue-200',
      border: 'border-blue-300 dark:border-blue-600'
    },
    'Sent to Team Leader': { 
      bg: 'bg-blue-100 dark:bg-blue-900/30', 
      text: 'text-blue-800 dark:text-blue-200',
      border: 'border-blue-300 dark:border-blue-600'
    },
    'Sent to General WOA': { 
      bg: 'bg-blue-100 dark:bg-blue-900/30', 
      text: 'text-blue-800 dark:text-blue-200',
      border: 'border-blue-300 dark:border-blue-600'
    },
    'Repair InProgress': { 
      bg: 'bg-yellow-100 dark:bg-yellow-900/30', 
      text: 'text-yellow-800 dark:text-yellow-200',
      border: 'border-yellow-300 dark:border-yellow-600'
    },
    'Pending Purchase': { 
      bg: 'bg-orange-100 dark:bg-orange-900/30', 
      text: 'text-orange-800 dark:text-orange-200',
      border: 'border-orange-300 dark:border-orange-600'
    },
    'Pending Approval': { 
      bg: 'bg-purple-100 dark:bg-purple-900/30', 
      text: 'text-purple-800 dark:text-purple-200',
      border: 'border-purple-300 dark:border-purple-600'
    },
    'Completed': { 
      bg: 'bg-green-100 dark:bg-green-900/30', 
      text: 'text-green-800 dark:text-green-200',
      border: 'border-green-300 dark:border-green-600'
    },
    'Rejected': { 
      bg: 'bg-red-100 dark:bg-red-900/30', 
      text: 'text-red-800 dark:text-red-200',
      border: 'border-red-300 dark:border-red-600'
    },
    'Cancelled': { 
      bg: 'bg-red-100 dark:bg-red-900/30', 
      text: 'text-red-800 dark:text-red-200',
      border: 'border-red-300 dark:border-red-600'
    },
    'Closed': { 
      bg: 'bg-gray-100 dark:bg-gray-700', 
      text: 'text-gray-800 dark:text-gray-200',
      border: 'border-gray-300 dark:border-gray-600'
    },
    'Applied': { 
      bg: 'bg-blue-100 dark:bg-blue-900/30', 
      text: 'text-blue-800 dark:text-blue-200',
      border: 'border-blue-300 dark:border-blue-600'
    },
  };
  
  return stateStyles[state] || stateStyles['Draft'];
};

/**
 * Get action button style based on action name
 */
export const getActionButtonStyle = (action: string): string => {
  const actionStyles: Record<string, string> = {
    'Apply': 'bg-blue-600 hover:bg-blue-700 text-white',
    'Send For Repair': 'bg-yellow-600 hover:bg-yellow-700 text-white',
    'Send For Approval': 'bg-purple-600 hover:bg-purple-700 text-white',
    'Material Request': 'bg-orange-600 hover:bg-orange-700 text-white',
    'Accept': 'bg-green-600 hover:bg-green-700 text-white',
    'Reject': 'bg-red-600 hover:bg-red-700 text-white',
    'Close': 'bg-gray-600 hover:bg-gray-700 text-white',
    'Re-Open': 'bg-blue-600 hover:bg-blue-700 text-white',
    'Cancel': 'bg-red-600 hover:bg-red-700 text-white',
    'Approve': 'bg-green-600 hover:bg-green-700 text-white',
  };
  
  return actionStyles[action] || 'bg-blue-600 hover:bg-blue-700 text-white';
};

/**
 * Get action icon based on action name
 */
export const getActionIcon = (action: string): string => {
  const actionIcons: Record<string, string> = {
    'Apply': '📤',
    'Send For Repair': '🔧',
    'Send For Approval': '📋',
    'Material Request': '📦',
    'Accept': '✅',
    'Reject': '❌',
    'Close': '🔒',
    'Re-Open': '🔓',
    'Cancel': '🚫',
    'Approve': '✅',
  };
  
  return actionIcons[action] || '▶️';
};

export default {
  getWorkflowTransitions,
  applyWorkflowAction,
  getWorkflowInfo,
  getCurrentUserRoles,
  getCurrentUser,
  getCurrentUserAndRoles,
  setCurrentUser,
  clearCurrentUser,
  canUserEditDocument,
  getWorkflowStateStyle,
  getActionButtonStyle,
  getActionIcon,
  isSystemManager,
  getAllTransitionsForState,
  evaluateCondition,
};