// OpenAPI 3.0 spec for the streamreverse REST API.
// Served at GET /api.json and rendered by Swagger UI at GET /.

const spec = {
  openapi: '3.0.3',
  info: {
    title: 'bug.tv api',
    version: '1.0.0'
  },
  tags: [
    { name: 'meta', description: 'service and provider metadata' },
    { name: 'search', description: 'TMDB search and episode browsing' },
    { name: 'details', description: 'TMDB media details' },
    { name: 'streams', description: 'm3u8 stream lookup from providers' },
  ],
  paths: {
    '/providers': {
      get: {
        tags: ['meta'],
        summary: 'List all providers and which are enabled',
        operationId: 'listProviders',
        responses: {
          200: {
            description: 'provider list',
            content: {
              'application/json': {
                schema: {
                  type: 'object',
                  properties: {
                    all: { type: 'array', items: { type: 'string' } },
                    enabled: { type: 'array', items: { type: 'string' } },
                  },
                },
              },
            },
          },
        },
      },
    },
    '/proxy/media': {
      get: {
        tags: ['meta'],
        summary: 'Proxy upstream media or m3u8 playlists with server-side headers',
        operationId: 'proxyMedia',
        parameters: [
          {
            name: 'url',
            in: 'query',
            required: true,
            schema: { type: 'string' },
          },
          {
            name: 'h',
            in: 'query',
            required: false,
            description: 'JSON-encoded headers to send to the upstream URL',
            schema: { type: 'string' },
          },
        ],
        responses: {
          200: {
            description: 'Proxied upstream response. m3u8 playlist URIs are rewritten to use the proxy.',
          },
          400: { $ref: '#/components/responses/BadRequest' },
          502: { $ref: '#/components/responses/Upstream' },
        },
      },
    },
    '/search': {
      get: {
        tags: ['search'],
        summary: 'Search movies + TV via TMDB',
        operationId: 'search',
        parameters: [
          {
            name: 'q',
            in: 'query',
            required: true,
            description: 'search text',
            schema: { type: 'string' },
            example: 'dune',
          },
        ],
        responses: {
          200: {
            description: 'up to 15 results',
            content: {
              'application/json': {
                schema: {
                  type: 'object',
                  properties: {
                    query: { type: 'string' },
                    count: { type: 'integer' },
                    results: { type: 'array', items: { $ref: '#/components/schemas/SearchResult' } },
                  },
                },
              },
            },
          },
          400: { $ref: '#/components/responses/BadRequest' },
          502: { $ref: '#/components/responses/Upstream' },
        },
      },
    },
    '/trending': {
      get: {
        tags: ['search'],
        summary: 'Trending movies and TV via TMDB',
        operationId: 'getTrending',
        parameters: [
          {
            name: 'type',
            in: 'query',
            required: false,
            schema: { type: 'string', enum: ['all', 'movie', 'tv'], default: 'all' },
          },
          {
            name: 'window',
            in: 'query',
            required: false,
            schema: { type: 'string', enum: ['day', 'week'], default: 'week' },
          },
        ],
        responses: {
          200: {
            description: 'up to 20 trending items',
            content: {
              'application/json': {
                schema: {
                  type: 'object',
                  properties: {
                    type: { type: 'string' },
                    window: { type: 'string' },
                    count: { type: 'integer' },
                    results: { type: 'array', items: { $ref: '#/components/schemas/SearchResult' } },
                  },
                },
              },
            },
          },
          400: { $ref: '#/components/responses/BadRequest' },
          502: { $ref: '#/components/responses/Upstream' },
        },
      },
    },
    '/movie/{id}': {
      get: {
        tags: ['details'],
        summary: 'Movie details (genres, rating, images, description)',
        description: 'Passes through the raw TMDB movie object, plus `poster_url`/`backdrop_url` convenience fields.',
        operationId: 'getMovieDetails',
        parameters: [{ $ref: '#/components/parameters/MovieId' }],
        responses: {
          200: {
            description: 'TMDB movie object',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/MediaDetails' } } },
          },
          404: { $ref: '#/components/responses/NotFound' },
          502: { $ref: '#/components/responses/Upstream' },
        },
      },
    },
    '/tv/{id}': {
      get: {
        tags: ['details'],
        summary: 'TV show details (genres, rating, images, description)',
        description: 'Passes through the raw TMDB tv object, plus `poster_url`/`backdrop_url` convenience fields.',
        operationId: 'getTvDetails',
        parameters: [{ $ref: '#/components/parameters/TvId' }],
        responses: {
          200: {
            description: 'TMDB tv object',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/MediaDetails' } } },
          },
          404: { $ref: '#/components/responses/NotFound' },
          502: { $ref: '#/components/responses/Upstream' },
        },
      },
    },
    '/tv/{id}/seasons': {
      get: {
        tags: ['search'],
        summary: 'List seasons for a TV show',
        operationId: 'getSeasons',
        parameters: [{ $ref: '#/components/parameters/TvId' }],
        responses: {
          200: {
            description: 'season list',
            content: {
              'application/json': {
                schema: {
                  type: 'object',
                  properties: {
                    tmdb_id: { type: 'string' },
                    count: { type: 'integer' },
                    seasons: { type: 'array', items: { $ref: '#/components/schemas/Season' } },
                  },
                },
              },
            },
          },
          400: { $ref: '#/components/responses/BadRequest' },
          502: { $ref: '#/components/responses/Upstream' },
        },
      },
    },
    '/tv/{id}/seasons/{season}': {
      get: {
        tags: ['search'],
        summary: 'List episodes for a season',
        operationId: 'getEpisodes',
        parameters: [
          { $ref: '#/components/parameters/TvId' },
          {
            name: 'season',
            in: 'path',
            required: true,
            description: 'season number',
            schema: { type: 'integer' },
            example: 1,
          },
        ],
        responses: {
          200: {
            description: 'episode list',
            content: {
              'application/json': {
                schema: {
                  type: 'object',
                  properties: {
                    tmdb_id: { type: 'string' },
                    season: { type: 'integer' },
                    count: { type: 'integer' },
                    episodes: { type: 'array', items: { $ref: '#/components/schemas/Episode' } },
                  },
                },
              },
            },
          },
          400: { $ref: '#/components/responses/BadRequest' },
          502: { $ref: '#/components/responses/Upstream' },
        },
      },
    },
    '/streams': {
      get: {
        tags: ['streams'],
        summary: 'Fetch m3u8 streams for a movie or TV episode',
        operationId: 'getStreams',
        description:
          'Scrapes every enabled provider in parallel (override with `providers`) and returns deduped, normalized, quality-ranked streams. ' +
          'For `type=tv` you must pass `season` and `episode`. Optional filters are applied before ranking.',
        parameters: [
          {
            name: 'tmdb',
            in: 'query',
            required: true,
            description: 'TMDB numeric id',
            schema: { type: 'integer' },
            example: 438631,
          },
          {
            name: 'type',
            in: 'query',
            required: false,
            description: 'movie (default) or tv',
            schema: { type: 'string', enum: ['movie', 'tv'], default: 'movie' },
          },
          {
            name: 'season',
            in: 'query',
            required: false,
            description: 'season number (required when type=tv)',
            schema: { type: 'integer' },
          },
          {
            name: 'episode',
            in: 'query',
            required: false,
            description: 'episode number (required when type=tv)',
            schema: { type: 'integer' },
          },
          {
            name: 'providers',
            in: 'query',
            required: false,
            description: 'comma-separated provider names; defaults to the enabled set',
            schema: { type: 'string' },
            example: 'videasy,vidfast',
          },
          {
            name: 'minQuality',
            in: 'query',
            required: false,
            schema: { type: 'string', enum: ['any', '480', '720', '1080', '2160'], default: 'any' },
          },
          {
            name: 'audioCodec',
            in: 'query',
            required: false,
            schema: { type: 'string', enum: ['any', 'aac', 'ac3', 'dts', 'opus', 'mp3', 'flac'], default: 'any' },
          },
          {
            name: 'subtitles',
            in: 'query',
            required: false,
            schema: { type: 'string', enum: ['any', 'required', 'lang'], default: 'any' },
          },
          {
            name: 'subtitleLang',
            in: 'query',
            required: false,
            description: 'two-letter lang code, used when subtitles=lang',
            schema: { type: 'string' },
            example: 'en',
          },
        ],
        responses: {
          200: {
            description: 'stream list (best quality first)',
            content: {
              'application/json': {
                schema: { $ref: '#/components/schemas/StreamList' },
              },
            },
          },
          400: { $ref: '#/components/responses/BadRequest' },
          500: {
            description: 'no providers available / internal error',
            content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } },
          },
        },
      },
    },
  },
  components: {
    parameters: {
      MovieId: {
        name: 'id',
        in: 'path',
        required: true,
        description: 'TMDB movie id',
        schema: { type: 'integer' },
        example: 438631,
      },
      TvId: {
        name: 'id',
        in: 'path',
        required: true,
        description: 'TMDB tv id',
        schema: { type: 'integer' },
        example: 1396,
      },
    },
    responses: {
      BadRequest: {
        description: 'missing or invalid parameters',
        content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } },
      },
      NotFound: {
        description: 'media id not found on TMDB',
        content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } },
      },
      Upstream: {
        description: 'TMDB request failed',
        content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } },
      },
    },
    schemas: {
      Error: {
        type: 'object',
        properties: { error: { type: 'string' } },
      },
      SearchResult: {
        type: 'object',
        properties: {
          tmdb_id: { type: 'integer', example: 438631 },
          type: { type: 'string', enum: ['movie', 'tv'] },
          name: { type: 'string', example: 'Dune' },
          year: { type: 'string', example: '2021' },
          poster: { type: 'string', format: 'uri' },
          overview: { type: 'string' },
        },
      },
      MediaDetails: {
        type: 'object',
        description: 'raw TMDB media object (movie or tv) with added poster_url/backdrop_url',
        properties: {
          id: { type: 'integer', example: 438631 },
          title: { type: 'string', description: 'movie title' },
          name: { type: 'string', description: 'tv show name' },
          overview: { type: 'string', description: 'description' },
          tagline: { type: 'string' },
          genres: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                id: { type: 'integer' },
                name: { type: 'string' },
              },
            },
          },
          vote_average: { type: 'number', description: 'rating, 0-10' },
          vote_count: { type: 'integer' },
          popularity: { type: 'number' },
          status: { type: 'string' },
          runtime: { type: 'integer', description: 'movie runtime in minutes' },
          number_of_seasons: { type: 'integer', description: 'tv' },
          number_of_episodes: { type: 'integer', description: 'tv' },
          release_date: { type: 'string', format: 'date', description: 'movie' },
          first_air_date: { type: 'string', format: 'date', description: 'tv' },
          poster_path: { type: 'string' },
          backdrop_path: { type: 'string' },
          poster_url: { type: 'string', format: 'uri', description: 'full url (original size)' },
          backdrop_url: { type: 'string', format: 'uri', description: 'full url (original size)' },
          images: {
            type: 'object',
            description:
              'all available images from TMDB (posters, backdrops, logos, profiles); every item includes `url` with the full image url',
          },
        },
        additionalProperties: true,
      },
      Season: {
        type: 'object',
        properties: {
          season_number: { type: 'integer' },
          name: { type: 'string' },
          episode_count: { type: 'integer' },
          air_date: { type: 'string', format: 'date' },
        },
      },
      Episode: {
        type: 'object',
        properties: {
          episode_number: { type: 'integer' },
          name: { type: 'string' },
          air_date: { type: 'string', format: 'date' },
        },
      },
      Subtitle: {
        type: 'object',
        properties: {
          url: { type: 'string', format: 'uri' },
          language: { type: 'string' },
          name: { type: 'string' },
        },
      },
      Stream: {
        type: 'object',
        properties: {
          provider: { type: 'string', example: 'videasy' },
          name: { type: 'string' },
          url: { type: 'string', format: 'uri', description: 'the m3u8 (or direct) url' },
          quality: { type: 'string', example: '2160p' },
          pixels: { type: ['integer', 'null'], example: 2160 },
          audio: { type: ['string', 'null'], example: 'aac' },
          type: { type: 'string', example: 'm3u8' },
          headers: {
            type: 'object',
            description: 'http headers the url needs (e.g. Referer)',
            additionalProperties: { type: 'string' },
          },
          subtitles: { type: 'array', items: { $ref: '#/components/schemas/Subtitle' } },
        },
      },
      StreamList: {
        type: 'object',
        properties: {
          tmdb_id: { type: 'integer' },
          type: { type: 'string', enum: ['movie', 'tv'] },
          season: { type: ['integer', 'null'] },
          episode: { type: ['integer', 'null'] },
          total: { type: 'integer', description: 'streams before filters' },
          matched: { type: 'integer', description: 'streams after filters' },
          streams: { type: 'array', items: { $ref: '#/components/schemas/Stream' } },
          providerErrors: {
            type: 'object',
            description: 'per-provider scrape errors',
            additionalProperties: { type: 'string' },
          },
          loadErrors: {
            type: 'object',
            description: 'per-provider load errors',
            additionalProperties: { type: 'string' },
          },
        },
      },
    },
  },
};

module.exports = spec;
