paths:
  # ─────────────────────────────────────────────────────────────────
  # Admin Card Management
  # ─────────────────────────────────────────────────────────────────

  /admin/merchants/{merchantId}/cards:
    get:
      summary: List all cards under a merchant
      description: |
        Returns all virtual cards belonging to all customers of a specific merchant.
        A customer can have multiple cards — all are returned and grouped with customer info.
        Supports pagination and status filtering.
        
        **Any authenticated Admin.**
      tags: [Admin - Card Management]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: merchantId
          required: true
          schema:
            type: string
            format: uuid
            example: "m1m2m3m4-m5m6-m7m8-m9m0-m1m2m3m4m5m6"
        - in: query
          name: page
          schema: { type: integer, default: 1 }
        - in: query
          name: limit
          schema: { type: integer, default: 50 }
        - in: query
          name: status
          schema:
            type: string
            enum: [active, frozen, terminated]
          description: Filter by card status
      responses:
        '200':
          description: List of cards across all merchant customers
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  merchant:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      businessName:
                        type: string
                        example: "TechPay Ltd"
                  total:
                    type: integer
                    example: 24
                  pages:
                    type: integer
                    example: 1
                  currentPage:
                    type: integer
                    example: 1
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/CardWithCustomer'
        '404':
          description: Merchant not found

  /admin/customers/{customerId}/cards:
    get:
      summary: List all cards for a specific customer (Admin view)
      description: |
        Returns all virtual cards belonging to a specific customer.
        No merchant restriction — admin can view any customer's cards.
        A customer can have multiple cards.
        
        **Any authenticated Admin.**
      tags: [Admin - Card Management]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: customerId
          required: true
          schema:
            type: string
            format: uuid
        - in: query
          name: status
          schema:
            type: string
            enum: [active, frozen, terminated]
      responses:
        '200':
          description: All cards for the customer
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  customer:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      fullName:
                        type: string
                        example: "John Doe"
                      email:
                        type: string
                        example: "john@example.com"
                  total:
                    type: integer
                    example: 3
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/CardDetail'
        '404':
          description: Customer not found

  /admin/cards/{cardId}:
    get:
      summary: Get full details of a single card
      description: |
        Returns complete card information including card number, expiry, balance, status,
        and associated customer + merchant details.
        
        > **Note**: CVV is excluded from all admin reads for PCI compliance.
        
        **Any authenticated Admin.**
      tags: [Admin - Card Management]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: cardId
          required: true
          schema:
            type: string
            format: uuid
            example: "c1c2c3c4-c5c6-c7c8-c9c0-c1c2c3c4c5c6"
      responses:
        '200':
          description: Full card detail
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    $ref: '#/components/schemas/CardWithCustomer'
        '404':
          description: Card not found

  /admin/cards/{cardId}/freeze:
    post:
      summary: Freeze a card (Admin)
      description: |
        Freezes a virtual card. The card must be in `active` status.
        The freeze is sent to PayScribe and the status is updated in the database.
        
        Action is logged to the audit trail.
        
        **Any authenticated Admin.**
      tags: [Admin - Card Management]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: cardId
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Card frozen successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: "Card frozen successfully by admin"
        '422':
          description: Card is not active (already frozen or terminated)
        '404':
          description: Card not found

  /admin/cards/{cardId}/unfreeze:
    post:
      summary: Unfreeze a card (Admin)
      description: |
        Unfreezes a virtual card. The card must be in `frozen` status.
        The unfreeze is sent to PayScribe and the status is updated.
        
        Action is logged to the audit trail.
        
        **Any authenticated Admin.**
      tags: [Admin - Card Management]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: cardId
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Card unfrozen successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: "Card unfrozen successfully by admin"
        '422':
          description: Card is not in frozen status
        '404':
          description: Card not found

  /admin/cards/{cardId}/terminate:
    post:
      summary: Terminate a card (SuperAdmin only)
      description: |
        Permanently terminates a virtual card. This action is **irreversible**.
        
        On termination:
        - The card is terminated on PayScribe
        - Any remaining card balance is automatically refunded to the customer's USD service balance
        - Card status is set to `terminated` and balance is set to `0`
        
        Action is logged to the audit trail.
        
        **SuperAdmin only.**
      tags: [Admin - Card Management]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: cardId
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Card terminated and remaining balance refunded
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: "Card terminated by admin. Remaining balance refunded to customer's USD account."
                  data:
                    type: object
                    properties:
                      refunded:
                        type: number
                        example: 45.50
                        description: Amount refunded to the customer's USD account
                      currency:
                        type: string
                        example: "USD"
        '422':
          description: Card is already terminated
        '404':
          description: Card not found
        '403':
          description: Forbidden - SuperAdmin only

  /admin/cards/{cardId}/balance:
    patch:
      summary: Update card balance — Admin manual adjustment (SuperAdmin only)
      description: |
        Performs a manual balance credit (add funds) or debit (remove funds) on a virtual card.
        
        This is an **administrative override** — it directly adjusts the local card balance
        in the database. Use this for balance corrections (e.g. when there is a discrepancy
        between PayScribe and the local record).
        
        **Required fields:**
        - `operation` — `"credit"` to add funds, `"debit"` to remove funds
        - `amount` — Positive number specifying how much to add/remove
        - `title` — Short heading describing this adjustment (e.g. `"Balance Correction"`)
        - `description` — Full explanation of the reason for the adjustment
        
        All adjustments are fully logged to the audit trail with the title, description, old balance, and new balance.
        
        **SuperAdmin only.**
      tags: [Admin - Card Management]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: cardId
          required: true
          schema:
            type: string
            format: uuid
            example: "c1c2c3c4-c5c6-c7c8-c9c0-c1c2c3c4c5c6"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CardBalanceUpdate'
            examples:
              credit:
                summary: Credit (add funds) to card
                value:
                  operation: "credit"
                  amount: 50.00
                  title: "Balance Correction"
                  description: "PayScribe reported an extra $50 on this card that was not reflected locally. Crediting to reconcile."
              debit:
                summary: Debit (remove funds) from card
                value:
                  operation: "debit"
                  amount: 20.00
                  title: "Erroneous Topup Reversal"
                  description: "Customer was accidentally topped up with $20 extra on 2026-07-24. Reversing the excess."
      responses:
        '200':
          description: Card balance updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: "Card balance credited successfully"
                  data:
                    $ref: '#/components/schemas/CardBalanceUpdateResponse'
        '400':
          description: Missing required fields or invalid operation
        '422':
          description: Insufficient card balance (for debit) or card is terminated
        '404':
          description: Card not found
        '403':
          description: Forbidden - SuperAdmin only

  # ─────────────────────────────────────────────────────────────────
  # Merchant Card Operations (Restricted)
  # ─────────────────────────────────────────────────────────────────

  /customers/{customerId}/cards:
    get:
      summary: List customer's virtual cards (Merchant)
      description: |
        Returns all virtual cards for a customer (CVV excluded). 
        Merchant can only view cards belonging to their own customers.
        A customer can have multiple cards.
      tags: [Cards]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: customerId
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: List of cards (no CVV)
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/CardDetail'

    post:
      summary: Create a virtual card for a customer (Merchant)
      description: |
        Creates a new USD virtual card for a customer. Customer must already be
        registered on PayScribe via the `/cards/register` endpoint first.
        Funds are deducted from the customer's USD service balance.
      tags: [Cards]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: customerId
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [amount]
              properties:
                amount:
                  type: number
                  example: 100
                  description: Initial funding amount (USD)
                brand:
                  type: string
                  enum: [visa, mastercard]
                  default: visa
                  example: "visa"
      responses:
        '201':
          description: Virtual card created successfully
        '422':
          description: Insufficient USD balance or PayScribe profile missing

  /customers/{customerId}/cards/{cardId}/freeze:
    post:
      summary: Freeze a customer's card (Merchant)
      tags: [Cards]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: customerId
          required: true
          schema: { type: string, format: uuid }
        - in: path
          name: cardId
          required: true
          schema: { type: string, format: uuid }
      responses:
        '200':
          description: Card frozen
        '422':
          description: Card is not active

  /customers/{customerId}/cards/{cardId}/unfreeze:
    post:
      summary: Unfreeze a customer's card (Merchant)
      tags: [Cards]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: customerId
          required: true
          schema: { type: string, format: uuid }
        - in: path
          name: cardId
          required: true
          schema: { type: string, format: uuid }
      responses:
        '200':
          description: Card unfrozen
        '422':
          description: Card is not frozen

  /customers/{customerId}/cards/{cardId}/terminate:
    post:
      summary: Terminate a customer's card (Merchant)
      description: |
        Permanently terminates a virtual card. Remaining balance is refunded
        to the customer's USD service account.
        
        **Note:** Merchants cannot update card balances (topup/withdraw). Those operations
        are restricted to server-to-server API key access only.
      tags: [Cards]
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: customerId
          required: true
          schema: { type: string, format: uuid }
        - in: path
          name: cardId
          required: true
          schema: { type: string, format: uuid }
      responses:
        '200':
          description: Card terminated and remaining balance refunded
        '422':
          description: Card is already terminated

