paths:

  # ─────────────────────────────────────────────────────────
  # ADMIN — SUBSCRIPTION PLAN MANAGEMENT
  # ─────────────────────────────────────────────────────────

  /admin/subscription-plans:
    post:
      summary: Create a subscription plan
      description: |
        SuperAdmin creates a new subscription plan available for merchants to subscribe to.

        **Key fields:**
        - `monthlyPrice` — the base price for one month's billing. The system calculates the annual price automatically using the discount.
        - `annualDiscountPercentage` — e.g. `20` means a 20% discount when billing yearly. Annual price = `monthlyPrice × 12 × (1 - discount/100)`.
        - `currency` — the currency merchants will be charged in (e.g. `NGN`, `USD`). Merchants must have sufficient wallet balance in this currency.
        - `benefits` — free-text bullet points displayed on the pricing page.
        - `includedServices` — array of SystemService codes that this plan unlocks for the merchant.
        - `transactionLimit` — max monthly transactions allowed. `null` = unlimited.
      tags: [Subscriptions — Admin]
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, monthlyPrice, currency]
              properties:
                name:
                  type: string
                  example: "Growth"
                  description: "Plan name shown to merchants (e.g. Starter, Growth, Enterprise)"
                description:
                  type: string
                  example: "Best for growing businesses with moderate transaction volumes."
                monthlyPrice:
                  type: number
                  example: 25000.00
                  description: "Base monthly price. Annual price is auto-calculated using annualDiscountPercentage."
                currency:
                  type: string
                  example: "NGN"
                  description: "Currency in which merchants are charged. Must match their wallet currency."
                annualDiscountPercentage:
                  type: number
                  example: 20.00
                  description: "Percentage discount applied when the merchant chooses yearly billing. 0 = no discount."
                  default: 0
                transactionLimit:
                  type: integer
                  nullable: true
                  example: 5000
                  description: "Max monthly transactions. null = unlimited."
                benefits:
                  type: array
                  items:
                    type: string
                  example: ["20% fee discount", "Up to 5,000 transactions/month", "Priority support"]
                  description: "Display bullet points shown to merchants on the pricing page."
                includedServices:
                  type: array
                  items:
                    type: string
                  example: ["virtual_cards", "international_payout"]
                  description: "SystemService codes this plan unlocks for the subscribing merchant."
                servicePricingOverrides:
                  type: object
                  nullable: true
                  description: "Optional JSON override for service-specific fee configs applied to this plan's subscribers."
                sortOrder:
                  type: integer
                  example: 2
                  description: "Display order on the pricing page. Lower number = shown first."
      responses:
        '201':
          description: Plan created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: "Subscription plan \"Growth\" created successfully."
                  data:
                    $ref: '#/components/schemas/SubscriptionPlan'
        '400':
          description: Missing required fields (name, monthlyPrice, or currency)
          content:
            application/json:
              example:
                success: false
                message: "name, monthlyPrice, and currency are required"

    get:
      summary: Get all subscription plans (admin view)
      description: |
        Returns **all** subscription plans including inactive ones, ordered by sortOrder then createdAt.

        > To get only active plans (merchant-facing), use `GET /merchants/subscriptions/plans`.
      tags: [Subscriptions — Admin]
      security:
        - bearerAuth: []
      responses:
        '200':
          description: List of all subscription plans
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/SubscriptionPlan'
              example:
                success: true
                data:
                  - id: "plan-uuid-1"
                    name: "Starter"
                    monthlyPrice: "5000.00"
                    currency: "NGN"
                    annualDiscountPercentage: "20.00"
                    transactionLimit: null
                    benefits: ["10% fee discount", "Up to 1,000 transactions/month"]
                    status: "active"
                    sortOrder: 1
                  - id: "plan-uuid-2"
                    name: "Growth"
                    monthlyPrice: "25000.00"
                    currency: "NGN"
                    annualDiscountPercentage: "20.00"
                    transactionLimit: 5000
                    benefits: ["20% fee discount", "Up to 5,000 transactions/month", "Priority support"]
                    status: "active"
                    sortOrder: 2

  /admin/subscription-plans/{id}:
    patch:
      summary: Update a subscription plan
      description: |
        Updates any fields on a subscription plan. Only send the fields you want to change.

        **Updatable fields:** `name`, `description`, `monthlyPrice`, `annualDiscountPercentage`,
        `currency`, `servicePricingOverrides`, `transactionLimit`, `benefits`, `includedServices`,
        `sortOrder`, `status`

        > Setting `status` to `inactive` will hide the plan from new merchants but will NOT affect existing active subscriptions.
      tags: [Subscriptions — Admin]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
            format: uuid
          description: The subscription plan UUID
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: "Growth Plus"
                description:
                  type: string
                monthlyPrice:
                  type: number
                  example: 30000.00
                annualDiscountPercentage:
                  type: number
                  example: 25.00
                currency:
                  type: string
                  example: "NGN"
                transactionLimit:
                  type: integer
                  nullable: true
                  example: 10000
                benefits:
                  type: array
                  items:
                    type: string
                  example: ["25% fee discount", "Up to 10,000 transactions/month"]
                includedServices:
                  type: array
                  items:
                    type: string
                status:
                  type: string
                  enum: [active, inactive]
                  example: "inactive"
                sortOrder:
                  type: integer
                  example: 2
      responses:
        '200':
          description: Plan updated successfully
          content:
            application/json:
              example:
                success: true
                message: "Subscription plan \"Growth Plus\" updated successfully."
                data:
                  id: "plan-uuid-2"
                  name: "Growth Plus"
                  monthlyPrice: "30000.00"
                  status: "active"
        '404':
          description: Plan not found
          content:
            application/json:
              example:
                success: false
                message: "Subscription plan not found"

    delete:
      summary: Deactivate a subscription plan
      description: |
        **Soft-deactivates** the plan by setting its `status` to `inactive`.

        - The plan will no longer appear on the merchant-facing pricing page.
        - **Existing active subscribers are NOT affected** — their subscription continues until the billing period ends.
        - Plans can be re-activated via PATCH with `{ "status": "active" }`.
      tags: [Subscriptions — Admin]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Plan deactivated successfully
          content:
            application/json:
              example:
                success: true
                message: "Subscription plan \"Growth\" has been deactivated."
        '404':
          description: Plan not found

  /admin/subscriptions/stats:
    get:
      summary: Get subscription dashboard stats
      description: |
        Returns aggregated subscription statistics for the admin dashboard:
        - Plan counts (total + active)
        - Subscription counts by status
        - Total subscription revenue (paid invoices)
        - Top 5 plans by active subscriber count
      tags: [Subscriptions — Admin]
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Subscription statistics
          content:
            application/json:
              example:
                success: true
                data:
                  plans:
                    total: 3
                    active: 3
                  subscriptions:
                    total: 47
                    active: 35
                    cancelled: 5
                    expired: 7
                  revenue:
                    total: "1250000.00"
                  topPlans:
                    - planId: "plan-uuid-1"
                      subscriberCount: "22"
                      plan:
                        name: "Starter"
                        monthlyPrice: "5000.00"
                        currency: "NGN"
                    - planId: "plan-uuid-2"
                      subscriberCount: "13"
                      plan:
                        name: "Growth"
                        monthlyPrice: "25000.00"
                        currency: "NGN"

  # ─────────────────────────────────────────────────────────
  # MERCHANT — SUBSCRIPTION LIFECYCLE
  # ─────────────────────────────────────────────────────────

  /merchants/subscriptions/plans:
    get:
      summary: Browse available subscription plans
      description: |
        Returns all **active** subscription plans. The `annualPrice` field is pre-calculated
        for display — use it to show the yearly cost before the merchant pays.

        **Frontend Note:** Call this to populate your pricing/plans page. Each plan object
        contains `monthlyPrice` (base), `annualPrice` (pre-calculated), `annualDiscountPercentage`,
        `currency`, `benefits` (bullet points), and `transactionLimit`.
      tags: [Subscriptions — Merchant]
      security:
        - bearerAuth: []
      responses:
        '200':
          description: List of active plans with pre-calculated annual pricing
          content:
            application/json:
              example:
                success: true
                data:
                  - id: "plan-uuid-1"
                    name: "Starter"
                    description: "Perfect for new businesses getting started."
                    monthlyPrice: "5000.00"
                    currency: "NGN"
                    annualDiscountPercentage: "20.00"
                    annualPrice: "48000.00"
                    transactionLimit: null
                    benefits: ["10% fee discount", "Unlimited transactions", "Email support"]
                    includedServices: []
                    sortOrder: 1
                    status: "active"
                  - id: "plan-uuid-2"
                    name: "Growth"
                    description: "Best for growing businesses."
                    monthlyPrice: "25000.00"
                    currency: "NGN"
                    annualDiscountPercentage: "20.00"
                    annualPrice: "240000.00"
                    transactionLimit: 5000
                    benefits: ["20% fee discount", "5,000 transactions/month", "Priority support"]
                    includedServices: ["virtual_cards"]
                    sortOrder: 2
                    status: "active"

  /merchants/subscriptions/me:
    get:
      summary: Get my current subscription
      description: |
        Returns the merchant's current active or cancelled (pending expiry) subscription,
        including the full plan details.

        **Frontend Note:** Call this on dashboard load to check if the merchant has an active plan.
        Use the `status` field to drive your UI:
        - `active` → show plan name, end date, benefits
        - `cancelled` → show "Expires on [endDate]" banner, offer re-subscribe option
        - `null` data → no subscription, show the pricing plans page
      tags: [Subscriptions — Merchant]
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Current subscription or null if none exists
          content:
            application/json:
              examples:
                active_subscription:
                  summary: Active subscription
                  value:
                    success: true
                    data:
                      id: "sub-uuid-1234"
                      merchantId: "merchant-uuid"
                      planId: "plan-uuid-2"
                      status: "active"
                      startDate: "2026-07-15"
                      endDate: "2026-08-15"
                      autoRenew: true
                      cancelledAt: null
                      plan:
                        id: "plan-uuid-2"
                        name: "Growth"
                        monthlyPrice: "25000.00"
                        currency: "NGN"
                        annualDiscountPercentage: "20.00"
                        transactionLimit: 5000
                        benefits: ["20% fee discount", "5,000 transactions/month", "Priority support"]
                no_subscription:
                  summary: No active subscription
                  value:
                    success: true
                    data: null
                    message: "No active subscription found. Browse available plans to get started."
                cancelled_subscription:
                  summary: Cancelled (still active until end date)
                  value:
                    success: true
                    data:
                      id: "sub-uuid-5678"
                      status: "cancelled"
                      startDate: "2026-07-01"
                      endDate: "2026-08-01"
                      autoRenew: false
                      cancelledAt: "2026-07-20T14:30:00.000Z"
                      plan:
                        name: "Starter"
                        monthlyPrice: "5000.00"
                        currency: "NGN"

  /merchants/subscriptions:
    post:
      summary: Subscribe to a plan
      description: |
        Subscribes the merchant to a plan by **immediately deducting the subscription price from their wallet balance** in the plan's currency.

        **How it works:**
        1. The merchant selects a plan and billing interval (`monthly` or `yearly`).
        2. The backend calculates the charge:
           - **Monthly:** `monthlyPrice`
           - **Yearly:** `monthlyPrice × 12 × (1 - annualDiscountPercentage/100)`
        3. The charge is deducted from the merchant's wallet in the **plan's currency** (e.g. NGN).
        4. A subscription record is created with `status: active`, `startDate: today`, and `endDate: today + 1 month or year`.
        5. An invoice is generated automatically with `paymentStatus: paid`.
        6. The subscription is immediately active — merchant benefits apply instantly.

        **Requirements:**
        - Merchant must **not** have an existing active subscription (use change-plan to switch).
        - Merchant's wallet balance must be >= the subscription price in the plan's currency.

        **Frontend Note:** Before showing the "Subscribe" button, check the merchant's balance from `GET /merchants/me` → `balance` and compare with the plan price.
      tags: [Subscriptions — Merchant]
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [planId, billingInterval]
              properties:
                planId:
                  type: string
                  format: uuid
                  example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  description: "The UUID of the plan from GET /merchants/subscriptions/plans"
                billingInterval:
                  type: string
                  enum: [monthly, yearly]
                  example: "monthly"
                  description: "'monthly' charges monthlyPrice. 'yearly' applies the annualDiscountPercentage."
            example:
              planId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
              billingInterval: "monthly"
      responses:
        '201':
          description: Subscription activated and wallet deducted
          content:
            application/json:
              example:
                success: true
                message: "Successfully subscribed to the \"Growth\" plan."
                data:
                  subscription:
                    id: "sub-uuid-new"
                    merchantId: "merchant-uuid"
                    planId: "plan-uuid-2"
                    status: "active"
                    startDate: "2026-07-25"
                    endDate: "2026-08-25"
                    autoRenew: true
                  invoice:
                    id: "inv-uuid"
                    amount: "25000.00"
                    currency: "NGN"
                    paymentMethod: "wallet"
                    paymentStatus: "paid"
                    billingPeriodStart: "2026-07-25"
                    billingPeriodEnd: "2026-08-25"
                    paidAt: "2026-07-25T09:00:00.000Z"
                  plan:
                    name: "Growth"
                    monthlyPrice: "25000.00"
                    annualDiscountPercentage: "20.00"
                  walletBalance: "75000.00"
        '400':
          description: Already subscribed OR insufficient wallet balance OR invalid billingInterval
          content:
            application/json:
              examples:
                already_subscribed:
                  summary: Merchant already has active subscription
                  value:
                    success: false
                    message: "You already have an active subscription. Use the change-plan endpoint to upgrade or downgrade."
                insufficient_balance:
                  summary: Not enough wallet balance
                  value:
                    success: false
                    message: "Insufficient wallet balance. Plan costs NGN 25000.00 but your balance is NGN 10000.00."
                invalid_interval:
                  summary: Invalid billingInterval value
                  value:
                    success: false
                    message: "billingInterval must be 'monthly' or 'yearly'"
        '404':
          description: Plan not found or inactive
          content:
            application/json:
              example:
                success: false
                message: "Subscription plan not found or inactive"

  /merchants/subscriptions/change-plan:
    patch:
      summary: Upgrade or downgrade subscription plan
      description: |
        Switches the merchant to a different plan or billing interval with **prorated pricing**.

        **How proration works:**
        1. Backend calculates how many days are remaining on the current plan.
        2. An "unused credit" is computed: `currentPlanPrice × (remainingDays / totalDays)`.
        3. Prorated cost = `newPlanPrice − unusedCredit`.
        4. **Upgrade (newPrice > oldPrice):** The prorated cost is deducted from the wallet.
        5. **Downgrade (newPrice < oldPrice):** If credit > newPrice, the surplus is **refunded to the wallet**.
        6. The old subscription is immediately expired and a new one starts today.
        7. A new invoice is created for the prorated amount.

        > You can also use this to switch billing interval on the **same plan** (e.g. monthly → yearly).
      tags: [Subscriptions — Merchant]
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [newPlanId, newBillingInterval]
              properties:
                newPlanId:
                  type: string
                  format: uuid
                  example: "b2c3d4e5-f6a7-8901-bcde-f12345678901"
                  description: "The UUID of the new plan to switch to"
                newBillingInterval:
                  type: string
                  enum: [monthly, yearly]
                  example: "yearly"
                  description: "The billing interval for the new plan"
            example:
              newPlanId: "b2c3d4e5-f6a7-8901-bcde-f12345678901"
              newBillingInterval: "yearly"
      responses:
        '200':
          description: Plan changed successfully with proration applied
          content:
            application/json:
              examples:
                upgrade:
                  summary: Upgrade example
                  value:
                    success: true
                    message: "Successfully upgraded to the \"Enterprise\" plan."
                    data:
                      subscription:
                        id: "sub-new-uuid"
                        status: "active"
                        startDate: "2026-07-25"
                        endDate: "2026-08-25"
                      previousPlan: "Growth"
                      newPlan: "Enterprise"
                      proratedCost: "15000.00"
                      walletBalance: "60000.00"
                downgrade:
                  summary: Downgrade example (credit returned to wallet)
                  value:
                    success: true
                    message: "Successfully downgraded to the \"Starter\" plan."
                    data:
                      previousPlan: "Growth"
                      newPlan: "Starter"
                      proratedCost: "0.00"
                      walletBalance: "85000.00"
        '400':
          description: No active subscription, insufficient balance for upgrade, or same plan/interval
          content:
            application/json:
              examples:
                no_subscription:
                  value:
                    success: false
                    message: "No active subscription to change. Subscribe first."
                same_plan:
                  value:
                    success: false
                    message: "You are already subscribed to this plan with this billing interval."
                insufficient_balance:
                  value:
                    success: false
                    message: "Insufficient balance for upgrade. Prorated cost is NGN 15000.00."

  /merchants/subscriptions/cancel:
    post:
      summary: Cancel subscription
      description: |
        Cancels the merchant's active subscription.

        **Important:** Cancellation does **NOT** immediately remove access.
        - `autoRenew` is set to `false` — the plan will NOT renew at end of billing period.
        - The merchant keeps full plan benefits until `endDate`.
        - After `endDate`, the system automatically expires the subscription.

        **Frontend Note:** Show the `expiresOn` date in a banner so the merchant knows they still have access.
      tags: [Subscriptions — Merchant]
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Subscription cancelled — benefits remain until end date
          content:
            application/json:
              example:
                success: true
                message: "Subscription cancelled. Your \"Growth\" plan benefits remain active until 2026-08-25."
                data:
                  planName: "Growth"
                  expiresOn: "2026-08-25"
                  feeDiscountPercent: "20.00"
        '400':
          description: No active subscription to cancel
          content:
            application/json:
              example:
                success: false
                message: "No active subscription to cancel."

  /merchants/subscriptions/history:
    get:
      summary: Get subscription history
      description: |
        Returns all past and current subscriptions for the merchant, ordered newest first.
        Each record includes the plan details and (if it was a plan change) the previous plan name.
      tags: [Subscriptions — Merchant]
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Full subscription history
          content:
            application/json:
              example:
                success: true
                data:
                  - id: "sub-uuid-current"
                    status: "active"
                    startDate: "2026-07-25"
                    endDate: "2026-08-25"
                    autoRenew: true
                    plan:
                      name: "Growth"
                      monthlyPrice: "25000.00"
                      currency: "NGN"
                    previousPlan:
                      name: "Starter"
                  - id: "sub-uuid-expired"
                    status: "expired"
                    startDate: "2026-06-01"
                    endDate: "2026-07-01"
                    autoRenew: false
                    plan:
                      name: "Starter"
                      monthlyPrice: "5000.00"
                      currency: "NGN"
                    previousPlan: null

  /merchants/subscriptions/invoices:
    get:
      summary: Get subscription invoices (billing receipts)
      description: |
        Returns all payment records generated when the merchant subscribed or changed plans.
        Ordered newest first. Each invoice includes the plan name, amount, currency, billing period, and payment status.
      tags: [Subscriptions — Merchant]
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Invoice list
          content:
            application/json:
              example:
                success: true
                data:
                  - id: "inv-uuid-1"
                    subscriptionId: "sub-uuid-current"
                    amount: "25000.00"
                    currency: "NGN"
                    paymentMethod: "wallet"
                    paymentStatus: "paid"
                    billingPeriodStart: "2026-07-25"
                    billingPeriodEnd: "2026-08-25"
                    paidAt: "2026-07-25T09:00:00.000Z"
                    plan:
                      name: "Growth"
                  - id: "inv-uuid-2"
                    subscriptionId: "sub-uuid-expired"
                    amount: "5000.00"
                    currency: "NGN"
                    paymentMethod: "wallet"
                    paymentStatus: "paid"
                    billingPeriodStart: "2026-06-01"
                    billingPeriodEnd: "2026-07-01"
                    paidAt: "2026-06-01T10:00:00.000Z"
                    plan:
                      name: "Starter"

