import { create } from 'zustand';
import { useShallow } from 'zustand/react/shallow';
import { immer } from 'zustand/middleware/immer';
import { toast } from '../lib/toast';
import { workflowService } from '../services/workflows';
import { versionService } from '../services/versions';
import { ApiRequestError } from '../types/api';
import { __ } from '../lib/i18n';

interface WorkflowState {
  // Workflow metadata
  id: number | null;
  name: string;
  isActive: boolean;
  initialName: string | null;

  // Version state
  publishedVersionId: number | null;
  lastPublishedAt: string | null;
  hasUnpublishedChanges: boolean;
  isPublishing: boolean;

  // Loading/saving states
  isLoading: boolean;
  isSaving: boolean;
  isActivating: boolean;
  loadError: string | null;
}

interface WorkflowActions {
  // Setters
  setId: (id: number | null) => void;
  setName: (name: string) => void;
  setInitialName: (name: string) => void;
  setActive: (active: boolean) => void;
  setIsSaving: (saving: boolean) => void;

  // Version setters
  setPublishedVersionId: (id: number | null) => void;
  setLastPublishedAt: (date: string | null) => void;
  setHasUnpublishedChanges: (hasChanges: boolean) => void;
  markAsUnpublished: () => void;

  // Async actions
  activate: () => Promise<boolean>;
  deactivate: () => Promise<boolean>;
  publish: (notes?: string) => Promise<boolean>;
  refreshVersionStatus: () => Promise<void>;

  // Computed
  hasNameChanged: () => boolean;
  isPublished: () => boolean;

  // Reset
  reset: () => void;
}

type WorkflowStore = WorkflowState & WorkflowActions;

const initialState: WorkflowState = {
  id: null,
  name: 'Untitled Workflow',
  isActive: false,
  initialName: null,
  publishedVersionId: null,
  lastPublishedAt: null,
  hasUnpublishedChanges: false,
  isPublishing: false,
  isLoading: false,
  isSaving: false,
  isActivating: false,
  loadError: null,
};