components:
  schemas:
    CardDetail:
      type: object
      properties:
        id:
          type: string
          format: uuid
          example: "c1c2c3c4-c5c6-c7c8-c9c0-c1c2c3c4c5c6"
        customerId:
          type: string
          format: uuid
        card_id:
          type: string
          example: "ps_card_abc123"
          description: "Provider (PayScribe) card reference"
        brand:
          type: string
          enum: [visa, mastercard]
          example: "visa"
        name:
          type: string
          example: "JOHN DOE"
        card_number:
          type: string
          example: "4111 **** **** 1234"
        expiry:
          type: string
          example: "12/28"
        balance:
          type: number
          example: 245.50
        prev_balance:
          type: number
          example: 195.50
        currency:
          type: string
          example: "USD"
        status:
          type: string
          enum: [active, frozen, terminated]
          example: "active"
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    CardWithCustomer:
      allOf:
        - $ref: '#/components/schemas/CardDetail'
        - type: object
          properties:
            customer:
              type: object
              properties:
                id:
                  type: string
                  format: uuid
                fullName:
                  type: string
                  example: "John Doe"
                email:
                  type: string
                  example: "john@example.com"
                phoneNumber:
                  type: string
                  example: "+2348012345678"

    CardBalanceUpdate:
      type: object
      required: [operation, amount, title, description]
      properties:
        operation:
          type: string
          enum: [credit, debit]
          example: "credit"
          description: "'credit' adds funds, 'debit' removes funds"
        amount:
          type: number
          example: 50.00
          description: "Positive number — amount to credit or debit"
        title:
          type: string
          example: "Balance Correction"
          description: "Short heading / label for this adjustment"
        description:
          type: string
          example: "Corrected balance after PayScribe reconciliation on 2026-07-24"
          description: "Full explanation of why this adjustment was made"

    CardBalanceUpdateResponse:
      type: object
      properties:
        cardId:
          type: string
          format: uuid
        card_id:
          type: string
          example: "ps_card_abc123"
        customer:
          type: object
          properties:
            id:
              type: string
              format: uuid
            fullName:
              type: string
              example: "John Doe"
            email:
              type: string
              example: "john@example.com"
        currency:
          type: string
          example: "USD"
        operation:
          type: string
          enum: [credit, debit]
          example: "credit"
        amount:
          type: number
          example: 50.00
        previousBalance:
          type: number
          example: 195.50
        newBalance:
          type: number
          example: 245.50
        adjustment:
          type: object
          properties:
            title:
              type: string
              example: "Balance Correction"
            description:
              type: string
              example: "Corrected balance after PayScribe reconciliation on 2026-07-24"
            performedBy:
              type: string
              format: uuid
              description: "Admin UUID who performed this adjustment"
            performedAt:
              type: string
              format: date-time
