# Custom Task Status Reorder Endpoint

## Overview

This document describes the PATCH endpoint for reordering custom task statuses within a project. The endpoint allows coordinators and administrators to change the display order of custom task statuses.

## Endpoint

```
PATCH /projects/{project_id}/task-statuses/reorder
```

## Authentication

Requires JWT authentication with coordinator or admin role.

## Request

### Path Parameters

- `project_id` (integer, required): The ID of the project

### Request Body

```json
{
  "status_ids": ["custom_abc123", "custom_def456", "custom_ghi789"]
}
```

**Fields:**
- `status_ids` (array of strings, required): Ordered list of status IDs in the desired sequence
  - Must contain all existing custom status IDs for the project
  - Cannot contain duplicates
  - Cannot be empty

## Response

### Success Response (200 OK)

```json
{
  "message": "Custom task statuses reordered successfully",
  "status": null,
  "all_statuses": {
    "statuses": [
      {
        "id": "custom_abc123",
        "name": "Review",
        "color": "#9333EA",
        "order": 0,
        "is_default": false
      },
      {
        "id": "custom_def456",
        "name": "Blocked",
        "color": "#DC2626",
        "order": 1,
        "is_default": true
      },
      {
        "id": "custom_ghi789",
        "name": "Ready for Delivery",
        "color": "#059669",
        "order": 2,
        "is_default": false
      }
    ],
    "system_statuses": [
      {
        "id": "not_started",
        "name": "Not Started",
        "color": "#6B7280",
        "is_system": true
      },
      {
        "id": "in_progress",
        "name": "In Progress",
        "color": "#3B82F6",
        "is_system": true
      },
      {
        "id": "submitted",
        "name": "Submitted",
        "color": "#F59E0B",
        "is_system": true
      },
      {
        "id": "approved",
        "name": "Approved",
        "color": "#10B981",
        "is_system": true
      },
      {
        "id": "retake",
        "name": "Retake",
        "color": "#EF4444",
        "is_system": true
      }
    ],
    "default_status_id": "custom_def456"
  }
}
```

### Error Responses

#### 400 Bad Request - Missing Status IDs

```json
{
  "detail": "Missing status IDs in reorder request: custom_xyz999"
}
```

Occurs when the request doesn't include all existing custom status IDs.

#### 400 Bad Request - Invalid Status IDs

```json
{
  "detail": "Status IDs not found: invalid_id_12345"
}
```

Occurs when the request includes status IDs that don't exist in the project.

#### 403 Forbidden

```json
{
  "detail": "Insufficient permissions"
}
```

Occurs when the user doesn't have coordinator or admin role.

#### 404 Not Found

```json
{
  "detail": "Project not found"
}
```

Occurs when the specified project doesn't exist.

#### 422 Unprocessable Entity - Duplicate IDs

```json
{
  "detail": "1 validation error for CustomTaskStatusReorder\nstatus_ids\n  Value error, Status IDs list contains duplicates"
}
```

Occurs when the request contains duplicate status IDs.

#### 422 Unprocessable Entity - Empty List

```json
{
  "detail": "1 validation error for CustomTaskStatusReorder\nstatus_ids\n  Value error, Status IDs list cannot be empty"
}
```

Occurs when the request contains an empty status_ids array.

## Implementation Details

### Validation

1. **Project Existence**: Verifies the project exists
2. **Permission Check**: Ensures user has coordinator or admin role
3. **Complete List**: Validates that all existing custom status IDs are included
4. **No Missing IDs**: Ensures no status IDs are omitted
5. **No Invalid IDs**: Ensures all provided IDs exist in the project
6. **No Duplicates**: Validates the list contains no duplicate IDs (handled by Pydantic schema)

### Order Update Process

1. Parse and validate the reorder request
2. Retrieve existing custom statuses from the project
3. Create a mapping of status_id to status data
4. Reorder statuses according to the provided list
5. Update the `order` field for each status (0-indexed)
6. Save the reordered list to the database
7. Use `flag_modified()` to ensure JSON column changes are persisted

### Database Changes

- Updates the `custom_task_statuses` JSON column in the `projects` table
- Each status object's `order` field is updated to match its position in the new list
- Uses SQLAlchemy's `flag_modified()` to ensure JSON column changes are detected

## Usage Examples

### Python (requests)

