export interface OpenApiBuildOptions {
  baseUrl: string;
  appVersion: string;
}

export function buildOpenApiDocument(options: OpenApiBuildOptions): unknown {
  const { baseUrl, appVersion } = options;
  const roomIdPathParameter = { name: 'roomId', in: 'path', required: true, schema: { type: 'string' } };
  const userIdPathParameter = { name: 'userId', in: 'path', required: true, schema: { type: 'string' } };
  const messageIdPathParameter = { name: 'messageId', in: 'path', required: true, schema: { type: 'string' } };
  const sinceTimestampQueryParameter = {
    name: 'sinceTimestamp',
    in: 'query',
    required: true,
    schema: { type: 'integer', minimum: 0, format: 'int64' }
  };

  return {
    openapi: '3.1.0',
    info: {
      title: 'Toju Local Desktop API',
      version: appVersion,
      description:
        'Authenticated local HTTP API exposed by the Toju desktop app. '
        + 'Authentication is performed against a configured signaling server. '
        + 'Bearer tokens issued here are scoped to this device only.'
    },
    servers: [{ url: baseUrl }],
    components: {
      securitySchemes: {
        bearerAuth: {
          type: 'http',
          scheme: 'bearer',
          bearerFormat: 'opaque'
        }
      },
      schemas: {
        Error: {
          type: 'object',
          required: ['error'],
          properties: {
            error: { type: 'string' },
            errorCode: { type: 'string' }
          }
        },
        LoginRequest: {
          type: 'object',
          required: [
            'username',
            'password',
            'serverUrl'
          ],
          properties: {
            username: { type: 'string' },
            password: { type: 'string' },
            serverUrl: {
              type: 'string',
              format: 'uri',
              description: 'Base URL of the signaling server to authenticate against. Must be in the allowed list configured in the desktop app.'
            }
          }
        },
        LoginResponse: {
          type: 'object',
          required: [
            'token',
            'expiresAt',
            'user'
          ],
          properties: {
            token: { type: 'string' },
            expiresAt: { type: 'integer', format: 'int64' },
            user: { $ref: '#/components/schemas/AuthUser' }
          }
        },
        AuthUser: {
          type: 'object',
          required: [
            'id',
            'username',
            'displayName'
          ],
          properties: {
            id: { type: 'string' },
            username: { type: 'string' },
            displayName: { type: 'string' }
          }
        },
        Profile: {
          type: 'object',
          properties: {
            id: { type: 'string' },
            username: { type: 'string' },
            displayName: { type: 'string' },
            description: { type: 'string' },
            avatarUrl: { type: 'string' },
            status: { type: 'string' }
          }
        },
        Room: {
          type: 'object',
          properties: {
            id: { type: 'string' },
            name: { type: 'string' }
          },
          additionalProperties: true
        },
        User: {
          type: 'object',
          properties: {
            id: { type: 'string' },
            oderId: { type: 'string' },
            username: { type: 'string' },
            displayName: { type: 'string' },
            status: { type: 'string' },
            role: { type: 'string' },
            isOnline: { type: 'boolean' }
          },
          additionalProperties: true
        },
        Message: {
          type: 'object',
          properties: {
            id: { type: 'string' },
            roomId: { type: 'string' },
            channelId: { type: 'string' },
            senderId: { type: 'string' },
            senderName: { type: 'string' },
            content: { type: 'string' },
            timestamp: { type: 'integer', format: 'int64' },
            editedAt: { type: 'integer', format: 'int64' },
            isDeleted: { type: 'boolean' }
          },
          additionalProperties: true
        },
        Reaction: {
          type: 'object',
          properties: {
            id: { type: 'string' },
            messageId: { type: 'string' },
            userId: { type: 'string' },
            oderId: { type: 'string' },
            emoji: { type: 'string' },
            timestamp: { type: 'integer', format: 'int64' }
          },
          additionalProperties: true
        },
        Attachment: {
          type: 'object',
          properties: {
            id: { type: 'string' },
            messageId: { type: 'string' },
            filename: { type: 'string' },
            size: { type: 'integer' },
            mime: { type: 'string' },
            isImage: { type: 'boolean' },
            filePath: { type: 'string' },
            savedPath: { type: 'string' }
          },
          additionalProperties: true
        },
        Ban: {
          type: 'object',
          properties: {
            oderId: { type: 'string' },
            roomId: { type: 'string' },
            userId: { type: 'string' },
            bannedBy: { type: 'string' },
            displayName: { type: 'string' },
            reason: { type: 'string' },
            expiresAt: { type: 'integer', format: 'int64' },
            timestamp: { type: 'integer', format: 'int64' }
          },
          additionalProperties: true
        },
        PluginDataValue: {
          type: 'object',
          properties: {
            value: {}
          }
        },
        MetaValue: {
          type: 'object',
          properties: {
            key: { type: 'string' },
            value: { type: ['string', 'null'] }
          }
        }
      }
    },
    security: [{ bearerAuth: [] }],
    paths: {
      '/api/health': {
        get: {
          security: [],
          summary: 'Liveness probe',
          responses: {
            '200': {
              description: 'Service is alive',
              content: {
                'application/json': {
                  schema: {
                    type: 'object',
                    properties: {
                      status: { type: 'string' },
                      version: { type: 'string' }
                    }
                  }
                }
              }
            }
          }
        }
      },
      '/api/openapi.json': {
        get: {
          security: [],
          summary: 'OpenAPI specification',
          responses: { '200': { description: 'This document' } }
        }
      },
      '/api/auth/login': {
        post: {
          security: [],
          summary: 'Exchange username/password (validated by a signaling server) for a bearer token',
          requestBody: {
            required: true,
            content: {
              'application/json': {
                schema: { $ref: '#/components/schemas/LoginRequest' }
              }
            }
          },
          responses: {
            '200': {
              description: 'Token issued',
              content: {
                'application/json': {
                  schema: { $ref: '#/components/schemas/LoginResponse' }
                }
              }
            },
            '401': {
              description: 'Invalid credentials',
              content: {
                'application/json': { schema: { $ref: '#/components/schemas/Error' } }
              }
            },
            '403': {
              description: 'Signaling server URL not allowed',
              content: {
                'application/json': { schema: { $ref: '#/components/schemas/Error' } }
              }
            }
          }
        }
      },
      '/api/auth/logout': {
        post: {
          summary: 'Revoke the current bearer token',
          responses: { '204': { description: 'Token revoked' } }
        }
      },
      '/api/profile': {
        get: {
          summary: 'Get the current user profile',
          responses: {
            '200': {
              description: 'Current user profile',
              content: {
                'application/json': {
                  schema: { $ref: '#/components/schemas/Profile' }
                }
              }
            },
            '404': {
              description: 'No current user is set on this device',
              content: {
                'application/json': { schema: { $ref: '#/components/schemas/Error' } }
              }
            }
          }
        }
      },
      '/api/rooms': {
        get: {
          summary: 'List rooms (servers) known to this device',
          responses: {
            '200': {
              description: 'Rooms array',
              content: {
                'application/json': {
                  schema: {
                    type: 'array',
                    items: { $ref: '#/components/schemas/Room' }
                  }
                }
              }
            }
          }
        }
      },
      '/api/rooms/{roomId}': {
        get: {
          summary: 'Get a room by id',
          parameters: [roomIdPathParameter],
          responses: {
            '200': {
              description: 'Room details',
              content: {
                'application/json': {
                  schema: { $ref: '#/components/schemas/Room' }
                }
              }
            },
            '404': {
              description: 'Room not found',
              content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } }
            }
          }
        }
      },
      '/api/rooms/{roomId}/users': {
        get: {
          summary: 'List users known for a room',
          parameters: [roomIdPathParameter],
          responses: {
            '200': {
              description: 'Users array',
              content: {
                'application/json': {
                  schema: { type: 'array', items: { $ref: '#/components/schemas/User' } }
                }
              }
            }
          }
        }
      },
      '/api/rooms/{roomId}/messages': {
        get: {
          summary: 'List messages for a room',
          parameters: [
            roomIdPathParameter,
            { name: 'limit', in: 'query', required: false, schema: { type: 'integer', minimum: 1, maximum: 500 } },
            { name: 'offset', in: 'query', required: false, schema: { type: 'integer', minimum: 0 } }
          ],
          responses: {
            '200': {
              description: 'Messages array',
              content: {
                'application/json': {
                  schema: {
                    type: 'array',
                    items: { $ref: '#/components/schemas/Message' }
                  }
                }
              }
            }
          }
        }
      },
      '/api/rooms/{roomId}/messages/since': {
        get: {
          summary: 'List room messages after a timestamp',
          parameters: [roomIdPathParameter, sinceTimestampQueryParameter],
          responses: {
            '200': {
              description: 'Messages array',
              content: {
                'application/json': {
                  schema: { type: 'array', items: { $ref: '#/components/schemas/Message' } }
                }
              }
            }
          }
        }
      },
      '/api/rooms/{roomId}/bans': {
        get: {
          summary: 'List active bans for a room',
          parameters: [roomIdPathParameter],
          responses: {
            '200': {
              description: 'Bans array',
              content: {
                'application/json': {
                  schema: { type: 'array', items: { $ref: '#/components/schemas/Ban' } }
                }
              }
            }
          }
        }
      },
      '/api/rooms/{roomId}/bans/{userId}': {
        get: {
          summary: 'Check whether a user is banned in a room',
          parameters: [roomIdPathParameter, userIdPathParameter],
          responses: {
            '200': {
              description: 'Ban status',
              content: {
                'application/json': {
                  schema: {
                    type: 'object',
                    required: ['isBanned'],
                    properties: { isBanned: { type: 'boolean' } }
                  }
                }
              }
            }
          }
        }
      },
      '/api/messages/{messageId}': {
        get: {
          summary: 'Get a message by id',
          parameters: [messageIdPathParameter],
          responses: {
            '200': {
              description: 'Message details',
              content: {
                'application/json': {
                  schema: { $ref: '#/components/schemas/Message' }
                }
              }
            },
            '404': {
              description: 'Message not found',
              content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } }
            }
          }
        }
      },
      '/api/messages/{messageId}/reactions': {
        get: {
          summary: 'List reactions for a message',
          parameters: [messageIdPathParameter],
          responses: {
            '200': {
              description: 'Reactions array',
              content: {
                'application/json': {
                  schema: { type: 'array', items: { $ref: '#/components/schemas/Reaction' } }
                }
              }
            }
          }
        }
      },
      '/api/messages/{messageId}/attachments': {
        get: {
          summary: 'List attachments for a message',
          parameters: [messageIdPathParameter],
          responses: {
            '200': {
              description: 'Attachments array',
              content: {
                'application/json': {
                  schema: { type: 'array', items: { $ref: '#/components/schemas/Attachment' } }
                }
              }
            }
          }
        }
      },
      '/api/users/{userId}': {
        get: {
          summary: 'Get a user by id',
          parameters: [userIdPathParameter],
          responses: {
            '200': {
              description: 'User details',
              content: {
                'application/json': {
                  schema: { $ref: '#/components/schemas/User' }
                }
              }
            },
            '404': {
              description: 'User not found',
              content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } }
            }
          }
        }
      },
      '/api/attachments': {
        get: {
          summary: 'List all attachments stored on this device',
          responses: {
            '200': {
              description: 'Attachments array',
              content: {
                'application/json': {
                  schema: { type: 'array', items: { $ref: '#/components/schemas/Attachment' } }
                }
              }
            }
          }
        }
      },
      '/api/plugin-data': {
        get: {
          summary: 'Read a plugin data value',
          parameters: [
            { name: 'pluginId', in: 'query', required: true, schema: { type: 'string' } },
            { name: 'key', in: 'query', required: true, schema: { type: 'string' } },
            { name: 'scope', in: 'query', required: true, schema: { type: 'string', enum: ['local', 'server'] } },
            { name: 'serverId', in: 'query', required: false, schema: { type: 'string' } }
          ],
          responses: {
            '200': {
              description: 'Plugin data value',
              content: {
                'application/json': {
                  schema: { $ref: '#/components/schemas/PluginDataValue' }
                }
              }
            }
          }
        }
      },
      '/api/meta/{key}': {
        get: {
          summary: 'Read a desktop metadata value',
          parameters: [{ name: 'key', in: 'path', required: true, schema: { type: 'string' } }],
          responses: {
            '200': {
              description: 'Metadata value',
              content: {
                'application/json': {
                  schema: { $ref: '#/components/schemas/MetaValue' }
                }
              }
            }
          }
        }
      }
    }
  };
}
