# Workflow State Machine Documentation

## Overview

The Workflow State Machine manages the complete lifecycle of translation jobs through a structured 6-state workflow with comprehensive validation, logging, and event hooks.

## States

### 1. Draft
**Initial state for all translations**
- Translation is being worked on
- Not yet ready for review
- Can be edited freely by translator

### 2. Pending Review
**Submitted for review**
- Translation completed by translator
- Waiting for reviewer assignment
- Cannot be edited without going back to draft

### 3. In Review
**Actively being reviewed**
- Assigned to reviewer
- Under quality assessment
- Can be approved, rejected, or sent back to draft

### 4. Approved
**Passed quality review**
- Translation meets quality standards
- Ready for publication
- Waiting for final publish action

### 5. Rejected
**Failed quality review**
- Issues found during review
- Must be revised before resubmission
- Can only transition back to draft

### 6. Published
**Live and active**
- Translation is publicly visible
- Can be revised if updates needed
- Revision creates new workflow cycle

## State Transitions

### Valid Transitions

```
draft → pending_review
pending_review → in_review
pending_review → draft
pending_review → rejected
in_review → approved
in_review → rejected
in_review → draft
approved → published
approved → rejected
rejected → draft
published → draft
```

### Transition Flow Diagram

```
┌─────────┐
│  Draft  │────────────────────┐
└────┬────┘                    │
     │                         │
     ↓                         │
┌──────────────┐               │
│Pending Review│◄──────────────┤
└──────┬───────┘               │
       │                       │
       ↓                       │
┌──────────┐                   │
│In Review │◄──────────────────┤
└─────┬────┘                   │
      │                        │
      ↓                        │
┌──────────┐                   │
│ Approved │                   │
└─────┬────┘                   │
      │                        │
      ↓                        │
┌───────────┐                  │
│ Published │──────────────────┘
└───────────┘

Any State → Rejected → Draft
```

## Usage

### Basic Transition

```php
use MultilingualPressZone\Workflow\StateMachine;
use MultilingualPressZone\Entities\Translation;

$state_machine = new StateMachine();
$translation = new Translation(['id' => 123, ...]);
$user_id = get_current_user_id();

// Submit for review
$state_machine->transition(
    $translation,
    'pending_review',
    $user_id,
    'Translation completed and ready for review'
);
```

### Initialize New Translation

```php
// Initialize workflow state for new translation
$state_machine->initializeState($translation, $user_id);
```

### Check Available Transitions

```php
// Get current state
$current_state = $state_machine->getCurrentState($translation);

// Check if transition is allowed
if ($state_machine->canTransition($translation, 'approved')) {
    // Proceed with transition
}

// Get all available transitions
$available = $state_machine->getAvailableTransitions($translation);
// Returns: ['in_review', 'draft', 'rejected']
```

### View State History

```php
// Get complete state history
$history = $state_machine->getStateHistory($translation);

foreach ($history as $entry) {
    echo sprintf(
        "%s → %s by User %d at %s\n",
        $entry['from_state'] ?? 'initial',
        $entry['to_state'],
        $entry['user_id'],
        $entry['created_at']
    );

    if (!empty($entry['notes'])) {
        echo "  Notes: {$entry['notes']}\n";
    }
}
```

### Bulk Transitions

```php
// Transition multiple translations at once
$translations = [
    new Translation(['id' => 1, ...]),
    new Translation(['id' => 2, ...]),
    new Translation(['id' => 3, ...]),
];

$result = $state_machine->bulkTransition(
    $translations,
    'pending_review',
    $user_id,
    'Bulk submission for review'
);

echo "Success: {$result['success']}\n";
echo "Failed: {$result['failed']}\n";
echo "Total: {$result['total']}\n";

if (!empty($result['errors'])) {
    foreach ($result['errors'] as $error) {
        echo "  - {$error}\n";
    }
}
```

### State Statistics

```php
// Get counts of translations in each state
$stats = $state_machine->getStateStatistics();

foreach ($stats as $state => $count) {
    echo "{$state}: {$count} translations\n";
}

// Output:
// draft: 45 translations
// pending_review: 12 translations
// in_review: 8 translations
// approved: 3 translations
// rejected: 5 translations
// published: 234 translations
```

## Permissions

### Required Capabilities

