import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { 
  TodayTask, 
  DailyWorkflow, 
  WorkflowProgress, 
  UserWorkflowPreferences,
  NavigationState,
  WorkflowStatus,
  WorkflowError
} from '../types/workflow';
import { taskWorkflowOrchestrator } from '../services/TaskWorkflowOrchestrator';
import { apiClient, ConnectionError, NetworkError } from '../api/client';

const isServerWorkflowId = (workflowId: string) => workflowId.startsWith('daily-');


const normalizeDependencies = (dependencies: unknown): string[] => {
  if (Array.isArray(dependencies)) {
    return dependencies.map(dep => String(dep).trim()).filter(Boolean);
  }

  if (typeof dependencies === 'string') {
    const raw = dependencies.trim();
    if (!raw) return [];

    try {
      const parsed = JSON.parse(raw);
      if (Array.isArray(parsed)) {
        return parsed.map(dep => String(dep).trim()).filter(Boolean);
      }
    } catch {}

    return [raw];
  }

  return [];
};

const normalizeServerWorkflow = (workflow: DailyWorkflow): DailyWorkflow => ({
  ...workflow,
  tasks: Array.isArray(workflow.tasks)
    ? workflow.tasks.map(task => ({
        ...task,
        dependencies: normalizeDependencies(task.dependencies),
      }))
    : [],
});

const isServerUnavailableError = (error: unknown): boolean =>
  error instanceof ConnectionError || error instanceof NetworkError;

const toWorkflowError = (error: unknown, fallbackMessage: string): WorkflowError => {
  if (error instanceof WorkflowError) return error;

  const message = error instanceof Error ? error.message : fallbackMessage;
  return {
    code: 'WORKFLOW_ERROR',
    message,
    timestamp: new Date(),
    recoverable: false,
  };
};

const computeProgressAndNavigation = (workflow: DailyWorkflow): { progress: WorkflowProgress; navigation: NavigationState } => {
  const tasks = Array.isArray(workflow.tasks) ? workflow.tasks : [];
  const totalTasks = tasks.length;
  const completedTasks = tasks.filter(t => t.status === 'completed' || t.status === 'skipped').length;
  const completionPercentage = totalTasks > 0 ? (completedTasks / totalTasks) * 100 : 0;

  const currentIndex = (() => {
    if (typeof workflow.currentTaskIndex === 'number' && workflow.currentTaskIndex >= 0 && workflow.currentTaskIndex < totalTasks) {
      return workflow.currentTaskIndex;
    }
    const idx = tasks.findIndex(t => t.status !== 'completed' && t.status !== 'skipped');
    return idx >= 0 ? idx : Math.max(0, totalTasks - 1);
  })();

  const currentTask = tasks[currentIndex] || null;
  const nextTask = tasks.slice(currentIndex + 1).find(t => t.status !== 'completed' && t.status !== 'skipped') || null;
  const previousTask = currentIndex > 0 ? tasks[currentIndex - 1] : null;

  const estimatedTimeRemaining = tasks
    .filter(t => t.status !== 'completed' && t.status !== 'skipped')
    .reduce((sum, t) => sum + (t.estimatedTime || 0), 0);

  return {
    progress: {
      completedTasks,
      totalTasks,
      completionPercentage,
      currentTask: currentTask || undefined,
      nextTask: nextTask || undefined,
      estimatedTimeRemaining,
      actualTimeSpent: workflow.actualTimeSpent || 0,
    },
    navigation: {
      currentTask,
      previousTask,
      nextTask,
      canGoBack: currentIndex > 0,
      canGoForward: Boolean(nextTask),
    }
  };
};

interface WorkflowState {
  // Current workflow state
  currentWorkflow: DailyWorkflow | null;
  workflowProgress: WorkflowProgress | null;
  navigationState: NavigationState | null;
  
  // User preferences
  userPreferences: UserWorkflowPreferences | null;
  
  // UI state
  isWorkflowModalOpen: boolean;
  isLoading: boolean;
  error: WorkflowError | null;
  isDegradedMode: boolean;
  degradedModeReason: string | null;
  
  // Actions
  generateDailyWorkflow: (userId: string, date?: string) => Promise<void>;
  startWorkflow: (workflowId: string) => Promise<void>;
  pauseWorkflow: (workflowId: string) => Promise<void>;
  stopWorkflow: (workflowId: string) => Promise<void>;
  completeTask: (taskId: string, completionData?: any) => Promise<void>;
  skipTask: (taskId: string) => Promise<void>;
  moveToNextTask: () => Promise<void>;
  moveToPreviousTask: () => Promise<void>;
  
