########################################
# CUSTOMERS MODULE & LOYALTY POINTS (العملاء + نقاط العملاء)
########################################

We want to:

1) Add a main sidebar group called "عملاء" after "التسويق".
2) Under "عملاء", add:
   - "عملاء" (customers list)
   - "نقاط العملاء" (loyalty points report)

3) Implement a loyalty points model that:
   - Tracks points earned by customers from orders/appointments.
   - Tracks expiry dates for points.
   - Provides reports:
     - Current points balance per customer.
     - Points that will expire.
     - Full transaction history of points per customer.

We already have a Customers module (clients) and Loyalty Settings (إعدادات الولاء) under "التسويق".
Loyalty **settings** (rules) stay under "التسويق".
Loyalty **points** (earned by customers) belong under "عملاء" as "نقاط العملاء".


========================================
# 1) SIDEBAR: "عملاء" + "نقاط العملاء"
========================================

Update sidebar navigation:

- After the "التسويق" group, add a new top-level group:
  - Title: "عملاء" (Customers)
  - Icon: people/users icon (if available)
  - Collapsible dropdown.

Under "عملاء", add:

1) "عملاء"
   - Links to the existing customers/clients list page
     (for example: `/customers` or `/clients`).

2) "نقاط العملاء"
   - Links to a new loyalty points report page
     (for example: `/customers/loyalty-points`).

Keep RTL layout and do not change the existing "المبيعات" or "التسويق" sections.
Loyalty settings ("إعدادات الولاء") remain under "التسويق".


========================================
# 2) LOYALTY SETTINGS (إعدادات الولاء) – REFERENCE
========================================

Assume we have (or create) a settings entry that defines how points are earned, for example:

- key: "loyalty_points_per_amount"
  - value: 100          // e.g. 1 point for each 100 SAR
- key: "loyalty_points_expiry_months"
  - value: 12           // points expire after 12 months

These settings are managed from "إعدادات الولاء" under the "التسويق" module.
We will just READ them here when creating loyalty transactions.


========================================
# 3) LOYALTY POINTS DATA MODEL
========================================

We will implement a transaction-based model:
- Each change in points (earn, spend, adjust, expire) is a row.
- Current balance is the sum of all non-expired transactions.

### Table: loyalty_point_transactions
Fields:
- id (integer, primary key, auto increment)
- customer_id (integer, foreign key to customers.id)   // العميل
- transaction_date (datetime, not null)                // تاريخ الحركة
- source_type (string, not null)                       // "order", "appointment", "manual_adjustment", "expiry"
- source_id (integer, nullable)                        // رقم الطلب أو الحجز إن وجد
- points_change (integer, not null)                    // عدد النقاط: موجب = كسب, سالب = خصم أو انتهاء
- points_before (integer, not null, default 0)         // رصيد قبل الحركة (اختياري لكن مفيد)
- points_after (integer, not null, default 0)          // رصيد بعد الحركة
- expiry_date (date, nullable)                         // تاريخ انتهاء هذه النقاط (للنقاط المكتسبة)
- note (string, nullable)                              // ملاحظة، مثلا: "طلب رقم SO-0001"
- created_at (datetime)
- updated_at (datetime)

Behavior:
- For "earn" operations (from orders/appointments):
  - points_change > 0
  - expiry_date = transaction_date + N months (from loyalty settings).
- For "expiry" operations:
  - points_change < 0
  - source_type = "expiry"
  - source_id can be null or reference batch/group.

We can compute points_before and points_after inside the same transaction by:
- Fetching current balance before inserting.
- points_after = points_before + points_change.


========================================
# 4) EARNING POINTS FROM ORDERS/APPOINTMENTS
========================================

When an order or appointment is COMPLETED, and loyalty is enabled:

- Determine the customer_id.
- Determine the total eligible amount for points:
  - For now, use the order total_amount (after discounts and VAT) or a configurable base.
- Read loyalty settings:
  - points_per_amount = read "loyalty_points_per_amount" (e.g. 100 SAR per 1 point).