| Transition Type | Required Capability | Description |
|----------------|-------------------|-------------|
| Submit | `edit_posts` | Submit own translations for review |
| Review | `edit_others_posts` | Start reviewing translations |
| Approve | `publish_posts` | Approve translations |
| Publish | `publish_posts` | Publish approved translations |
| Reject | `edit_others_posts` | Reject translations during review |
| Revise | `edit_posts` | Move back to draft for revision |

### Checking Permissions

```php
// Automatically checked during transition
try {
    $state_machine->transition($translation, 'approved', $user_id);
} catch (\RuntimeException $e) {
    // User doesn't have permission
    echo "Permission denied: " . $e->getMessage();
}
```

## Events & Hooks

### General Hooks

#### Before Transition
```php
add_action('mpz_before_state_transition', function($translation, $from, $to, $user_id) {
    // Fired before any state transition
    error_log("Transitioning from {$from} to {$to}");
}, 10, 4);
```

#### After Transition
```php
add_action('mpz_after_state_transition', function($translation, $from, $to, $user_id) {
    // Fired after successful state transition
    error_log("Successfully transitioned from {$from} to {$to}");
}, 10, 4);
```

#### State Change Notification
```php
add_action('mpz_workflow_state_changed', function($translation, $from, $to, $user_id) {
    // Fired for notification purposes
    // Send email, push notification, etc.
}, 10, 4);
```

### State-Specific Hooks

#### Transition to Specific State
```php
add_action('mpz_transition_to_pending_review', function($translation, $from, $user_id) {
    // Fired when entering pending_review state
    // Notify reviewers
}, 10, 3);

add_action('mpz_transition_to_published', function($translation, $from, $user_id) {
    // Fired when entering published state
    // Clear caches, update search index, etc.
}, 10, 3);
```

#### Review Requested
```php
add_action('mpz_workflow_review_requested', function($translation, $user_id) {
    // Send email to reviewers
    $reviewers = get_users(['role' => 'editor']);
    foreach ($reviewers as $reviewer) {
        wp_mail(
            $reviewer->user_email,
            'New translation ready for review',
            sprintf('Translation #%d needs review', $translation->getId())
        );
    }
}, 10, 2);
```

#### Translation Approved
```php
add_action('mpz_workflow_translation_approved', function($translation, $user_id) {
    // Notify translator of approval
    $translator_id = $translation->getCreatedBy();
    $translator = get_user_by('id', $translator_id);

    wp_mail(
        $translator->user_email,
        'Translation approved',
        'Your translation has been approved!'
    );
}, 10, 2);
```

#### Translation Rejected
```php
add_action('mpz_workflow_translation_rejected', function($translation, $user_id) {
    // Notify translator of rejection
    // Send feedback from notes
    $history = $state_machine->getStateHistory($translation);
    $rejection = $history[0];

    // Send email with rejection notes
}, 10, 2);
```

#### Translation Published
```php
add_action('mpz_workflow_translation_published', function($translation, $user_id) {
    // Clear relevant caches
    wp_cache_delete('translation_' . $translation->getId());

    // Update search index
    do_action('mpz_update_search_index', $translation);
}, 10, 2);
```

## Database Schema

### workflow_states Table

```sql
CREATE TABLE wp_mpz_workflow_states (
    id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    translation_id BIGINT(20) UNSIGNED NOT NULL,
    from_state VARCHAR(50) DEFAULT NULL,
    to_state VARCHAR(50) NOT NULL,
    user_id BIGINT(20) UNSIGNED NOT NULL,
    notes TEXT DEFAULT NULL,
    created_at DATETIME NOT NULL,

    KEY idx_translation (translation_id),
    KEY idx_user (user_id),
    KEY idx_state (to_state),
    KEY idx_created (created_at),
    KEY idx_translation_created (translation_id, created_at)
);
```

## Error Handling

### Invalid State Exception
```php
try {
    $state_machine->transition($translation, 'invalid_state', $user_id);
} catch (\InvalidArgumentException $e) {
    // Invalid state provided
    echo "Error: " . $e->getMessage();
}
```

### Invalid Transition Exception
```php
try {
    // Try to skip states
    $state_machine->transition($translation, 'published', $user_id);
} catch (\InvalidArgumentException $e) {
    // Invalid transition path
    echo "Cannot transition from draft directly to published";
}
```

### Permission Exception
```php
try {
    $state_machine->transition($translation, 'approved', $user_id);
} catch (\RuntimeException $e) {
    // User lacks required capability
    echo "Insufficient permissions";
}
```

