# PROMPT 05 — Customer App APIs

## Context
In **Water Rush**, these are the APIs consumed by the **Customer mobile app**.
All routes are prefixed `/api/customer/`.
Response format: `{ "status": true/false, "message": "...", "data": ... }`

**Public routes** (no auth): sliders, categories, products, scheduled times
**Protected routes** (auth:sanctum, customer guard): addresses, cart, promo code, orders

---

## Task — Create the following under `App\Http\Controllers\Api\`

---

### 1. `SliderController`

**Route:** `GET /api/customer/sliders` — public

- Return all active sliders ordered by `sort_order` ASC
- Include full image URL

---

### 2. `CategoryController`

**Route:** `GET /api/customer/categories` — public

- Return all active categories
- Each category includes its active products (with images)
- Product images should return full URLs

---

### 3. `ProductController`

| Method | Route | Auth |
|--------|-------|------|
| GET | `/api/customer/products` | public |
| GET | `/api/customer/products/{id}` | public |

- `index`:
  - Return active products with their images and category name
  - Accept optional query param `category_id` to filter
  - Paginate (15 per page)

- `show`:
  - Return single active product with images and category
  - Return 404 if not found or inactive

---

### 4. `ScheduledTimeController`

**Route:** `GET /api/customer/scheduled-times` — public

- Return all active scheduled times (id, label, time_from, time_to)

---

### 5. `AddressController` — protected

**Routes prefix:** `/api/customer/addresses`

| Method | Route | Action |
|--------|-------|--------|
| GET | `/` | index |
| POST | `/` | store |
| PUT | `/{id}` | update |
| DELETE | `/{id}` | destroy |
| POST | `/{id}/set-default` | setDefault |

- `index`: return authenticated customer's addresses
- `store`: validate title (required), address (required), lat (required), lng (required), is_default (boolean)
  - If is_default is true → set all others to false first
- `update`: same validation, same default logic
- `destroy`: cannot delete the only address — must have at least one
- `setDefault`: set this address as default, unset all others for this customer
- All operations scoped to authenticated customer only

---

### 6. `CartController` — protected

**Routes prefix:** `/api/customer/cart`

| Method | Route | Action |
|--------|-------|--------|
| GET | `/` | index |
| POST | `/items` | addItem |
| PATCH | `/items/{id}` | updateItem |
| DELETE | `/items/{id}` | removeItem |
| DELETE | `/` | clear |

- `index`:
  - Return cart with all items
  - Each item includes: product or bundle info (title, price, image), quantity, item_subtotal
  - Return cart total at the end

- `addItem`:
  - Body: `{ product_id OR bundle_id, quantity }`
  - Validate: one of product_id/bundle_id must be present (not both)
  - If item already exists in cart → increment quantity
  - If not → create new cart item
  - Auto-create cart if customer doesn't have one yet

- `updateItem`:
  - Body: `{ quantity }` (min 1)
  - Must belong to authenticated customer's cart

- `removeItem`:
  - Delete specific cart item
  - Must belong to authenticated customer's cart

- `clear`:
  - Delete all items from customer's cart

---

### 7. `PromoCodeController` — protected

**Route:** `POST /api/customer/promo-codes/apply`

Body: `{ code }`

Validation:
- Code exists and is_active = 1
- Not expired (expires_at is null OR expires_at >= today)
- Used count < quantity

On success return:
```json
{
  "status": true,
  "message": "Promo code applied",
  "data": {
    "code": "SAVE10",
    "type": "percent",
    "discount": 10
  }
}
```

On failure return appropriate message (invalid, expired, exhausted).

---

### 8. `OrderController` — protected

| Method | Route | Action |
|--------|-------|--------|
| GET | `/api/customer/orders` | index |
| GET | `/api/customer/orders/{id}` | show |
| POST | `/api/customer/orders` | store |

#### `index`
- Return authenticated customer's orders (paginated)
- Each order: id, status, total, delivery_date, payment_method, created_at

#### `show`
- Full order details:
  - Order info (status, total, subtotal, delivery_fee, payment_method, delivery_date, notes)
  - Address (title, address, lat, lng)
  - Driver info if assigned (name, phone, vehicle_type, vehicle_number)
  - Scheduled time if selected (label, time_from, time_to)
  - Promo code if used (code, type, discount)
  - Items: each with product or bundle (title, price, image), quantity, unit_price, subtotal
- Must belong to authenticated customer

#### `store` — Place Order
Body:
```json
{
  "address_id": 1,
  "delivery_date": "2025-01-15",
  "scheduled_time_id": 2,
  "payment_method": "cod",
  "promo_code": "SAVE10"
}
```

Validation:
- `address_id`: required, must belong to authenticated customer
- `delivery_date`: required, date, not in the past
- `scheduled_time_id`: optional, must exist and be active
- `payment_method`: required, in: cod, online
- `promo_code`: optional string

Logic:
1. Get customer's cart — return error if cart is empty
2. Calculate subtotal from cart items (product price × quantity or bundle price × quantity)
3. Apply promo code if provided:
   - Validate code (active, not expired, quantity available)
   - Calculate discount amount based on type (percent or fixed)
   - Deduct from subtotal
4. Add delivery_fee (hardcode **10.00** for now)
5. Calculate total = subtotal - discount + delivery_fee
6. Create order record
7. Create order_items from cart items (copy product_id/bundle_id, quantity, unit_price at time of order)
8. Increment promo_code `used_count` if used
9. Clear all cart items after order is placed
10. Return created order with full details (same as `show`)

---

## Notes
- All image URLs must be full absolute URLs using `Storage::url()`
- All queries must be scoped to the authenticated customer (never expose other customers' data)
- Return 404 with `{ status: false, message: "Not found" }` when applicable
- Delivery fee is hardcoded as 10.00 — will be configurable later