```python
import requests

# Login and get token
response = requests.post(
    "http://localhost:8000/auth/login",
    json={"email": "admin@vfx.com", "password": "admin123"}
)
token = response.json()["access_token"]

# Reorder statuses
headers = {"Authorization": f"Bearer {token}"}
data = {
    "status_ids": [
        "custom_abc123",
        "custom_def456",
        "custom_ghi789"
    ]
}

response = requests.patch(
    "http://localhost:8000/projects/1/task-statuses/reorder",
    headers=headers,
    json=data
)

if response.status_code == 200:
    result = response.json()
    print(f"✅ {result['message']}")
    print(f"Reordered {len(result['all_statuses']['statuses'])} statuses")
else:
    print(f"❌ Error: {response.json()['detail']}")
```

### JavaScript (fetch)

```javascript
// Assuming you have a token from login
const token = "your_jwt_token_here";

const reorderStatuses = async (projectId, statusIds) => {
  const response = await fetch(
    `http://localhost:8000/projects/${projectId}/task-statuses/reorder`,
    {
      method: 'PATCH',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        status_ids: statusIds
      })
    }
  );

  if (response.ok) {
    const result = await response.json();
    console.log('✅', result.message);
    return result.all_statuses;
  } else {
    const error = await response.json();
    console.error('❌ Error:', error.detail);
    throw new Error(error.detail);
  }
};

// Usage
const statusIds = [
  'custom_abc123',
  'custom_def456',
  'custom_ghi789'
];

reorderStatuses(1, statusIds)
  .then(allStatuses => {
    console.log('New order:', allStatuses.statuses);
  })
  .catch(error => {
    console.error('Failed to reorder:', error);
  });
```

## Frontend Integration

### Drag-and-Drop Implementation

The frontend should implement drag-and-drop functionality using a library like `vue-draggable-next`:

1. Display statuses in their current order
2. Allow users to drag statuses to reorder them
3. On drop, collect the new order of status IDs
4. Call the reorder endpoint with the new order
5. Update the UI optimistically or wait for the response
6. Handle errors by reverting to the previous order

### Example Vue Component

```vue
<template>
  <draggable
    v-model="statuses"
    @end="handleReorder"
    item-key="id"
  >
    <template #item="{ element }">
      <div class="status-item">
        <span class="drag-handle">⋮⋮</span>
        <span :style="{ color: element.color }">
          {{ element.name }}
        </span>
      </div>
    </template>
  </draggable>
</template>

<script setup>
import { ref } from 'vue';
import draggable from 'vuedraggable';
import { reorderTaskStatuses } from '@/services/customTaskStatus';

const props = defineProps({
  projectId: Number,
  initialStatuses: Array
});

const statuses = ref([...props.initialStatuses]);

const handleReorder = async () => {
  const statusIds = statuses.value.map(s => s.id);
  
  try {
    const result = await reorderTaskStatuses(props.projectId, statusIds);
    // Update with server response
    statuses.value = result.all_statuses.statuses;
  } catch (error) {
    // Revert to original order on error
    statuses.value = [...props.initialStatuses];
    console.error('Failed to reorder:', error);
  }
};
</script>
```

## Testing

A comprehensive test script is available at `backend/test_reorder_custom_task_status.py` that tests:

1. ✅ Successful reordering (reversing order)
2. ✅ Order field updates correctly
3. ✅ Rejection of incomplete status lists
4. ✅ Rejection of invalid status IDs
5. ✅ Rejection of duplicate status IDs

Run the test with:

```bash
cd backend
python test_reorder_custom_task_status.py
```

## Requirements Validation

This endpoint satisfies the following requirements from the custom task status specification:

- **Requirement 4.1**: ✅ Displays statuses in their defined order
- **Requirement 4.2**: ✅ Updates the order when user reorders statuses
- **Requirement 4.3**: ✅ Updates display order in all dropdowns and filters
- **Requirement 4.4**: ✅ Validates all status IDs are present

## Related Endpoints

- `GET /projects/{project_id}/task-statuses` - Get all task statuses
- `POST /projects/{project_id}/task-statuses` - Create a custom status
- `PUT /projects/{project_id}/task-statuses/{status_id}` - Update a custom status
- `DELETE /projects/{project_id}/task-statuses/{status_id}` - Delete a custom status

## Notes

- System statuses (not_started, in_progress, submitted, approved, retake) cannot be reordered
- Only custom statuses can be reordered
- The order field is 0-indexed
- Reordering does not affect the default status designation
- The endpoint uses `flag_modified()` to ensure JSON column changes are persisted to the database