export const useWorkflowStore = create<WorkflowStore>()(
  immer((set, get) => ({
    ...initialState,

    setId: (id) =>
      set((state) => {
        state.id = id;
      }),

    setName: (name) =>
      set((state) => {
        state.name = name;
      }),

    setInitialName: (name) =>
      set((state) => {
        state.initialName = name;
      }),

    setActive: (active) =>
      set((state) => {
        state.isActive = active;
      }),

    setIsSaving: (saving) =>
      set((state) => {
        state.isSaving = saving;
      }),

    // Version setters
    setPublishedVersionId: (id) =>
      set((state) => {
        state.publishedVersionId = id;
      }),

    setLastPublishedAt: (date) =>
      set((state) => {
        state.lastPublishedAt = date;
      }),

    setHasUnpublishedChanges: (hasChanges) =>
      set((state) => {
        state.hasUnpublishedChanges = hasChanges;
      }),

    markAsUnpublished: () =>
      set((state) => {
        state.hasUnpublishedChanges = true;
      }),

    activate: async () => {
      const { id, isSaving, isActivating } = get();
      if (!id || isSaving || isActivating) return false;

      set((state) => {
        state.isActivating = true;
      });

      try {
        await workflowService.activateWorkflow(id);
        set((state) => {
          state.isActive = true;
          state.isActivating = false;
        });
        toast.success(__('Workflow activated'));
        return true;
      } catch (err) {
        let errorMessages: string[] = [__('Failed to activate workflow')];

        if (err instanceof ApiRequestError && err.data?.errors && Array.isArray(err.data.errors)) {
          errorMessages = err.data.errors.map((e: { message: string }) => e.message);
        } else if (err instanceof Error) {
          errorMessages = [err.message];
        }

        set((state) => {
          state.isActivating = false;
        });

        // Show errors as a single toast with bullet list
        if (errorMessages.length === 1) {
          toast.error(errorMessages[0]);
        } else {
          toast.error(__('Workflow activation failed'), {
            description: errorMessages.map((msg) => `• ${msg}`).join('\n'),
          });
        }

        return false;
      }
    },

    deactivate: async () => {
      const { id, isSaving, isActivating } = get();
      if (!id || isSaving || isActivating) return false;

      set((state) => {
        state.isActivating = true;
      });

      try {
        await workflowService.deactivateWorkflow(id);
        set((state) => {
          state.isActive = false;
          state.isActivating = false;
        });
        toast.success(__('Workflow deactivated'));
        return true;
      } catch (err) {
        const errorMessage =
          err instanceof Error ? err.message : __('Failed to deactivate workflow');

        set((state) => {
          state.isActivating = false;
        });

        toast.error(errorMessage);
        return false;
      }
    },

    publish: async (notes?: string) => {
      const { id, isSaving, isPublishing } = get();
      if (!id || isSaving || isPublishing) return false;

      set((state) => {
        state.isPublishing = true;
      });

      try {
        const response = await versionService.publishWorkflow(id, notes);
        set((state) => {
          state.publishedVersionId = response.version.id;
          state.lastPublishedAt = response.version.created_at;
          state.hasUnpublishedChanges = false;
          state.isPublishing = false;
        });
        // Note: success toast is shown in FlowBuilder.handlePublish
        return true;
      } catch (err) {
        let errorMessages: string[] = [__('Failed to publish workflow')];

        if (err instanceof ApiRequestError && err.data?.errors && Array.isArray(err.data.errors)) {
          errorMessages = err.data.errors.map((e: { message: string }) => e.message);
        } else if (err instanceof Error) {
          errorMessages = [err.message];
        }

        set((state) => {
          state.isPublishing = false;
        });

        // Show errors as a single toast with bullet list
        if (errorMessages.length === 1) {
          toast.error(errorMessages[0]);
        } else {
          toast.error(__('Workflow publish failed'), {
            description: errorMessages.map((msg) => `• ${msg}`).join('\n'),
          });
        }

        return false;
      }
    },

    refreshVersionStatus: async () => {
      const { id } = get();
      if (!id) return;

      try {
        const status = await versionService.getWorkflowStatus(id);
        set((state) => {
          state.publishedVersionId = status.published_version_id;
          state.lastPublishedAt = status.last_published_at;
          state.hasUnpublishedChanges = status.has_unpublished_changes;
        });
      } catch {
        // Silently fail - version status is not critical
      }
    },

    hasNameChanged: () => {
      const { name, initialName } = get();
      return initialName !== null && name !== initialName;
    },

    isPublished: () => {
      const { publishedVersionId } = get();
      return publishedVersionId !== null;
    },

    reset: () => set(initialState),
  })),
);

// --- Granular selectors to prevent unnecessary re-renders ---

// State selectors (primitive values — stable by default)
export const useWorkflowName = () => useWorkflowStore((s) => s.name);
export const useWorkflowId = () => useWorkflowStore((s) => s.id);
export const useIsActive = () => useWorkflowStore((s) => s.isActive);
export const useIsSaving = () => useWorkflowStore((s) => s.isSaving);
export const useIsActivating = () => useWorkflowStore((s) => s.isActivating);
export const useIsPublishing = () => useWorkflowStore((s) => s.isPublishing);
export const useHasUnpublishedChanges = () => useWorkflowStore((s) => s.hasUnpublishedChanges);
export const usePublishedVersionId = () => useWorkflowStore((s) => s.publishedVersionId);

// Action selectors (grouped via useShallow for stable object identity)
export const useWorkflowActions = () =>
  useWorkflowStore(
    useShallow((s) => ({
      setName: s.setName,
      setActive: s.setActive,
      activate: s.activate,
      deactivate: s.deactivate,
      publish: s.publish,
      refreshVersionStatus: s.refreshVersionStatus,
      markAsUnpublished: s.markAsUnpublished,
      hasNameChanged: s.hasNameChanged,
    })),
  );

export const useWorkflowSetters = () =>
  useWorkflowStore(
    useShallow((s) => ({
      setId: s.setId,
      setName: s.setName,
      setActive: s.setActive,
      setIsSaving: s.setIsSaving,
      setInitialName: s.setInitialName,
      setPublishedVersionId: s.setPublishedVersionId,
      setLastPublishedAt: s.setLastPublishedAt,
      setHasUnpublishedChanges: s.setHasUnpublishedChanges,
    })),
  );
