import { NextResponse } from 'next/server';
import { wrapRouteHandler } from '@server/logger/request';

/**
 * Public OpenAPI 3.1 specification for the RestroAgent v1 REST API.
 *
 * This route is intentionally unauthenticated so SDK generators (openapi-generator,
 * stoplight, etc.) and the in-dashboard docs panel can fetch it without holding
 * a Bearer token. The spec is generated from a static literal — there are only
 * 19 endpoints — so we don't need the runtime overhead of a builder library.
 */

const STANDARD_ERROR = {
  type: 'object',
  required: ['error'],
  properties: {
    error: {
      type: 'object',
      required: ['code', 'message'],
      properties: {
        code: { type: 'string', example: 'AUTH_ERROR' },
        message: { type: 'string', example: 'Invalid or missing API key' },
        details: { type: 'object', additionalProperties: true, nullable: true },
      },
    },
  },
};

// (Pagination is now expressed inline per list operation as `{ data, next_cursor }`.
// We keep no shared schema because the public surface intentionally exposes
// only the opaque cursor token — never page numbers or totals.)

const COMMON_RESPONSES = {
  Unauthorized: { description: 'Missing or invalid API key', content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } } },
  Forbidden:    { description: 'Key lacks the required permission', content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } } },
  NotFound:     { description: 'Resource not found',                 content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } } },
  Validation:   { description: 'Request body failed validation',     content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } } },
  RateLimited:  { description: 'Rate limit exceeded (60/min, 5000/day per key)', content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } } },
};

function listOp(summary: string, perm: string, tag: string, extraQuery: Array<{ name: string; type: string; description?: string; enum?: string[] }> = [], maxLimit = 100, defaultLimit = 20) {
  return {
    summary,
    tags: [tag],
    security: [{ bearerAuth: [perm] }],
    parameters: [
      { name: 'cursor', in: 'query', description: 'Opaque token returned as `next_cursor` from the previous page. Omit for the first page.', schema: { type: 'string' } },
      { name: 'limit',  in: 'query', schema: { type: 'integer', minimum: 1, maximum: maxLimit, default: defaultLimit } },
      { name: 'search', in: 'query', schema: { type: 'string' } },
      ...extraQuery.map((q) => ({ name: q.name, in: 'query' as const, description: q.description, schema: q.enum ? { type: q.type, enum: q.enum } : { type: q.type } })),
    ],
    responses: {
      200: {
        description: 'OK',
        content: {
          'application/json': {
            schema: {
              type: 'object',
              required: ['data', 'next_cursor'],
              properties: {
                data: { type: 'array', items: { type: 'object', additionalProperties: true } },
                next_cursor: { type: 'string', nullable: true, description: 'Opaque cursor for the next page; `null` when there are no more rows.' },
              },
            },
          },
        },
      },
      400: { $ref: '#/components/responses/Validation' },
      401: { $ref: '#/components/responses/Unauthorized' },
      403: { $ref: '#/components/responses/Forbidden' },
      429: { $ref: '#/components/responses/RateLimited' },
    },
  };
}

function singleOp(summary: string, perm: string, tag: string, idDescription = 'Resource id (uuid)') {
  return {
    summary,
    tags: [tag],
    security: [{ bearerAuth: [perm] }],
    parameters: [{ name: 'id', in: 'path', required: true, description: idDescription, schema: { type: 'string', format: 'uuid' } }],
    responses: {
      200: { description: 'OK', content: { 'application/json': { schema: { type: 'object', properties: { data: { type: 'object', additionalProperties: true } } } } } },
      401: { $ref: '#/components/responses/Unauthorized' },
      403: { $ref: '#/components/responses/Forbidden' },
      404: { $ref: '#/components/responses/NotFound' },
      429: { $ref: '#/components/responses/RateLimited' },
    },
  };
}

