// Hand-written OpenAPI 3.0 spec, served via swagger-ui-express at /api-docs.
// Security requirements here mirror the requireAuth/requireAdmin middleware
// actually applied in src/routes/*.ts — keep both in sync when routes change.

const bearerAuth = [{ bearerAuth: [] as string[] }];

// Shared by the paginated product lists (/product, /new, /featured, /popular).
const productListParams = [
  { name: "page", in: "query", schema: { type: "integer", default: 1 } },
  { name: "perPage", in: "query", schema: { type: "integer", default: 10 } },
];

const productListResponses = {
  "200": {
    description: "OK",
    content: {
      "application/json": {
        schema: {
          type: "object",
          properties: {
            products: { type: "array", items: { $ref: "#/components/schemas/Product" } },
            totalItemCount: { type: "integer", description: "Total matching products across all pages" },
          },
        },
      },
    },
  },
};

export const openapiSpec = {
  openapi: "3.0.3",
  info: {
    title: "Before the Dates API",
    version: "1.0.0",
    description:
      "REST API for the Before the Dates vendor/admin portal and mobile app. " +
      "Protected endpoints require a JWT, sent as `Authorization: Bearer <token>` " +
      "(the legacy `x-auth-token` header is also accepted).",
  },
  // The current environment's own API_URL (from .env.<NODE_ENV>) is always
  // listed first, so Swagger UI defaults to it — e.g. the real production
  // URL when NODE_ENV=production. The others stay as convenience options
  // in the server dropdown when testing against a different environment.
  servers: [
    { url: process.env.API_URL || "http://localhost:8080/api/v1", description: `Current (${process.env.NODE_ENV || "development"})` },
    { url: "https://beforethedatesapi.alliancetek.net/api/v1", description: "QA" },
    { url: "https://api.beforethedates.com/api/v1", description: "Production" },
    { url: "http://localhost:8080/api/v1", description: "Local" },
  ].filter((server, index, all) => all.findIndex((s) => s.url === server.url) === index),
  components: {
    securitySchemes: {
      bearerAuth: {
        type: "http",
        scheme: "bearer",
        bearerFormat: "JWT",
      },
    },
    schemas: {
      Error: {
        type: "object",
        properties: { message: { type: "string" } },
      },
      User: {
        type: "object",
        properties: {
          _id: { type: "string" },
          name: { type: "string" },
          email: { type: "string" },
          role: { type: "string", enum: ["Admin", "Vendor", "User"] },
          status: {
            type: "string",
            enum: ["Active", "Inactive", "Pending", "Suspended", "Blocked"],
          },
          birthday: { type: "string", format: "date-time", nullable: true },
          anniversary: { type: "string", format: "date-time", nullable: true },
          token: { type: "string", description: "Only present in the login response" },
        },
      },
      Product: {
        type: "object",
        properties: {
          _id: { type: "string" },
          title: { type: "string" },
          description: { type: "string" },
          category: { type: "string" },
          price: { type: "number" },
          discountedPrice: { type: "number", nullable: true },
          images: { type: "array", items: { type: "string", format: "uri" } },
          vendor: { type: "string" },
          status: { type: "string", enum: ["Active", "Inactive"] },
          colorVariations: { type: "array", items: { type: "string" } },
          sizeVariations: { type: "array", items: { type: "string" } },
        },
      },
      Event: {
        type: "object",
        properties: {
          _id: { type: "string" },
          title: { type: "string" },
          fullDate: { type: "string", format: "date-time" },
          note: { type: "string" },
          recipientPhone: { type: "string" },
          recurringEvent: { type: "boolean" },
          user: { type: "string" },
          gifts: {
            type: "array",
            items: {
              type: "object",
              properties: {
                product: { type: "string" },
                selectedVariations: {
                  type: "object",
                  properties: {
                    color: { type: "string" },
                    size: { type: "string" },
                  },
                },
              },
            },
          },
        },
      },
      Order: {
        type: "object",
        properties: {
          _id: { type: "string" },
          vendor: { type: "string" },
          user: { type: "string" },
          event: { type: "string" },
          amount: { type: "number" },
          totalAmount: { type: "number" },
          status: { type: "string" },
          address: { type: "string" },
          city: { type: "string" },
          state: { type: "string" },
          zipcode: { type: "string" },
          recipientName: { type: "string" },
          trackingID: { type: "string" },
          trackingURL: { type: "string" },
        },
      },
      Review: {
        type: "object",
        properties: {
          _id: { type: "string" },
          product: { type: "string" },
          order: { type: "string" },
          rating: { type: "number" },
          comment: { type: "string" },
        },
      },
    },
  },
  tags: [
    { name: "Auth", description: "Login, signup, password reset, social login" },
    { name: "Admin", description: "Admin-only account management" },
    { name: "Events", description: "Gift-giving events/occasions" },
    { name: "Notifications" },
    { name: "Occasions", description: "Reference list of event occasions (birthday, anniversary, etc.)" },
    { name: "Orders" },
    { name: "Payment Methods" },
    { name: "Payments" },
    { name: "Products" },
    { name: "Reviews" },
    { name: "Store" },
    { name: "Stripe" },
    { name: "Subscriptions" },
    { name: "Users" },
    { name: "Vendors" },
    { name: "Wish", description: "Public shareable gift-wish cards" },
  ],
  paths: {
    // ---------------- Auth ----------------
    "/login": {
      post: {
        tags: ["Auth"],
        summary: "Log in with email/password",
        description: "Rate-limited: 10 attempts per 15 minutes per IP.",
        requestBody: {
          required: true,
          content: {
            "application/json": {
              schema: {
                type: "object",
                required: ["email", "password"],
                properties: {
                  email: { type: "string" },
                  password: { type: "string" },
                  FCMToken: { type: "string" },
                },
              },
            },
          },
        },
        responses: {
          "200": {
            description: "Login successful",
            content: {
              "application/json": {
                schema: {
                  type: "object",
                  properties: {
                    message: { type: "string" },
                    user: { $ref: "#/components/schemas/User" },
                  },
                },
              },
            },
          },
          "400": { description: "Invalid credentials", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
          "429": { description: "Too many attempts" },
        },
      },
    },
    "/signup": {
      post: {
        tags: ["Auth"],
        summary: "Create an account",
        description: "Rate-limited: 20 attempts per hour per IP.",
        requestBody: {
          required: true,
          content: {
            "application/json": {
              schema: {
                type: "object",
                required: ["name", "email", "password", "loginProvider", "role"],
                properties: {
                  name: { type: "string" },
                  email: { type: "string" },
                  password: {
                    type: "string",
                    description: "8-20 chars, upper+lower+digit+special",
                  },
                  loginProvider: { type: "string", enum: ["Local", "Google", "Facebook"] },
                  role: { type: "string", enum: ["Admin", "Vendor", "User"] },
                  birthday: { type: "string", format: "date", nullable: true, description: "Optional, e.g. 1995-08-24" },
                  anniversary: { type: "string", format: "date", nullable: true, description: "Optional, e.g. 2020-02-14" },
                },
              },
            },
          },
        },
        responses: {
          "200": { description: "Account created" },
          "400": { description: "Invalid request / user already exists" },
        },
      },
    },
    "/social-login": {
      post: {
        tags: ["Auth"],
        summary: "Log in via Google/Facebook/Apple",
        responses: { "200": { description: "Login successful" } },
      },
    },
    "/forgot-password": {
      post: {
        tags: ["Auth"],
        summary: "Request a password-reset OTP by email",
        description: "Rate-limited: 10 attempts per 15 minutes per IP.",
        requestBody: {
          required: true,
          content: {
            "application/json": {
              schema: { type: "object", required: ["email"], properties: { email: { type: "string" } } },
            },
          },
        },
        responses: { "200": { description: "OTP sent" }, "400": { description: "Invalid email / user not found" } },
      },
    },
    "/verify-otp": {
      post: {
        tags: ["Auth"],
        summary: "Verify a password-reset OTP",
        description:
          "Rate-limited: 10 attempts per 15 minutes per IP. The code itself is also " +
          "invalidated after 5 wrong guesses, independent of the IP rate limit.",
        requestBody: {
          required: true,
          content: {
            "application/json": {
              schema: {
                type: "object",
                required: ["email", "otp"],
                properties: { email: { type: "string" }, otp: { type: "string" } },
              },
            },
          },
        },
        responses: {
          "200": { description: "OTP valid" },
          "400": { description: "Invalid OTP" },
          "429": { description: "Too many incorrect attempts — request a new code" },
        },
      },
    },
    "/reset-password": {
      post: {
        tags: ["Auth"],
        summary: "Reset password using a verified OTP",
        description: "Rate-limited: 10 attempts per 15 minutes per IP.",
        requestBody: {
          required: true,
          content: {
            "application/json": {
              schema: {
                type: "object",
                required: ["email", "password", "otp"],
                properties: {
                  email: { type: "string" },
                  password: { type: "string" },
                  otp: { type: "string" },
                },
              },
            },
          },
        },
        responses: { "200": { description: "Password reset" }, "400": { description: "Invalid OTP / password" } },
      },
    },

    // ---------------- Admin ----------------
    "/admins": {
      get: {
        tags: ["Admin"],
        summary: "List all admin accounts",
        security: bearerAuth,
        responses: { "200": { description: "OK" }, "401": { description: "Unauthenticated" }, "403": { description: "Not an admin" } },
      },
    },
    "/admin/dashboardDetails": {
      get: {
        tags: ["Admin"],
        summary: "Admin dashboard summary stats",
        security: bearerAuth,
        responses: { "200": { description: "OK" }, "403": { description: "Not an admin" } },
      },
    },

    // ---------------- Events ----------------
    "/event/{id}": {
      get: {
        tags: ["Events"],
        summary: "List a user's events (paginated)",
        security: bearerAuth,
        parameters: [
          { name: "id", in: "path", required: true, schema: { type: "string" }, description: "User ID" },
          { name: "page", in: "query", schema: { type: "integer", default: 1 } },
          { name: "perPage", in: "query", schema: { type: "integer", default: 10 } },
        ],
        responses: { "200": { description: "OK. Returns { events, totalItemCount }" }, "401": { description: "Unauthenticated" } },
      },
      put: {
        tags: ["Events"],
        summary: "Update an event",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Updated" } },
      },
      delete: {
        tags: ["Events"],
        summary: "Delete (soft-delete) an event",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Deleted" } },
      },
    },
    "/event/upcoming/{id}": {
      get: {
        tags: ["Events"],
        summary: "List a user's upcoming events (paginated)",
        security: bearerAuth,
        parameters: [
          { name: "id", in: "path", required: true, schema: { type: "string" }, description: "User ID" },
          { name: "page", in: "query", schema: { type: "integer", default: 1 } },
          { name: "perPage", in: "query", schema: { type: "integer", default: 10 } },
        ],
        responses: { "200": { description: "OK. Returns { events, totalItemCount }" } },
      },
    },
    "/event/details/{id}": {
      get: {
        tags: ["Events"],
        summary: "Get a single event's details",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" }, description: "Event ID" }],
        responses: {
          "200": {
            description: "OK",
            content: { "application/json": { schema: { $ref: "#/components/schemas/Event" } } },
          },
          "400": { description: "Invalid event ID" },
          "404": { description: "Event not found" },
        },
      },
    },
    "/event/past/{id}": {
      get: {
        tags: ["Events"],
        summary: "List a user's past events (paginated)",
        security: bearerAuth,
        parameters: [
          { name: "id", in: "path", required: true, schema: { type: "string" }, description: "User ID" },
          { name: "page", in: "query", schema: { type: "integer", default: 1 } },
          { name: "perPage", in: "query", schema: { type: "integer", default: 10 } },
        ],
        responses: { "200": { description: "OK. Returns { events, totalItemCount }" } },
      },
    },
    "/events": {
      get: {
        tags: ["Events"],
        summary: "List all events (admin)",
        security: bearerAuth,
        responses: { "200": { description: "OK" }, "403": { description: "Not an admin" } },
      },
    },
    "/event": {
      post: {
        tags: ["Events"],
        summary: "Create an event",
        security: bearerAuth,
        requestBody: {
          required: true,
          content: {
            "application/json": {
              schema: {
                type: "object",
                required: ["title", "fullDate", "date", "month", "year", "time", "user"],
                properties: {
                  title: { type: "string" },
                  fullDate: { type: "string", format: "date-time" },
                  note: { type: "string" },
                  recipientPhone: { type: "string" },
                  recurringEvent: { type: "boolean" },
                  user: { type: "string" },
                  gifts: {
                    type: "array",
                    items: {
                      type: "object",
                      properties: {
                        product: { type: "string" },
                        selectedVariations: { type: "object" },
                      },
                    },
                  },
                },
              },
            },
          },
        },
        responses: { "201": { description: "Created" } },
      },
    },

    // ---------------- Notifications ----------------
    "/notifications/user/{id}": {
      get: {
        tags: ["Notifications"],
        summary: "List a user's notifications (paginated)",
        security: bearerAuth,
        parameters: [
          { name: "id", in: "path", required: true, schema: { type: "string" }, description: "User ID" },
          { name: "page", in: "query", schema: { type: "integer", default: 1 } },
          { name: "perPage", in: "query", schema: { type: "integer", default: 10 } },
        ],
        responses: { "200": { description: "OK. Returns { notifications, totalItemCount }" } },
      },
    },
    "/notifications/{id}": {
      put: {
        tags: ["Notifications"],
        summary: "Mark a notification read/unread",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Updated" } },
      },
    },
    "/notificationsSetings": {
      post: {
        tags: ["Notifications"],
        summary: "Save a user's notification preferences",
        security: bearerAuth,
        responses: { "200": { description: "Saved" } },
      },
    },
    "/notificationsSetings/user/{id}": {
      get: {
        tags: ["Notifications"],
        summary: "Get a user's notification preferences",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },

    // ---------------- Orders ----------------
    "/checkout": {
      post: {
        tags: ["Orders"],
        summary: "Place an order (checkout)",
        security: bearerAuth,
        requestBody: {
          required: true,
          content: {
            "application/json": {
              schema: {
                type: "object",
                required: ["orderedGifts", "user", "totalAmount", "address", "state", "city", "zipcode", "paymentBreakdown"],
                properties: {
                  orderedGifts: { type: "array", items: { type: "object" } },
                  user: { type: "string" },
                  event: { type: "string" },
                  totalAmount: { type: "number" },
                  paymentBreakdown: { type: "array", items: { type: "object" } },
                  address: { type: "string" },
                  state: { type: "string" },
                  city: { type: "string" },
                  zipcode: { type: "string" },
                  recipientName: { type: "string" },
                },
              },
            },
          },
        },
        responses: { "201": { description: "Order(s) created" }, "400": { description: "Invalid request" } },
      },
    },
    "/orders/change-status": {
      post: {
        tags: ["Orders"],
        summary: "Change an order's status",
        security: bearerAuth,
        responses: { "200": { description: "Updated" } },
      },
    },
    "/orders/user/{id}": {
      get: {
        tags: ["Orders"],
        summary: "List a customer's orders (paginated; returns { orders, totalItemCount })",
        security: bearerAuth,
        parameters: [
          { name: "id", in: "path", required: true, schema: { type: "string" } },
          { name: "page", in: "query", schema: { type: "integer", default: 1 } },
          { name: "perPage", in: "query", schema: { type: "integer", default: 10 } },
        ],
        responses: { "200": { description: "OK" } },
      },
    },
    "/orders/vendor/{id}": {
      get: {
        tags: ["Orders"],
        summary: "List a vendor's orders",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },
    "/orders": {
      get: {
        tags: ["Orders"],
        summary: "List all orders (admin)",
        security: bearerAuth,
        responses: { "200": { description: "OK" }, "403": { description: "Not an admin" } },
      },
    },
    "/orders-stats/vendor/{id}": {
      get: {
        tags: ["Orders"],
        summary: "Vendor order statistics",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },
    "/orders/request-payment/{id}": {
      post: {
        tags: ["Orders"],
        summary: "Vendor requests payout for an order",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Requested" } },
      },
    },
    "/orders/dispatch-amount": {
      post: {
        tags: ["Orders"],
        summary: "Admin dispatches a vendor payout",
        security: bearerAuth,
        responses: { "200": { description: "Dispatched" }, "403": { description: "Not an admin" } },
      },
    },
    "/carriers": {
      get: {
        tags: ["Orders"],
        summary: "List connected ShipEngine carriers",
        security: bearerAuth,
        responses: { "200": { description: "OK" } },
      },
    },
    "/get-shipping-charges": {
      post: {
        tags: ["Orders"],
        summary: "Calculate shipping + tax for a checkout",
        security: bearerAuth,
        requestBody: {
          required: true,
          content: {
            "application/json": {
              schema: {
                type: "object",
                required: ["vendor", "address", "city", "state", "zip", "weight", "amount"],
                properties: {
                  vendor: { type: "string" },
                  address: { type: "string" },
                  city: { type: "string" },
                  state: { type: "string" },
                  zip: { type: "string" },
                  weight: { type: "number" },
                  length: { type: "number" },
                  width: { type: "number" },
                  height: { type: "number" },
                  amount: { type: "number", description: "Product subtotal, in cents" },
                  event: { type: "string" },
                },
              },
            },
          },
        },
        responses: { "200": { description: "OK" }, "400": { description: "Invalid request" } },
      },
    },
    "/orders/{id}/shipping-invoice": {
      get: {
        tags: ["Orders"],
        summary: "Generate a shipping invoice PDF",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "PDF" } },
      },
    },

    // ---------------- Payment Methods ----------------
    "/payment-method/{id}": {
      get: {
        tags: ["Payment Methods"],
        summary: "Get a payment method",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
      put: {
        tags: ["Payment Methods"],
        summary: "Update a payment method",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Updated" } },
      },
      delete: {
        tags: ["Payment Methods"],
        summary: "Delete a payment method",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Deleted" } },
      },
    },
    "/payment-method": {
      post: {
        tags: ["Payment Methods"],
        summary: "Add a payment method",
        security: bearerAuth,
        responses: { "201": { description: "Created" } },
      },
    },

    // ---------------- Payments ----------------
    "/paymentsStats/{id}": {
      get: {
        tags: ["Payments"],
        summary: "Vendor payment statistics",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },

    // ---------------- Products ----------------
    "/product": {
      get: {
        tags: ["Products"],
        summary: "List products (paginated)",
        security: bearerAuth,
        parameters: [
          ...productListParams,
          { name: "search", in: "query", schema: { type: "string" }, description: "Matches title, description or category" },
          { name: "eventDate", in: "query", schema: { type: "string", format: "date" } },
          { name: "source", in: "query", schema: { type: "string", enum: ["admin", "vendor"] }, description: "Bypasses the Active-status filter" },
        ],
        responses: productListResponses,
      },
      post: {
        tags: ["Products"],
        summary: "Create a product (multipart, up to 20 images)",
        security: bearerAuth,
        requestBody: {
          required: true,
          content: {
            "multipart/form-data": {
              schema: {
                type: "object",
                required: ["title", "price", "vendorID", "orderMinDays", "orderMaxDays"],
                properties: {
                  title: { type: "string" },
                  description: { type: "string" },
                  category: { type: "string" },
                  price: { type: "number" },
                  discountedPrice: { type: "number" },
                  vendorID: { type: "string" },
                  status: { type: "string" },
                  colorVariations: { type: "array", items: { type: "string" } },
                  sizeVariations: { type: "array", items: { type: "string" } },
                  orderMinDays: { type: "integer" },
                  orderMaxDays: { type: "integer" },
                  files: { type: "array", items: { type: "string", format: "binary" } },
                },
              },
            },
          },
        },
        responses: { "201": { description: "Created" }, "400": { description: "Validation error" } },
      },
    },
    "/product/featured": {
      get: { tags: ["Products"], summary: "Featured products (paginated)", security: bearerAuth, parameters: productListParams, responses: productListResponses },
    },
    "/product/new": {
      get: { tags: ["Products"], summary: "Newest products (paginated)", security: bearerAuth, parameters: productListParams, responses: productListResponses },
    },
    "/product/popular": {
      get: { tags: ["Products"], summary: "Most popular products (paginated)", security: bearerAuth, parameters: productListParams, responses: productListResponses },
    },
    "/product/vendor/{id}": {
      get: {
        tags: ["Products"],
        summary: "List a vendor's products",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },
    "/product/details/{id}": {
      get: {
        tags: ["Products"],
        summary: "Get a single product's details",
        security: bearerAuth,
        description:
          "Visibility is decided by the caller's role from the token: admins see any product, " +
          "vendors also see their own inactive products, everyone else only sees Active products.",
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" }, description: "Product ID" }],
        responses: {
          "200": {
            description: "OK",
            content: { "application/json": { schema: { $ref: "#/components/schemas/Product" } } },
          },
          "400": { description: "Invalid product ID" },
          "404": { description: "Product not found" },
        },
      },
    },
    "/product/{id}": {
      put: {
        tags: ["Products"],
        summary: "Update a product (multipart, up to 5 new images)",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Updated" } },
      },
      delete: {
        tags: ["Products"],
        summary: "Delete a product",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Deleted" } },
      },
    },

    // ---------------- Reviews ----------------
    "/reviews": {
      post: {
        tags: ["Reviews"],
        summary: "Submit a review",
        security: bearerAuth,
        requestBody: {
          required: true,
          content: {
            "application/json": {
              schema: {
                type: "object",
                required: ["product", "order", "rating"],
                properties: {
                  product: { type: "string" },
                  order: { type: "string" },
                  rating: { type: "number", minimum: 1, maximum: 5 },
                  comment: { type: "string" },
                },
              },
            },
          },
        },
        responses: { "201": { description: "Created" } },
      },
    },
    "/reviews/{id}": {
      put: {
        tags: ["Reviews"],
        summary: "Update a review",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Updated" } },
      },
      delete: {
        tags: ["Reviews"],
        summary: "Delete a review",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Deleted" } },
      },
    },
    "/reviews/product/{id}": {
      get: {
        tags: ["Reviews"],
        summary: "List a product's reviews",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },
    "/reviews/order/{id}": {
      get: {
        tags: ["Reviews"],
        summary: "List an order's reviews",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },
    "/reviews/vendor/{id}": {
      get: {
        tags: ["Reviews"],
        summary: "List a vendor's reviews",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },
    "/reviews/{id}/report": {
      post: {
        tags: ["Reviews"],
        summary: "Report a review",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Reported" } },
      },
    },
    "/admin/reviews/{id}": {
      delete: {
        tags: ["Reviews"],
        summary: "Delete a review (admin)",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Deleted" }, "403": { description: "Not an admin" } },
      },
    },
    "/admin/reviews/reported": {
      get: {
        tags: ["Reviews"],
        summary: "List reported reviews (admin)",
        security: bearerAuth,
        responses: { "200": { description: "OK" }, "403": { description: "Not an admin" } },
      },
    },
    "/admin/reviews/{id}/dismiss": {
      put: {
        tags: ["Reviews"],
        summary: "Dismiss a review report (admin)",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Dismissed" }, "403": { description: "Not an admin" } },
      },
    },

    // ---------------- Store ----------------
    "/store/businessInformation/{id}": {
      get: {
        tags: ["Store"],
        summary: "Get a vendor's business information",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },
    "/store/businessInformation": {
      post: {
        tags: ["Store"],
        summary: "Save business information",
        security: bearerAuth,
        responses: { "200": { description: "Saved" } },
      },
    },
    "/store/storeInformation/{id}": {
      get: {
        tags: ["Store"],
        summary: "Get a vendor's public storefront info",
        description: "Public — name/logo/description are meant to be visible while browsing.",
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },
    "/store/storeInformation": {
      post: {
        tags: ["Store"],
        summary: "Save storefront info",
        security: bearerAuth,
        responses: { "200": { description: "Saved" } },
      },
    },
    "/store/paymentInformation/{id}": {
      get: {
        tags: ["Store"],
        summary: "Get a vendor's payout information",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },
    "/store/paymentInformation": {
      post: {
        tags: ["Store"],
        summary: "Save payout information",
        security: bearerAuth,
        responses: { "200": { description: "Saved" } },
      },
    },
    "/store/logo": {
      post: {
        tags: ["Store"],
        summary: "Upload a store logo",
        security: bearerAuth,
        requestBody: {
          required: true,
          content: {
            "multipart/form-data": {
              schema: {
                type: "object",
                required: ["vendorID", "file"],
                properties: {
                  vendorID: { type: "string" },
                  file: { type: "string", format: "binary" },
                },
              },
            },
          },
        },
        responses: { "200": { description: "Uploaded" } },
      },
    },

    // ---------------- Stripe ----------------
    "/stripe/publishable-key": {
      get: {
        tags: ["Stripe"],
        summary: "Get the Stripe publishable key",
        security: bearerAuth,
        responses: { "200": { description: "OK" } },
      },
    },
    "/stripe/payment-sheet": {
      post: {
        tags: ["Stripe"],
        summary: "Create a Stripe payment sheet (mobile)",
        security: bearerAuth,
        responses: { "200": { description: "OK" } },
      },
    },
    "/stripe/customer-sheet": {
      post: {
        tags: ["Stripe"],
        summary: "Create a Stripe customer sheet (mobile)",
        security: bearerAuth,
        responses: { "200": { description: "OK" } },
      },
    },
    "/subscription-plans": {
      get: {
        tags: ["Stripe"],
        summary: "List subscription plans",
        security: bearerAuth,
        responses: { "200": { description: "OK" } },
      },
    },
    "/create-checkout-session": {
      post: {
        tags: ["Stripe"],
        summary: "Create a Stripe Checkout session for a vendor subscription",
        security: bearerAuth,
        requestBody: {
          required: true,
          content: {
            "application/json": {
              schema: {
                type: "object",
                required: ["priceId", "vendorID", "planName"],
                properties: {
                  priceId: { type: "string" },
                  vendorID: { type: "string" },
                  planName: { type: "string" },
                },
              },
            },
          },
        },
        responses: { "200": { description: "OK" } },
      },
    },
    "/check-session": {
      post: {
        tags: ["Stripe"],
        summary: "Check a Checkout session's payment status",
        security: bearerAuth,
        requestBody: {
          required: true,
          content: {
            "application/json": {
              schema: { type: "object", required: ["sessionId"], properties: { sessionId: { type: "string" } } },
            },
          },
        },
        responses: { "200": { description: "OK" } },
      },
    },
    "/create-portal-session/{id}": {
      post: {
        tags: ["Stripe"],
        summary: "Create a Stripe billing-portal session",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },
    "/stripe/webhook": {
      post: {
        tags: ["Stripe"],
        summary: "Stripe webhook receiver",
        description: "Public — authenticated via the `stripe-signature` header, not a user token.",
        responses: { "200": { description: "OK" } },
      },
    },

    // ---------------- Subscriptions ----------------
    "/subscriptions/{id}": {
      get: {
        tags: ["Subscriptions"],
        summary: "Get a vendor's subscription",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },

    // ---------------- Users ----------------
    "/users": {
      get: {
        tags: ["Users"],
        summary: "List all users (admin)",
        security: bearerAuth,
        responses: { "200": { description: "OK" }, "403": { description: "Not an admin" } },
      },
    },
    "/user/{id}": {
      put: {
        tags: ["Users"],
        summary: "Update a user profile",
        description: "`birthday` / `anniversary` are optional: omit to leave unchanged, send null or \"\" to clear.",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        requestBody: {
          required: true,
          content: {
            "multipart/form-data": {
              schema: {
                type: "object",
                properties: {
                  name: { type: "string" },
                  phoneNumber: { type: "string" },
                  countryCode: { type: "string" },
                  address: { type: "string" },
                  signature: { type: "string" },
                  birthday: { type: "string", format: "date" },
                  anniversary: { type: "string", format: "date" },
                  profileImage: { type: "string", format: "binary", description: "Optional. JPEG/PNG/WEBP/GIF/HEIC, max 10MB." },
                },
              },
            },
          },
        },
        responses: { "200": { description: "Updated" }, "400": { description: "Invalid birthday/anniversary" }, "404": { description: "User not found" } },
      },
      delete: {
        tags: ["Users"],
        summary: "Delete a user (admin)",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Deleted" }, "403": { description: "Not an admin" } },
      },
    },
    "/user/updatePackage/{id}": {
      post: {
        tags: ["Users"],
        summary: "Change a user's subscription package (admin)",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Updated" }, "403": { description: "Not an admin" } },
      },
    },
    "/user/updateStatus/{id}": {
      post: {
        tags: ["Users"],
        summary: "Change a user's account status (admin)",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Updated" }, "403": { description: "Not an admin" } },
      },
    },

    // ---------------- Vendors ----------------
    "/vendor/dashboardDetails/{id}": {
      get: {
        tags: ["Vendors"],
        summary: "Vendor dashboard summary",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "OK" } },
      },
    },
    "/vendors": {
      get: {
        tags: ["Vendors"],
        summary: "List vendors",
        security: bearerAuth,
        responses: { "200": { description: "OK" } },
      },
    },
    "/vendor/updateStatus/{id}": {
      put: {
        tags: ["Vendors"],
        summary: "Approve/suspend a vendor (admin)",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Updated" }, "403": { description: "Not an admin" } },
      },
    },

    // ---------------- Wish ----------------
    "/wish/{id}": {
      get: {
        tags: ["Wish"],
        summary: "Get a shareable gift-wish card by order ID",
        description:
          "Public — opened by the gift recipient via a shared link, not a logged-in user.",
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" }, description: "Order ID" }],
        responses: { "200": { description: "OK" }, "404": { description: "Not found" } },
      },
    },

    // ---------------- Occasions ----------------
    "/occasions": {
      get: {
        tags: ["Occasions"],
        summary: "List active occasions (birthday, anniversary, etc.)",
        security: bearerAuth,
        responses: { "200": { description: "OK" } },
      },
      post: {
        tags: ["Occasions"],
        summary: "Create an occasion (admin)",
        security: bearerAuth,
        requestBody: {
          required: true,
          content: {
            "multipart/form-data": {
              schema: {
                type: "object",
                required: ["key", "title"],
                properties: {
                  key: { type: "string", description: "Stable id, e.g. \"birthday\"" },
                  title: { type: "string" },
                  autoNote: { type: "string" },
                  sortOrder: { type: "integer" },
                  icon: { type: "string", format: "binary" },
                },
              },
            },
          },
        },
        responses: { "201": { description: "Created" }, "403": { description: "Not an admin" } },
      },
    },
    "/occasions/{id}": {
      put: {
        tags: ["Occasions"],
        summary: "Update an occasion (admin)",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        requestBody: {
          content: {
            "multipart/form-data": {
              schema: {
                type: "object",
                properties: {
                  title: { type: "string" },
                  autoNote: { type: "string" },
                  sortOrder: { type: "integer" },
                  isActive: { type: "boolean" },
                  icon: { type: "string", format: "binary" },
                },
              },
            },
          },
        },
        responses: { "200": { description: "Updated" }, "403": { description: "Not an admin" } },
      },
      delete: {
        tags: ["Occasions"],
        summary: "Deactivate an occasion (admin)",
        security: bearerAuth,
        parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
        responses: { "200": { description: "Deactivated" }, "403": { description: "Not an admin" } },
      },
    },
  },
};