### Transaction Failure
```php
try {
    $state_machine->transition($translation, 'pending_review', $user_id);
} catch (\RuntimeException $e) {
    // Database error or transaction failure
    error_log('State transition failed: ' . $e->getMessage());
}
```

## Best Practices

### 1. Always Check Permissions First
```php
if (!current_user_can('publish_posts')) {
    wp_die('Insufficient permissions');
}

$state_machine->transition($translation, 'approved', $user_id);
```

### 2. Provide Meaningful Notes
```php
// Good: Descriptive notes
$state_machine->transition(
    $translation,
    'rejected',
    $user_id,
    'Grammar errors in paragraphs 2-5. Please review verb tenses.'
);

// Bad: Vague notes
$state_machine->transition(
    $translation,
    'rejected',
    $user_id,
    'not good'
);
```

### 3. Use Bulk Operations for Multiple Translations
```php
// Good: Single bulk operation
$result = $state_machine->bulkTransition($translations, 'pending_review', $user_id);

// Bad: Individual transitions in loop
foreach ($translations as $translation) {
    $state_machine->transition($translation, 'pending_review', $user_id);
}
```

### 4. Handle Errors Gracefully
```php
try {
    $state_machine->transition($translation, $new_state, $user_id, $notes);

    wp_send_json_success([
        'message' => 'Transition successful',
        'new_state' => $new_state
    ]);

} catch (\InvalidArgumentException $e) {
    wp_send_json_error([
        'message' => 'Invalid transition: ' . $e->getMessage()
    ], 400);

} catch (\RuntimeException $e) {
    wp_send_json_error([
        'message' => 'Transition failed: ' . $e->getMessage()
    ], 500);
}
```

### 5. Monitor State History
```php
// Add logging for audit trail
add_action('mpz_after_state_transition', function($translation, $from, $to, $user_id) {
    error_log(sprintf(
        'Translation %d transitioned from %s to %s by user %d at %s',
        $translation->getId(),
        $from,
        $to,
        $user_id,
        current_time('mysql')
    ));
}, 10, 4);
```

## REST API Integration

### Transition Endpoint
```php
// In REST controller
public function transition_state(\WP_REST_Request $request): \WP_REST_Response {
    $translation_id = $request->get_param('translation_id');
    $new_state = $request->get_param('state');
    $notes = $request->get_param('notes') ?? '';

    $translation = $this->get_translation($translation_id);
    $user_id = get_current_user_id();

    try {
        $state_machine = new StateMachine();
        $state_machine->transition($translation, $new_state, $user_id, $notes);

        return new \WP_REST_Response([
            'success' => true,
            'state' => $state_machine->getCurrentState($translation),
            'available_transitions' => $state_machine->getAvailableTransitions($translation)
        ], 200);

    } catch (\Exception $e) {
        return new \WP_REST_Response([
            'success' => false,
            'error' => $e->getMessage()
        ], 400);
    }
}
```

## Testing

### Unit Tests
```bash
# Run unit tests
vendor/bin/phpunit tests/unit/Workflow/StateMachineTest.php
```

### Integration Tests
```bash
# Run integration tests with WP-CLI
wp eval-file tests/integration/WorkflowIntegrationTest.php
```

## Performance Considerations

### Indexes
The `workflow_states` table includes optimized indexes:
- `idx_translation`: Fast lookups by translation
- `idx_translation_created`: Fast history queries
- `idx_state`: State-based statistics queries

### Caching
State history is not cached by default. For frequently accessed translations, consider:

```php
$cache_key = 'workflow_history_' . $translation->getId();
$history = wp_cache_get($cache_key);

if ($history === false) {
    $history = $state_machine->getStateHistory($translation);
    wp_cache_set($cache_key, $history, '', 3600);
}
```

### Bulk Operations
Always use `bulkTransition()` for multiple translations to reduce database round-trips and improve performance.

## Migration

The workflow states table is created by migration `Migration002CreateWorkflowStatesTable`.

### Run Migration
```bash
# Migrations are automatically run on plugin activation
# Or manually run:
wp eval-file includes/Core/Migrations.php
```

## Troubleshooting

### Issue: Transitions Not Working
**Check:**
1. User has required capability
2. Transition is valid (use `canTransition()`)
3. Database table exists
4. No PHP errors in logs

### Issue: State History Empty
**Check:**
1. Translation ID is valid
2. State was initialized with `initializeState()`
3. Database table has records

### Issue: Permission Denied
**Check:**
1. User role has required capability
2. Correct user ID is passed
3. WordPress capabilities are properly configured
