# frozen_string_literal: true
require 'swagger_helper'

RSpec.describe 'topics' do

  let(:'Api-Key') { Fabricate(:api_key).key }
  let(:'Api-Username') { 'system' }

  path '/t/{id}/posts.json' do
    get 'Get specific posts from a topic' do
      tags 'Topics'
      operationId 'getSpecificPostsFromTopic'
      consumes 'application/json'
      parameter name: 'Api-Key', in: :header, type: :string, required: true
      parameter name: 'Api-Username', in: :header, type: :string, required: true
      parameter name: :id, in: :path, schema: { type: :string }

      parameter name: :post_body, in: :body, schema: {
        type: :object,
        properties: {
          'post_ids[]': { type: :integer }
        }, required: [ 'post_ids[]' ]
      }

      produces 'application/json'
      response '200', 'specific posts' do
        schema type: :object, properties: {
          post_stream: {
            type: :object,
            properties: {
              posts: {
                type: :array,
                items: {
                  type: :object,
                  properties: {
                    id: { type: :integer },
                    name: { type: [:string, :null] },
                    username: { type: :string },
                    avatar_template: { type: :string },
                    created_at: { type: :string },
                    cooked: { type: :string },
                    post_number: { type: :integer },
                    post_type: { type: :integer },
                    updated_at: { type: :string },
                    reply_count: { type: :integer },
                    reply_to_post_number: { type: [:string, :null] },
                    quote_count: { type: :integer },
                    incoming_link_count: { type: :integer },
                    reads: { type: :integer },
                    readers_count: { type: :integer },
                    score: { type: :integer },
                    yours: { type: :boolean },
                    topic_id: { type: :integer },
                    topic_slug: { type: :string },
                    display_username: { type: [:string, :null] },
                    primary_group_name: { type: [:string, :null] },
                    flair_name: { type: [:string, :null] },
                    flair_url: { type: [:string, :null] },
                    flair_bg_color: { type: [:string, :null] },
                    flair_color: { type: [:string, :null] },
                    version: { type: :integer },
                    can_edit: { type: :boolean },
                    can_delete: { type: :boolean },
                    can_recover: { type: :boolean },
                    can_wiki: { type: :boolean },
                    read: { type: :boolean },
                    user_title: { type: [:string, :null] },
                    actions_summary: {
                      type: :array,
                      items: {
                        type: :object,
                        properties: {
                          id: { type: :integer },
                          can_act: { type: :boolean },
                        }
                      },
                    },
                    moderator: { type: :boolean },
                    admin: { type: :boolean },
                    staff: { type: :boolean },
                    user_id: { type: :integer },
                    hidden: { type: :boolean },
                    trust_level: { type: :integer },
                    deleted_at: { type: [:string, :null] },
                    user_deleted: { type: :boolean },
                    edit_reason: { type: [:string, :null] },
                    can_view_edit_history: { type: :boolean },
                    wiki: { type: :boolean },
                    reviewable_id: { type: :integer },
                    reviewable_score_count: { type: :integer },
                    reviewable_score_pending_count: { type: :integer },
                  }
                },
              },
            }
          },
          id: { type: :integer },
        }

        let(:post_body) { { 'post_ids[]': 1 } }
        let(:id) { Fabricate(:topic).id }

        run_test!
      end
    end
  end

  path '/t/{id}.json' do
    get 'Get a single topic' do
      tags 'Topics'
      operationId 'getTopic'
      consumes 'application/json'
      parameter name: 'Api-Key', in: :header, type: :string, required: true
      parameter name: 'Api-Username', in: :header, type: :string, required: true
      parameter name: :id, in: :path, schema: { type: :string }
      expected_request_schema = nil

      produces 'application/json'
      response '200', 'specific posts' do

        let(:id) { Fabricate(:topic).id }

        expected_response_schema = load_spec_schema('topic_show_response')
        schema expected_response_schema

        it_behaves_like "a JSON endpoint", 200 do
          let(:expected_response_schema) { expected_response_schema }
          let(:expected_request_schema) { expected_request_schema }
        end
      end
    end

    delete 'Remove a topic' do
      tags 'Topics'
      operationId 'removeTopic'
      consumes 'application/json'
      parameter name: 'Api-Key', in: :header, type: :string, required: true
      parameter name: 'Api-Username', in: :header, type: :string, required: true
      parameter name: :id, in: :path, schema: { type: :string }
      response '200', 'specific posts' do

        let!(:post) { Fabricate(:post) }
        let(:id) { post.topic.id }

        run_test!
      end
    end
  end

  path '/t/-/{id}.json' do
    put 'Update a topic' do
      tags 'Topics'
      operationId 'updateTopic'
      consumes 'application/json'
      parameter name: 'Api-Key', in: :header, type: :string, required: true
      parameter name: 'Api-Username', in: :header, type: :string, required: true
      parameter name: :id, in: :path, schema: { type: :string }

      parameter name: :post_body, in: :body, schema: {
        type: :object,
        properties: {
          topic: {
            type: :object,
            properties: {
              title: { type: :string },
              category_id: { type: :integer },
            }
          }
        }
      }

      produces 'application/json'
      response '200', 'topic updated' do
        schema type: :object, properties: {
          basic_topic: {
            type: :object,
            properties: {
              id: { type: :integer },
              title: { type: :string },
              fancy_title: { type: :string },
              slug: { type: :string },
              posts_count: { type: :integer },
            }
          },
        }

        let(:post_body) { { title: 'New topic title' } }
        let!(:post) { Fabricate(:post) }
        let(:id) { post.topic.id }

        run_test! do |response|
          data = JSON.parse(response.body)
          expect(data['basic_topic']['title']).to eq("New topic title")
        end
      end
    end
  end

  path '/t/{id}/invite.json' do
    post 'Invite to topic' do
      tags 'Topics', 'Invites'
      operationId 'inviteToTopic'
      consumes 'application/json'
      parameter name: 'Api-Key', in: :header, type: :string, required: true
      parameter name: 'Api-Username', in: :header, type: :string, required: true
      parameter name: :id, in: :path, schema: { type: :string }

      parameter name: :request_body, in: :body, schema: {
        type: :object,
        properties: {
          user: { type: :string },
          email: { type: :string },
        }
      }

      produces 'application/json'
      response '200', 'topic updated' do
        schema type: :object, properties: {
          user: {
            type: :object,
            properties: {
              id: { type: :integer },
              username: { type: :string },
              name: { type: :string },
              avatar_template: { type: :string },
            }
          },
        }

        let(:username) { Fabricate(:user).username }
        let(:request_body) { { user: username } }
        let(:id) { Fabricate(:private_message_topic).id }

        run_test! do |response|
          data = JSON.parse(response.body)
          expect(data['user']['username']).to eq(username)
        end
      end
    end
  end

  path '/t/{id}/bookmark.json' do
    put 'Bookmark topic' do
      tags 'Topics'
      operationId 'bookmarkTopic'
      consumes 'application/json'
      parameter name: 'Api-Key', in: :header, type: :string, required: true
      parameter name: 'Api-Username', in: :header, type: :string, required: true
      parameter name: :id, in: :path, schema: { type: :string }

      produces 'application/json'
      response '200', 'topic updated' do

        let!(:post) { Fabricate(:post) }
        let(:id) { post.topic.id }

        run_test!
      end
    end
  end

  path '/t/{id}/status.json' do
    put 'Update the status of a topic' do
      tags 'Topics'
      operationId 'updateTopicStatus'
      consumes 'application/json'
      parameter name: 'Api-Key', in: :header, type: :string, required: true
      parameter name: 'Api-Username', in: :header, type: :string, required: true
      parameter name: :id, in: :path, schema: { type: :string }

      parameter name: :request_body, in: :body, schema: {
        type: :object,
        properties: {
          status: {
            type: :string,
            enum: ['closed', 'pinned', 'pinned_globally', 'archived', 'visible'],
          },
          enabled: {
            type: :string,
            enum: ['true', 'false']
          },
          until: {
            type: :string,
            description: 'Only required for `pinned` and `pinned_globally`',
            example: '2030-12-31'
          }
        }, required: [ 'status', 'enabled' ]
      }

      produces 'application/json'
      response '200', 'topic updated' do
        schema type: :object, properties: {
          success: { type: :string, example: "OK" },
          topic_status_update: { type: [:string, :null] },
        }

        let(:request_body) { { status: 'closed', enabled: 'true' } }
        let(:id) { Fabricate(:topic).id }

        run_test!
      end
    end
  end

  path '/latest.json' do
    get 'Get the latest topics' do
      tags 'Topics'
      operationId 'listLatestTopics'
      consumes 'application/json'
      parameter name: 'Api-Key', in: :header, type: :string, required: true
      parameter name: 'Api-Username', in: :header, type: :string, required: true
      parameter(
        name: :order,
        in: :query,
        type: :string,
        description: 'Enum: `default`, `created`, `activity`, `views`, `posts`, `category`, `likes`, `op_likes`, `posters`')
      parameter(
        name: :ascending,
        in: :query,
        type: :string,
        description: 'Defaults to `desc`, add `ascending=true` to sort asc')

      produces 'application/json'
      response '200', 'topic updated' do
        schema type: :object, properties: {
          users: {
            type: :array,
            items: {
              type: :object,
              properties: {
                id: { type: :integer },
                username: { type: :string },
                name: { type: [:string, :null] },
                avatar_template: { type: :string },
              }
            },
          },
          primary_groups: {
            type: :array,
            items: {},
          },
          topic_list: {
            type: :object,
            properties: {
              can_create_topic: { type: :boolean },
              draft: { type: [:string, :null] },
              draft_key: { type: :string },
              draft_sequence: { type: :integer },
              per_page: { type: :integer },
              topics: {
                type: :array,
                items: {
                  type: :object,
                  properties: {
                    id: { type: :integer },
                    title: { type: :string },
                    fancy_title: { type: :string },
                    slug: { type: :string },
                    posts_count: { type: :integer },
                    reply_count: { type: :integer },
                    highest_post_number: { type: :integer },
                    image_url: { type: :string },
                    created_at: { type: :string },
                    last_posted_at: { type: :string },
                    bumped: { type: :boolean },
                    bumped_at: { type: :string },
                    archetype: { type: :string },
                    unseen: { type: :boolean },
                    last_read_post_number: { type: :integer },
                    unread_posts: { type: :integer },
                    pinned: { type: :boolean },
                    unpinned: { type: [:string, :null] },
                    visible: { type: :boolean },
                    closed: { type: :boolean },
                    archived: { type: :boolean },
                    notification_level: { type: :integer },
                    bookmarked: { type: :boolean },
                    liked: { type: :boolean },
                    views: { type: :integer },
                    like_count: { type: :integer },
                    has_summary: { type: :boolean },
                    last_poster_username: { type: :string },
                    category_id: { type: :integer },
                    op_like_count: { type: :integer },
                    pinned_globally: { type: :boolean },
                    featured_link: { type: [:string, :null] },
                    posters: {
                      type: :array,
                      items: {
                        type: :object,
                        properties: {
                          extras: { type: :string },
                          description: { type: :string },
                          user_id: { type: :integer },
                          primary_group_id: { type: [:string, :null] },
                        }
                      },
                    },
                  }
                },
              },
            }
          },
        }

        let(:order) { 'default' }
        let(:ascending) { 'false' }

        run_test!
      end
    end
  end

  path '/top.json' do
    get 'Get the top topics filtered by period' do
      tags 'Topics'
      operationId 'listTopTopics'
      consumes 'application/json'
      parameter name: 'Api-Key', in: :header, type: :string, required: true
      parameter name: 'Api-Username', in: :header, type: :string, required: true
      parameter(
        name: :period,
        in: :query,
        type: :string,
        description: 'Enum: `all`, `yearly`, `quarterly`, `monthly`, `weekly`, `daily`')

      produces 'application/json'
      response '200', 'response' do
        schema type: :object, properties: {
          users: {
            type: :array,
            items: {
              type: :object,
              properties: {
                id: { type: :integer },
                username: { type: :string },
                name: { type: :string },
                avatar_template: { type: :string },
              }
            },
          },
          primary_groups: {
            type: :array,
            items: {},
          },
          topic_list: {
            type: :object,
            properties: {
              can_create_topic: { type: :boolean },
              draft: { type: [:string, :null] },
              draft_key: { type: :string },
              draft_sequence: { type: :integer },
              for_period: { type: :string },
              per_page: { type: :integer },
              topics: {
                type: :array,
                items: {
                  type: :object,
                  properties: {
                    id: { type: :integer },
                    title: { type: :string },
                    fancy_title: { type: :string },
                    slug: { type: :string },
                    posts_count: { type: :integer },
                    reply_count: { type: :integer },
                    highest_post_number: { type: :integer },
                    image_url: { type: [:string, :null] },
                    created_at: { type: :string },
                    last_posted_at: { type: :string },
                    bumped: { type: :boolean },
                    bumped_at: { type: :string },
                    archetype: { type: :string },
                    unseen: { type: :boolean },
                    last_read_post_number: { type: :integer },
                    unread_posts: { type: :integer },
                    pinned: { type: :boolean },
                    unpinned: { type: :boolean },
                    visible: { type: :boolean },
                    closed: { type: :boolean },
                    archived: { type: :boolean },
                    notification_level: { type: :integer },
                    bookmarked: { type: :boolean },
                    liked: { type: :boolean },
                    views: { type: :integer },
                    like_count: { type: :integer },
                    has_summary: { type: :boolean },
                    last_poster_username: { type: :string },
                    category_id: { type: :integer },
                    op_like_count: { type: :integer },
                    pinned_globally: { type: :boolean },
                    featured_link: { type: [:string, :null] },
                    posters: {
                      type: :array,
                      items: {
                        type: :object,
                        properties: {
                          extras: { type: [:string, :null] },
                          description: { type: :string },
                          user_id: { type: :integer },
                          primary_group_id: { type: [:string, :null] },
                        }
                      },
                    },
                  }
                },
              },
            }
          },
        }

        let(:period) { 'all' }

        run_test!
      end
    end
  end

  path '/t/{id}/notifications.json' do
    post 'Set notification level' do
      tags 'Topics'
      operationId 'setNotificationLevel'
      consumes 'application/json'
      parameter name: 'Api-Key', in: :header, type: :string, required: true
      parameter name: 'Api-Username', in: :header, type: :string, required: true
      parameter name: :id, in: :path, schema: { type: :string }

      parameter name: :request_body, in: :body, schema: {
        type: :object,
        properties: {
          notification_level: {
            type: :string,
            enum: ['0', '1', '2', '3'],
          }
        }, required: [ 'notification_level' ]
      }

      produces 'application/json'
      response '200', 'topic updated' do
        schema type: :object, properties: {
          success: { type: :string, example: "OK" }
        }

        let(:request_body) { { notification_level: '3' } }
        let(:id) { Fabricate(:topic).id }

        run_test!
      end
    end
  end

  path '/t/{id}/change-timestamp.json' do
    put 'Update topic timestamp' do
      tags 'Topics'
      operationId 'updateTopicTimestamp'
      consumes 'application/json'
      parameter name: 'Api-Key', in: :header, type: :string, required: true
      parameter name: 'Api-Username', in: :header, type: :string, required: true
      parameter name: :id, in: :path, schema: { type: :string }

      parameter name: :request_body, in: :body, schema: {
        type: :object,
        properties: {
          timestamp: {
            type: :string,
            example: '1594291380'
          }
        }, required: [ 'timestamp' ]
      }

      produces 'application/json'
      response '200', 'topic updated' do
        schema type: :object, properties: {
          success: { type: :string, example: "OK" }
        }

        let(:request_body) { { timestamp: '1594291380' } }
        let!(:post) { Fabricate(:post) }
        let(:id) { post.topic.id }

        run_test!
      end
    end
  end

  path '/t/{id}/timer.json' do
    post 'Create topic timer' do
      tags 'Topics'
      operationId 'createTopicTimer'
      consumes 'application/json'
      parameter name: 'Api-Key', in: :header, type: :string, required: true
      parameter name: 'Api-Username', in: :header, type: :string, required: true
      parameter name: :id, in: :path, schema: { type: :string }

      parameter name: :request_body, in: :body, schema: {
        type: :object,
        properties: {
          time: {
            type: :string,
            example: ''
          },
          status_type: {
            type: :string,
          },
          based_on_last_post: {
            type: :boolean,
          },
          category_id: {
            type: :integer
          }
        }
      }

      produces 'application/json'
      response '200', 'topic updated' do
        schema type: :object, properties: {
          success: { type: :string, example: "OK" },
          execute_at: { type: :string },
          duration: { type: [:string, :null] },
          based_on_last_post: { type: :boolean },
          closed: { type: :boolean },
          category_id: { type: [:string, :null] },
        }

        let(:request_body) { { time: Time.current + 1.day, status_type: 'close' } }
        let!(:topic_post) { Fabricate(:post) }
        let(:id) { topic_post.topic.id }

        run_test!
      end
    end
  end

  path '/t/external_id/{external_id}.json' do
    get 'Get topic by external_id' do
      tags 'Topics'
      operationId 'getTopicByExternalId'
      consumes 'application/json'
      parameter name: :external_id, in: :path, type: :string, required: true
      expected_request_schema = nil

      produces 'application/json'
      response '301', 'redirects to /t/{topic_id}.json' do
        expected_response_schema = nil
        schema expected_response_schema

        let(:topic) { Fabricate(:topic, external_id: 'external_id_1') }
        let(:external_id) { topic.external_id }

        run_test! do |response|
          expect(response).to redirect_to(topic.relative_url + ".json")
        end
      end
    end
  end

end