function bodyOp(summary: string, perm: string, tag: string, schemaName: string, status = 201, params: Array<Record<string, unknown>> = []) {
  return {
    summary,
    tags: [tag],
    security: [{ bearerAuth: [perm] }],
    parameters: params,
    requestBody: {
      required: true,
      content: { 'application/json': { schema: { $ref: `#/components/schemas/${schemaName}` } } },
    },
    responses: {
      [status]: { description: 'Created', content: { 'application/json': { schema: { type: 'object', properties: { data: { type: 'object', additionalProperties: true } } } } } },
      400: { $ref: '#/components/responses/Validation' },
      401: { $ref: '#/components/responses/Unauthorized' },
      403: { $ref: '#/components/responses/Forbidden' },
      404: { $ref: '#/components/responses/NotFound' },
      429: { $ref: '#/components/responses/RateLimited' },
    },
  };
}

function buildSpec(baseUrl: string) {
  return {
    openapi: '3.1.0',
    info: {
      title: 'RestroAgent Public REST API',
      version: '1.0.0',
      description:
        'Public REST API for RestroAgent. Authenticate every request with a Bearer token issued from the **REST API** dashboard panel (`Authorization: Bearer rsk_…`). Each key carries a permission allow-list and is rate-limited to 60 requests per minute and 5,000 requests per day.',
    },
    servers: [{ url: baseUrl, description: 'Current deployment' }],
    security: [{ bearerAuth: [] }],
    tags: [
      { name: 'Orders' },
      { name: 'Bookings' },
      { name: 'Customers' },
      { name: 'Menu' },
      { name: 'Branches' },
      { name: 'Analytics' },
      { name: 'AI Conversations' },
    ],
    paths: {
      '/orders': {
        get:  listOp('List orders', 'orders:read', 'Orders', [
          { name: 'branch_id', type: 'string', description: 'Filter by branch UUID' },
          { name: 'status',    type: 'string' },
          { name: 'channel',   type: 'string', description: 'Filter by intake channel', enum: ['chat', 'voice', 'whatsapp', 'email', 'sms', 'storefront', 'pos', 'zomato', 'swiggy', 'online'] },
          { name: 'from',      type: 'string', description: 'ISO-8601 date or datetime — inclusive lower bound on created_at' },
          { name: 'to',        type: 'string', description: 'ISO-8601 date or datetime — inclusive upper bound on created_at' },
          { name: 'sort',      type: 'string' },
          { name: 'dir',       type: 'string' },
        ]),
        post: bodyOp('Create order', 'orders:write', 'Orders', 'CreateOrder'),
      },
      '/orders/{id}': {
        get:   singleOp('Get order by id', 'orders:read', 'Orders'),
        patch: bodyOp('Update order status or details', 'orders:write', 'Orders', 'UpdateOrder', 200, [
          { name: 'id', in: 'path', required: true, schema: { type: 'string', format: 'uuid' } },
        ]),
      },
      '/bookings': {
        get:  listOp('List table bookings', 'bookings:read', 'Bookings', [
          { name: 'branch_id', type: 'string' },
          { name: 'status',    type: 'string' },
          { name: 'date',      type: 'string', description: 'YYYY-MM-DD' },
        ]),
        post: bodyOp('Create booking', 'bookings:write', 'Bookings', 'CreateBooking'),
      },
      '/bookings/{id}': {
        patch: bodyOp('Update booking status or details', 'bookings:write', 'Bookings', 'UpdateBooking', 200, [
          { name: 'id', in: 'path', required: true, schema: { type: 'string', format: 'uuid' } },
        ]),
        delete: {
          summary: 'Cancel booking',
          tags: ['Bookings'],
          security: [{ bearerAuth: ['bookings:write'] }],
          parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string', format: 'uuid' } }],
          responses: {
            200: { description: 'Cancelled', content: { 'application/json': { schema: { type: 'object', properties: { data: { type: 'object' } } } } } },
            401: { $ref: '#/components/responses/Unauthorized' },
            403: { $ref: '#/components/responses/Forbidden' },
            404: { $ref: '#/components/responses/NotFound' },
            429: { $ref: '#/components/responses/RateLimited' },
          },
        },
      },
      '/customers': {
        get: listOp('List customers', 'customers:read', 'Customers', [
          { name: 'branch_id', type: 'string' },
        ]),
      },
      '/customers/{id}': {
        get: singleOp('Get customer by id', 'customers:read', 'Customers'),
      },
      '/branches': {
        get: listOp('List branches', 'menu:read', 'Branches', [
          { name: 'include_inactive', type: 'boolean', description: 'Set to true to include inactive branches. Defaults to false (active only).' },
        ], 200, 50),
      },
      /* Branch response shape (stable contract):
         id, name, address, phone, timezone, is_active, hours (JSONB),
         accepts_dine_in, accepts_takeaway, accepts_delivery,
         storefront_enabled, slug, min_order_value, created_at, updated_at.
         SMTP/internal credentials are never included. */
      '/menu/items': {
        get:  listOp('List menu items', 'menu:read', 'Menu', [
          { name: 'branch_id',   type: 'string' },
          { name: 'category_id', type: 'string' },
        ], 200, 50),
        post: bodyOp('Create menu item', 'menu:write', 'Menu', 'CreateMenuItem'),
      },
      '/menu/items/{id}': {
        get:    singleOp('Get menu item by id', 'menu:read', 'Menu'),
        patch:  bodyOp('Update menu item', 'menu:write', 'Menu', 'UpdateMenuItem', 200, [
          { name: 'id', in: 'path', required: true, schema: { type: 'string', format: 'uuid' } },
        ]),
        delete: {
          summary: 'Delete menu item',
          tags: ['Menu'],
          security: [{ bearerAuth: ['menu:write'] }],
          parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string', format: 'uuid' } }],
          responses: {
            200: { description: 'Deleted', content: { 'application/json': { schema: { type: 'object', properties: { data: { type: 'object', properties: { id: { type: 'string', format: 'uuid' }, deleted: { type: 'boolean' } } } } } } } },
            401: { $ref: '#/components/responses/Unauthorized' },
            403: { $ref: '#/components/responses/Forbidden' },
            404: { $ref: '#/components/responses/NotFound' },
            429: { $ref: '#/components/responses/RateLimited' },
          },
        },
      },
      '/analytics/summary': {
        get: {
          summary: 'Revenue and order analytics summary',
          tags: ['Analytics'],
          security: [{ bearerAuth: ['analytics:read'] }],
          parameters: [
            { name: 'branch_id', in: 'query', schema: { type: 'string' } },
            { name: 'period',    in: 'query', schema: { type: 'string', enum: ['today', '7days', 'month', 'lifetime'], default: 'today' } },
          ],
          responses: {
            200: {
              description: 'OK',
              content: {
                'application/json': {
                  schema: {
                    type: 'object',
                    properties: {
                      data: {
                        type: 'object',
                        properties: {
                          period:     { type: 'string' },
                          branch_id:  { type: 'string', nullable: true },
                          stats:      { type: 'object', additionalProperties: true },
                          revenue:    { type: 'object', additionalProperties: true },
                        },
                      },
                    },
                  },
                },
              },
            },
            401: { $ref: '#/components/responses/Unauthorized' },
            403: { $ref: '#/components/responses/Forbidden' },
            429: { $ref: '#/components/responses/RateLimited' },
          },
        },
      },
      '/ai/conversations': {
        get: listOp('List AI conversations', 'ai:read', 'AI Conversations', [
          { name: 'branch_id', type: 'string' },
          { name: 'status',    type: 'string' },
          { name: 'channel',   type: 'string' },
          { name: 'from',      type: 'string', description: 'ISO-8601 date or datetime — inclusive lower bound on created_at' },
          { name: 'to',        type: 'string', description: 'ISO-8601 date or datetime — inclusive upper bound on created_at' },
        ]),
      },
      '/ai/conversations/{id}/takeover': {
        post: bodyOp('Take over an AI conversation', 'ai:write', 'AI Conversations', 'TakeoverConversation', 200, [
          { name: 'id', in: 'path', required: true, schema: { type: 'string', format: 'uuid' } },
        ]),
      },
    },
    components: {
      securitySchemes: {
        bearerAuth: {
          type: 'http',
          scheme: 'bearer',
          bearerFormat: 'rsk_<hex>',
          description: 'Issue keys from the dashboard REST API panel. Keys begin with `rsk_` followed by 64 hex characters.',
        },
      },
      responses: COMMON_RESPONSES,
      schemas: {
        Error: STANDARD_ERROR,
        OrderItem: {
          type: 'object',
          required: ['name', 'quantity'],
          properties: {
            name:     { type: 'string' },
            quantity: { type: 'integer', minimum: 1 },
            price:    { type: 'number',  minimum: 0 },
            modifiers: { type: 'array', items: { type: 'string' } },
            special_instructions: { type: 'string' },
          },
        },
        CreateOrder: {
          type: 'object',
          required: ['items'],
          properties: {
            branch_id:      { type: 'string', format: 'uuid' },
            customer_id:    { type: 'string', format: 'uuid' },
            customer_name:  { type: 'string' },
            customer_phone: { type: 'string' },
            items:          { type: 'array', items: { $ref: '#/components/schemas/OrderItem' }, minItems: 1 },
            channel:        { type: 'string', enum: ['chat', 'voice', 'whatsapp', 'email', 'sms', 'pos', 'zomato', 'swiggy', 'online'] },
            delivery_type:  { type: 'string' },
            table_number:   { type: 'string' },
            subtotal:       { type: 'number' },
            tax:            { type: 'number' },
            total:          { type: 'number' },
            special_instructions: { type: 'string' },
            coupon_code:    { type: 'string' },
          },
        },
        UpdateOrder: {
          type: 'object',
          properties: {
            status: { type: 'string', enum: ['pending','confirmed','kitchen','ready','delivered','completed','cancelled','failed','escalated','processing','rider'] },
            modification_note: { type: 'string' },
            customer_name:  { type: 'string' },
            customer_phone: { type: 'string', nullable: true },
            items: { type: 'array', items: { $ref: '#/components/schemas/OrderItem' } },
            delivery_type:    { type: 'string' },
            delivery_address: { type: 'string', nullable: true },
            table_number:     { type: 'string', nullable: true },
            special_instructions: { type: 'string', nullable: true },
          },
        },
        CreateBooking: {
          type: 'object',
          required: ['guest_name'],
          properties: {
            branch_id:    { type: 'string', format: 'uuid' },
            customer_id:  { type: 'string', format: 'uuid' },
            guest_name:   { type: 'string' },
            guest_phone:  { type: 'string' },
            guest_email:  { type: 'string', format: 'email' },
            table_no:     { type: 'string' },
            table_id:     { type: 'string', format: 'uuid', nullable: true },
            party_size:   { type: 'integer', minimum: 1 },
            booking_date: { type: 'string', description: 'YYYY-MM-DD' },
            booking_time: { type: 'string', description: 'HH:MM (24h) or H:MM AM/PM (12h)' },
            start_at:     { type: 'string', format: 'date-time' },
            duration_min: { type: 'integer', minimum: 15, maximum: 480 },
            buffer_min:   { type: 'integer', minimum: 0,  maximum: 60 },
            zone:         { type: 'string' },
            channel:      { type: 'string', enum: ['chat','voice','whatsapp','email','sms'] },
            occasion:     { type: 'string' },
            dietary_needs:{ type: 'array', items: { type: 'string' } },
            special_requests: { type: 'string' },
            is_vip:       { type: 'boolean' },
            notes:        { type: 'string' },
          },
        },
        CreateMenuItem: {
          type: 'object',
          required: ['name'],
          properties: {
            branch_id:    { type: 'string', format: 'uuid', nullable: true },
            category_id:  { type: 'string', format: 'uuid', nullable: true },
            name:         { type: 'string' },
            description:  { type: 'string', nullable: true },
            price:        { type: 'number', minimum: 0 },
            dietary_tags: { type: 'array', items: { type: 'string' } },
            image_url:    { type: 'string', nullable: true },
            is_available: { type: 'boolean' },
            is_in_stock:  { type: 'boolean' },
            stock_count:  { type: 'integer', minimum: 0, nullable: true },
            sort_order:   { type: 'integer', minimum: 0 },
            spice_level:  { type: 'integer', minimum: 0, maximum: 3 },
            is_veg:       { type: 'boolean' },
            prep_time_minutes: { type: 'integer', minimum: 0 },
            calories:     { type: 'integer', minimum: 0 },
          },
        },
        UpdateMenuItem: {
          type: 'object',
          description: 'All fields are optional. Only provided fields are updated.',
          properties: {
            category_id:  { type: 'string', format: 'uuid', nullable: true },
            name:         { type: 'string' },
            description:  { type: 'string', nullable: true },
            price:        { type: 'number', minimum: 0 },
            dietary_tags: { type: 'array', items: { type: 'string' } },
            image_url:    { type: 'string', nullable: true },
            is_available: { type: 'boolean', description: 'Toggle item visibility on the menu' },
            is_in_stock:  { type: 'boolean', description: 'Toggle in-stock status' },
            stock_count:  { type: 'integer', minimum: 0, nullable: true },
            low_stock_threshold:  { type: 'integer', minimum: 0, nullable: true },
            daily_reset_count:    { type: 'integer', minimum: 0, nullable: true },
            sort_order:   { type: 'integer', minimum: 0 },
            spice_level:  { type: 'integer', minimum: 0, maximum: 3 },
            is_veg:       { type: 'boolean' },
            prep_time_minutes: { type: 'integer', minimum: 0 },
            calories:     { type: 'integer', minimum: 0 },
          },
        },
        UpdateBooking: {
          type: 'object',
          description: 'All fields are optional. Only provided fields are updated.',
          properties: {
            status:       { type: 'string', enum: ['pending','confirmed','seated','completed','cancelled','noshow','escalated','reminder_sent'] },
            table_no:     { type: 'string', nullable: true },
            table_id:     { type: 'string', format: 'uuid', nullable: true },
            party_size:   { type: 'integer', minimum: 1 },
            booking_date: { type: 'string', description: 'YYYY-MM-DD' },
            booking_time: { type: 'string', description: 'HH:MM (24h) or H:MM AM/PM (12h)' },
            start_at:     { type: 'string', format: 'date-time' },
            duration_min: { type: 'integer', minimum: 15, maximum: 480 },
            buffer_min:   { type: 'integer', minimum: 0,  maximum: 60 },
            zone:         { type: 'string' },
            notes:        { type: 'string' },
            special_requests: { type: 'string' },
            is_vip:       { type: 'boolean' },
          },
        },
        TakeoverConversation: {
          type: 'object',
          required: ['agent_name'],
          properties: { agent_name: { type: 'string', description: 'Name shown to the customer when the human agent replies' } },
        },
      },
    },
  };
}

async function handleGET(req: Request) {
  const url = new URL(req.url);
  const baseUrl = `${url.protocol}//${url.host}/api/v1`;
  const spec = buildSpec(baseUrl);
  return NextResponse.json(spec, {
    headers: {
      // Allow third-party SDK generators to fetch the spec from a browser.
      'Access-Control-Allow-Origin': '*',
      'Cache-Control': 'public, max-age=300',
    },
  });
}

export const GET = wrapRouteHandler(handleGET);