  // UI actions
  openWorkflowModal: () => void;
  closeWorkflowModal: () => void;
  setError: (error: WorkflowError | null) => void;
  clearError: () => void;
  
  // Preferences
  updateUserPreferences: (preferences: Partial<UserWorkflowPreferences>) => void;
  
  // Utility actions
  refreshWorkflowProgress: () => void;
  getCurrentTask: () => TodayTask | null;
  getNextTask: () => TodayTask | null;
  isWorkflowComplete: () => boolean;
  getCompletionPercentage: () => number;
}

export const useWorkflowStore = create<WorkflowState>()(
  persist(
    (set, get) => ({
      // Initial state
      currentWorkflow: null,
      workflowProgress: null,
      navigationState: null,
      userPreferences: null,
      isWorkflowModalOpen: false,
      isLoading: false,
      error: null,
      isDegradedMode: false,
      degradedModeReason: null,

      // Generate daily workflow
      generateDailyWorkflow: async (userId: string, date?: string) => {
        set({ isLoading: true, error: null });
        
        try {
          const resp = await apiClient.get('/api/today-workflow', { params: date ? { date } : {} });
          const serverWorkflow = resp?.data?.data?.workflow as DailyWorkflow | undefined;
          const planSummary = resp?.data?.data?.plan?.provenance_summary;
          
          if (serverWorkflow && Array.isArray(serverWorkflow.tasks)) {
            if (planSummary && !serverWorkflow.provenanceSummary) {
              serverWorkflow.provenanceSummary = planSummary;
            }
            const normalizedWorkflow = normalizeServerWorkflow(serverWorkflow);
            const derived = computeProgressAndNavigation(normalizedWorkflow);
            set({
              currentWorkflow: normalizedWorkflow,
              workflowProgress: derived.progress,
              navigationState: derived.navigation,
              isLoading: false,
              isDegradedMode: false,
              degradedModeReason: null,
            });
            return;
          }

          throw new WorkflowError({
            code: 'WORKFLOW_SCHEMA_INVALID',
            message: 'Server workflow response is missing a valid tasks array.',
            timestamp: new Date(),
            recoverable: false,
            suggestedAction: 'Refresh and try again. If this persists, contact support.'
          });
        } catch (error) {
          if (!isServerUnavailableError(error)) {
            set({
              error: toWorkflowError(error, 'Failed to load workflow from server.'),
              isLoading: false,
              isDegradedMode: false,
              degradedModeReason: null,
            });
            return;
          }
        }

        try {
          const workflow = await taskWorkflowOrchestrator.generateDailyWorkflow(userId, date);
          const progress = taskWorkflowOrchestrator.getWorkflowProgress(workflow.id);
          const navigation = taskWorkflowOrchestrator.getNavigationState(workflow.id);
          set({
            currentWorkflow: workflow,
            workflowProgress: progress,
            navigationState: navigation,
            isLoading: false,
            isDegradedMode: true,
            degradedModeReason: 'Server workflow unavailable. Using local fallback workflow.',
            error: null,
          });
        } catch (error) {
          set({
            error: toWorkflowError(error, 'Failed to generate local fallback workflow.'),
            isLoading: false,
          });
        }
      },

      // Start workflow
      startWorkflow: async (workflowId: string) => {
        set({ isLoading: true, error: null });
        
        try {
          const current = get().currentWorkflow;
          if (current && current.id === workflowId && isServerWorkflowId(workflowId)) {
            const tasks = current.tasks.map((t, idx) => {
              if (idx === current.currentTaskIndex && t.status === 'pending') {
                return { ...t, status: 'in_progress' as const, startedAt: new Date() };
              }
              return t;
            });
            const updated: DailyWorkflow = { ...current, workflowStatus: 'in_progress', startedAt: new Date(), tasks };
            const derived = computeProgressAndNavigation(updated);
            set({ currentWorkflow: updated, workflowProgress: derived.progress, navigationState: derived.navigation, isLoading: false });
            return;
          }

          const workflow = await taskWorkflowOrchestrator.startWorkflow(workflowId);
          const progress = taskWorkflowOrchestrator.getWorkflowProgress(workflow.id);
          const navigation = taskWorkflowOrchestrator.getNavigationState(workflow.id);
          set({ currentWorkflow: workflow, workflowProgress: progress, navigationState: navigation, isLoading: false });
        } catch (error) {
          const workflowError = error as WorkflowError;
          set({ 
            error: workflowError, 
            isLoading: false 
          });
        }
      },

      // Pause workflow
      pauseWorkflow: async (workflowId: string) => {
        set({ isLoading: true, error: null });
        
        try {
          // For now, we'll just update the workflow status to paused
          // In a real implementation, this would call the orchestrator
          const currentWorkflow = get().currentWorkflow;
          if (currentWorkflow && currentWorkflow.id === workflowId) {
            const pausedWorkflow = {
              ...currentWorkflow,
              workflowStatus: 'paused' as const,
              pausedAt: new Date()
            };
            
            set({
              currentWorkflow: pausedWorkflow,
              isLoading: false
            });
          }
        } catch (error) {
          const workflowError = error as WorkflowError;
          set({ 
            error: workflowError, 
            isLoading: false 
          });
        }
      },

      // Stop workflow
      stopWorkflow: async (workflowId: string) => {
        set({ isLoading: true, error: null });
        
        try {
          // For now, we'll just update the workflow status to stopped
          // In a real implementation, this would call the orchestrator
          const currentWorkflow = get().currentWorkflow;
          if (currentWorkflow && currentWorkflow.id === workflowId) {
            const stoppedWorkflow = {
              ...currentWorkflow,
              workflowStatus: 'stopped' as const,
              completedAt: new Date()
            };
            
            set({
              currentWorkflow: stoppedWorkflow,
              isLoading: false
            });
          }
        } catch (error) {
          const workflowError = error as WorkflowError;
          set({ 
            error: workflowError, 
            isLoading: false 
          });
        }
      },

      // Complete task
      completeTask: async (taskId: string, completionData?: any) => {
        const { currentWorkflow } = get();
        if (!currentWorkflow) return;

        set({ isLoading: true, error: null });
        
        try {
          if (isServerWorkflowId(currentWorkflow.id)) {
            await apiClient.post(`/api/today-workflow/tasks/${taskId}/status`, {
              status: 'completed',
              completion_notes: completionData?.userNotes
            });

            const tasks = currentWorkflow.tasks.map(t => (t.id === taskId ? { ...t, status: 'completed' as const, completedAt: new Date() } : t));
            const completedTasks = tasks.filter(t => t.status === 'completed' || t.status === 'skipped').length;
            const totalTasks = tasks.length;
            const workflowStatus: WorkflowStatus = totalTasks > 0 && completedTasks === totalTasks ? 'completed' : 'in_progress';
            const updated: DailyWorkflow = {
              ...currentWorkflow,
              tasks,
              completedTasks,
              totalTasks,
              workflowStatus,
              completedAt: workflowStatus === 'completed' ? new Date() : currentWorkflow.completedAt,
            };
            const derived = computeProgressAndNavigation(updated);
            set({ currentWorkflow: updated, workflowProgress: derived.progress, navigationState: derived.navigation, isLoading: false });
            return;
          }

          const progress = await taskWorkflowOrchestrator.completeTask(currentWorkflow.id, taskId, completionData);
          const navigation = taskWorkflowOrchestrator.getNavigationState(currentWorkflow.id);
          const updatedWorkflow = taskWorkflowOrchestrator.getWorkflow(currentWorkflow.userId, currentWorkflow.date);
          set({ currentWorkflow: updatedWorkflow, workflowProgress: progress, navigationState: navigation, isLoading: false });
        } catch (error) {
          const workflowError = error as WorkflowError;
          set({ 
            error: workflowError, 
            isLoading: false 
          });
        }
      },

      // Skip task
      skipTask: async (taskId: string) => {
        const { currentWorkflow } = get();
        if (!currentWorkflow) return;

        set({ isLoading: true, error: null });
        
        try {
          if (isServerWorkflowId(currentWorkflow.id)) {
            await apiClient.post(`/api/today-workflow/tasks/${taskId}/status`, { status: 'skipped' });
            const tasks = currentWorkflow.tasks.map(t => (t.id === taskId ? { ...t, status: 'skipped' as const, completedAt: new Date() } : t));
            const completedTasks = tasks.filter(t => t.status === 'completed' || t.status === 'skipped').length;
            const totalTasks = tasks.length;
            const workflowStatus: WorkflowStatus = totalTasks > 0 && completedTasks === totalTasks ? 'completed' : currentWorkflow.workflowStatus;
            const updated: DailyWorkflow = { ...currentWorkflow, tasks, completedTasks, totalTasks, workflowStatus };
            const derived = computeProgressAndNavigation(updated);
            set({ currentWorkflow: updated, workflowProgress: derived.progress, navigationState: derived.navigation, isLoading: false });
            return;
          }

          const progress = await taskWorkflowOrchestrator.skipTask(currentWorkflow.id, taskId);
          const navigation = taskWorkflowOrchestrator.getNavigationState(currentWorkflow.id);
          const updatedWorkflow = taskWorkflowOrchestrator.getWorkflow(currentWorkflow.userId, currentWorkflow.date);
          set({ currentWorkflow: updatedWorkflow, workflowProgress: progress, navigationState: navigation, isLoading: false });
        } catch (error) {
          const workflowError = error as WorkflowError;
          set({ 
            error: workflowError, 
            isLoading: false 
          });
        }
      },

      // Move to next task
      moveToNextTask: async () => {
        const { currentWorkflow } = get();
        if (!currentWorkflow) return;

        set({ isLoading: true, error: null });
        
        try {
          if (isServerWorkflowId(currentWorkflow.id)) {
            const tasks = currentWorkflow.tasks;
            const nextIndex = tasks.findIndex((t, idx) => idx > currentWorkflow.currentTaskIndex && t.status !== 'completed' && t.status !== 'skipped');
            const updated: DailyWorkflow = {
              ...currentWorkflow,
              currentTaskIndex: nextIndex >= 0 ? nextIndex : currentWorkflow.currentTaskIndex,
            };
            const derived = computeProgressAndNavigation(updated);
            set({ currentWorkflow: updated, workflowProgress: derived.progress, navigationState: derived.navigation, isLoading: false });
            return;
          }

          await taskWorkflowOrchestrator.moveToNextTask(currentWorkflow.id);
          const progress = taskWorkflowOrchestrator.getWorkflowProgress(currentWorkflow.id);
          const navigation = taskWorkflowOrchestrator.getNavigationState(currentWorkflow.id);
          const updatedWorkflow = taskWorkflowOrchestrator.getWorkflow(currentWorkflow.userId, currentWorkflow.date);
          set({ currentWorkflow: updatedWorkflow, workflowProgress: progress, navigationState: navigation, isLoading: false });
        } catch (error) {
          const workflowError = error as WorkflowError;
          set({ 
            error: workflowError, 
            isLoading: false 
          });
        }
      },

      // Move to previous task
      moveToPreviousTask: async () => {
        const { currentWorkflow } = get();
        if (!currentWorkflow) return;

        set({ isLoading: true, error: null });
        
        try {
          // This would need to be implemented in the orchestrator
          // For now, we'll just refresh the navigation state
          const navigation = taskWorkflowOrchestrator.getNavigationState(currentWorkflow.id);
          
          set({
            navigationState: navigation,
            isLoading: false
          });
        } catch (error) {
          const workflowError = error as WorkflowError;
          set({ 
            error: workflowError, 
            isLoading: false 
          });
        }
      },

      // UI actions
      openWorkflowModal: () => set({ isWorkflowModalOpen: true }),
      closeWorkflowModal: () => set({ isWorkflowModalOpen: false }),
      setError: (error: WorkflowError | null) => set({ error }),
      clearError: () => set({ error: null }),

      // Update user preferences
      updateUserPreferences: (preferences: Partial<UserWorkflowPreferences>) => {
        const { userPreferences } = get();
        set({
          userPreferences: {
            ...userPreferences,
            ...preferences
          } as UserWorkflowPreferences
        });
      },

      // Utility actions
      refreshWorkflowProgress: () => {
        const { currentWorkflow } = get();
        if (!currentWorkflow) return;

        try {
          if (isServerWorkflowId(currentWorkflow.id)) {
            const derived = computeProgressAndNavigation(currentWorkflow);
            set({ workflowProgress: derived.progress, navigationState: derived.navigation });
            return;
          }

          const progress = taskWorkflowOrchestrator.getWorkflowProgress(currentWorkflow.id);
          const navigation = taskWorkflowOrchestrator.getNavigationState(currentWorkflow.id);
          set({ workflowProgress: progress, navigationState: navigation });
        } catch (error) {
          console.warn('Failed to refresh workflow progress:', error);
        }
      },

      getCurrentTask: () => {
        const { navigationState } = get();
        return navigationState?.currentTask || null;
      },

      getNextTask: () => {
        const { navigationState } = get();
        return navigationState?.nextTask || null;
      },

      isWorkflowComplete: () => {
        const { workflowProgress } = get();
        return workflowProgress ? workflowProgress.completedTasks === workflowProgress.totalTasks : false;
      },

      getCompletionPercentage: () => {
        const { workflowProgress } = get();
        return workflowProgress?.completionPercentage || 0;
      }
    }),
    {
      name: 'workflow-store',
      partialize: (state) => ({
        userPreferences: state.userPreferences,
        currentWorkflow: state.currentWorkflow
      })
    }
  )
);

export default useWorkflowStore;