components:
  schemas:
    SubscriptionPlan:
      type: object
      description: "A subscription plan created by the admin that merchants can subscribe to."
      properties:
        id:
          type: string
          format: uuid
          example: "plan-uuid-1"
        name:
          type: string
          example: "Growth"
        description:
          type: string
          example: "Best for growing businesses with moderate transaction volumes."
        monthlyPrice:
          type: string
          example: "25000.00"
          description: "Base monthly price in the plan's currency."
        currency:
          type: string
          example: "NGN"
          description: "Currency in which merchants are charged."
        annualDiscountPercentage:
          type: string
          example: "20.00"
          description: "Discount when merchant chooses yearly billing."
        annualPrice:
          type: string
          example: "240000.00"
          description: "Pre-calculated annual price. Only present in merchant-facing GET /plans response."
        transactionLimit:
          type: integer
          nullable: true
          example: 5000
          description: "Max monthly transactions. null = unlimited."
        benefits:
          type: array
          items:
            type: string
          example: ["20% fee discount", "5,000 transactions/month", "Priority support"]
          description: "Bullet-point benefits shown on the pricing page."
        includedServices:
          type: array
          items:
            type: string
          example: ["virtual_cards", "international_payout"]
          description: "SystemService codes this plan unlocks."
        servicePricingOverrides:
          type: object
          nullable: true
          description: "Optional custom fee configs applied to subscribers of this plan."
        sortOrder:
          type: integer
          example: 2
          description: "Display order on the pricing page."
        status:
          type: string
          enum: [active, inactive]
          example: "active"
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