- Calculate earned_points = floor(total_amount / points_per_amount).
- If earned_points > 0:
  - Compute expiry_date:
    - months = read "loyalty_points_expiry_months" (e.g. 12 months).
    - expiry_date = transaction_date + months.
  - Insert into loyalty_point_transactions:
    - customer_id = order.customer_id
    - transaction_date = order.completed_at or now
    - source_type = "order"
    - source_id = order.id
    - points_change = earned_points
    - expiry_date = expiry_date
    - note = "اكتساب نقاط من طلب رقم [order_number]"
    - points_before / points_after computed based on existing balance.

This should also work similarly for appointments (if we allow points from appointments), with:
- source_type = "appointment"
- source_id = appointment.id
- note = "اكتساب نقاط من حجز رقم [appointment_number]"


========================================
# 5) EXPIRING POINTS
========================================

We need a basic process (can be a simple endpoint for now) to expire points whose expiry_date < today.

Implement:

### Endpoint: POST /loyalty/expire-points
- This will:
  - Find all positive loyalty_point_transactions (earnings) where:
    - expiry_date < today
    - and the remaining unexpired portion > 0 (if partial consumption is implemented later).
  - For a simple version, we can assume points are not partially consumed and just expire the remaining balance.

Basic approach:
- Compute customer current balance and total expired to date.
- For points expiring, create a negative transaction:

  - source_type = "expiry"
  - source_id = null
  - points_change = -N (amount to expire)
  - note = "انتهاء صلاحية النقاط"

This logic can be simplified initially:
- For each customer:
  - total_expired_now = sum of points from transactions where expiry_date < today and not yet expired.
  - Insert one negative transaction per customer.

You can keep the first version simple & document it in comments.

========================================
# 6) LOYALTY REPORTS ("نقاط العملاء" PAGE)
========================================

We need two main APIs:

----------------------------------------
### 6.1 Summary per customer
----------------------------------------

GET /customers/loyalty-summary

Returns a list of customers, each with:
- customer_id
- customer_name
- total_points_balance             // current usable points
- points_expiring_soon             // e.g. points with expiry_date within the next 30 days
- last_transaction_date            // آخر حركة نقاط

Implementation idea:
- current_date = today.
- balance = sum(points_change) for this customer where:
  - expiry_date is null OR expiry_date >= today.
- points_expiring_soon = sum(points_change) where:
  - expiry_date between today and (today + 30 days).
- last_transaction_date = max(transaction_date).

Return as JSON list to be displayed in "نقاط العملاء" page.

----------------------------------------
### 6.2 Detailed history per customer
----------------------------------------

GET /customers/:id/loyalty-transactions

Returns:
- All loyalty_point_transactions for this customer ordered by transaction_date descending:
  - id
  - transaction_date
  - source_type
  - source_id
  - points_change
  - points_before
  - points_after
  - expiry_date
  - note

This is the "حركة كل نقطة مكتسبة" report.

Example output row in Arabic UI:
- "بتاريخ 2025-10-01: +1 نقطة من طلب رقم SO-0001 (الرصيد بعد الحركة: 15 نقطة)"

Use Arabic error messages:
- "العميل غير موجود"
- "لا توجد حركات نقاط لهذا العميل"


========================================
# 7) MANUAL ADJUSTMENTS (اختياري)
========================================

Add an endpoint to allow admin to manually add or deduct points:

POST /customers/:id/loyalty-adjust
Request example:
{
  "points_change": 10,
  "note": "تعويض عن مشكلة في الطلب"
}

- source_type = "manual_adjustment"
- source_id = null
- expiry_date:
  - If points_change > 0 → use default expiry (settings).
  - If points_change < 0 → no expiry_date needed.

Return updated balance.


========================================
# 8) VALIDATION & ARABIC MESSAGES
========================================

Add Arabic validation messages such as:
- "العميل غير موجود"
- "إعدادات الولاء غير معرفة" (if settings missing)
- "عدد النقاط يجب أن يكون رقم صحيح"
- "لا توجد نقاط كافية للخصم"
- "لا توجد حركات نقاط لهذا العميل"

Make sure the code is modular:
- Routes under something like: `src/routes/loyalty` or `src/routes/customers/`
- Controllers/services under: `src/services/loyalty`, `src/controllers/loyalty`.

Finally, ensure:
- Sidebar group "عملاء" appears after "التسويق"
- "نقاط العملاء" page uses the summary API (and optionally links to the detailed history per customer).
