# frozen_string_literal: true

require 'rails_helper'
require 'rspec_api_documentation/dsl'

resource 'ContentBuilderLayouts' do
  explanation 'Content builder layouts for projects.'

  before { header 'Content-Type', 'application/json' }

  context 'when not authorized' do
    let(:user) { create(:user) }
    let(:project) { create(:project) }
    let!(:layout) { create(:layout, content_buildable: project) }
    let(:project_id) { project.id }
    let(:code) { layout.code }

    get 'web_api/v1/projects/:project_id/content_builder_layouts/:code' do
      example_request 'Get one layout by project_id and code' do
        assert_status 200

        json_response = json_parse(response_body)
        expect(json_response).to include(
          {
            data: {
              id: layout.id,
              type: 'content_builder_layout',
              attributes: hash_including(
                code: code,
                created_at: match(time_regex),
                updated_at: match(time_regex)
              )
            }
          }
        )
      end
    end

    context 'when the layout does not exist' do
      let(:layout) { create(:layout) }
      let(:project_id) { layout.content_buildable_id }
      let(:code) { 'unknown' }

      post 'web_api/v1/projects/:project_id/content_builder_layouts/:code/upsert' do
        example_request '[error] Try to create a layout for a project without authorization' do
          expect(status).to eq 401
        end
      end
    end

    context 'when the layout exists' do
      let(:layout) { create(:layout) }
      let(:project_id) { layout.content_buildable_id }
      let(:code) { layout.code }

      post 'web_api/v1/projects/:project_id/content_builder_layouts/:code/upsert' do
        example_request '[error] Try to update a layout of a project without authorization' do
          expect(status).to eq 401
        end
      end

      delete 'web_api/v1/projects/:project_id/content_builder_layouts/:code' do
        example_request '[error] Try to delete a layout of a project without authorization' do
          expect(status).to eq 401
        end
      end
    end
  end

  context 'when admin' do
    before { admin_header_token }

    describe 'GET' do
      context 'when the layout exists' do
        let(:layout) { create(:layout) }
        let(:project_id) { layout.content_buildable_id }
        let(:code) { layout.code }

        get 'web_api/v1/projects/:project_id/content_builder_layouts/:code' do
          example_request 'Get one layout by project_id and code' do
            expect(status).to eq 200
          end
        end
      end

      context 'when the project does not exist' do
        let(:layout) { create(:layout) }
        let(:project_id) { 'unknown' }
        let(:code) { layout.code }

        get 'web_api/v1/projects/:project_id/content_builder_layouts/:code' do
          example_request '[error] Try to get a layout of a project when the project does not exist' do
            expect(status).to eq 404
          end
        end
      end

      context 'when no layout with the given code exists for the given project' do
        let(:layout) { create(:layout) }
        let(:project_id) { layout.content_buildable_id }
        let(:code) { 'unknown' }

        get 'web_api/v1/projects/:project_id/content_builder_layouts/:code' do
          example_request '[error] Try to get a layout of a project when the code is unknown' do
            expect(status).to eq 404
          end
        end
      end
    end

    describe 'POST' do
      with_options scope: :content_builder_layout do
        parameter :enabled, 'Indicates that the layout is enabled.'
        parameter :craftjs_json, 'The craftjs layout configuration'
      end

      context 'when the project does not exist' do
        let(:layout) { create(:layout) }
        let(:project_id) { 'unknown' }
        let(:code) { layout.code }

        post 'web_api/v1/projects/:project_id/content_builder_layouts/:code/upsert' do
          example_request '[error] Try to upsert a layout for a project that does not exist' do
            expect(status).to eq 404
          end
        end
      end

      context 'when the layout does not exist' do
        let(:project) { create(:project) }
        let(:project_id) { project.id }
        let(:code) { 'project_description' }
        let(:enabled) { true }
        let :craftjs_json do
          {
            ROOT: {
              type: {
                resolvedName: 'Container'
              }
            }
          }
        end

        post 'web_api/v1/projects/:project_id/content_builder_layouts/:code/upsert' do
          example_request 'Create a layout for a project' do
            assert_status 201
            json_response = json_parse(response_body)
            expect(json_response).to include(
              {
                data: {
                  id: be_a(String),
                  type: 'content_builder_layout',
                  attributes: {
                    craftjs_json: {
                      ROOT: {
                        type: {
                          resolvedName: 'Container'
                        }
                      }
                    },
                    enabled: true,
                    code: code,
                    created_at: match(time_regex),
                    updated_at: match(time_regex)
                  }
                }
              }
            )
            created_at = json_response.dig(:data, :attributes, :created_at)
            updated_at = json_response.dig(:data, :attributes, :updated_at)
            expect(updated_at).to eq created_at
          end
        end
      end

      context 'when the layout exists' do
        let(:project_id) { layout.content_buildable_id }
        let(:code) { layout.code }

        describe 'updating one locale' do
          let! :layout do
            create(:layout, craftjs_json: { ROOT: {} })
          end
          let :craftjs_json do
            {
              ROOT: {
                type: {
                  resolvedName: 'Container'
                }
              }
            }
          end

          post 'web_api/v1/projects/:project_id/content_builder_layouts/:code/upsert' do
            example_request 'Update one locale of a layout of a project' do
              assert_status 200
              json_response = json_parse(response_body)
              expect(json_response).to include(
                {
                  data: {
                    id: layout.id,
                    type: 'content_builder_layout',
                    attributes: {
                      craftjs_json: {
                        ROOT: {
                          type: {
                            resolvedName: 'Container'
                          }
                        }
                      },
                      enabled: true,
                      code: code,
                      created_at: match(time_regex),
                      updated_at: match(time_regex)
                    }
                  }
                }
              )
              created_at = json_response.dig(:data, :attributes, :created_at)
              updated_at = json_response.dig(:data, :attributes, :updated_at)
              expect(updated_at).to be > created_at
            end
          end
        end

        describe 'disabling a layout' do
          let! :layout do
            create(
              :layout,
              craftjs_json: { ROOT: {} }
            )
          end
          let(:enabled) { false }

          post 'web_api/v1/projects/:project_id/content_builder_layouts/:code/upsert' do
            example_request 'Disable a layout of a project' do
              assert_status 200
              json_response = json_parse(response_body)
              expect(json_response).to include(
                {
                  data: {
                    id: layout.id,
                    type: 'content_builder_layout',
                    attributes: {
                      craftjs_json: { ROOT: {} },
                      enabled: false,
                      code: code,
                      created_at: match(time_regex),
                      updated_at: match(time_regex)
                    }
                  }
                }
              )
              created_at = json_response.dig(:data, :attributes, :created_at)
              updated_at = json_response.dig(:data, :attributes, :updated_at)
              expect(updated_at).to be > created_at
            end
          end
        end

        describe 'enabling a layout' do
          let! :layout do
            create(
              :layout,
              enabled: false,
              craftjs_json: { ROOT: {} }
            )
          end
          let(:enabled) { true }

          post 'web_api/v1/projects/:project_id/content_builder_layouts/:code/upsert' do
            example_request 'Enable a layout of a project' do
              assert_status 200
              json_response = json_parse(response_body)
              expect(json_response).to include(
                {
                  data: {
                    id: layout.id,
                    type: 'content_builder_layout',
                    attributes: {
                      craftjs_json: { ROOT: {} },
                      enabled: true,
                      code: code,
                      created_at: match(time_regex),
                      updated_at: match(time_regex)
                    }
                  }
                }
              )
              created_at = json_response.dig(:data, :attributes, :created_at)
              updated_at = json_response.dig(:data, :attributes, :updated_at)
              expect(updated_at).to be > created_at
            end
          end
        end
      end
    end

    describe 'DELETE' do
      context 'when the layout exists' do
        let(:layout) { create(:layout) }
        let(:project_id) { layout.content_buildable_id }
        let(:code) { layout.code }

        delete 'web_api/v1/projects/:project_id/content_builder_layouts/:code' do
          example_request 'Delete one layout by project_id and code' do
            expect(status).to eq 200
          end
        end
      end

      context 'when the project does not exist' do
        let(:layout) { create(:layout) }
        let(:project_id) { 'unknown' }
        let(:code) { layout.code }

        delete 'web_api/v1/projects/:project_id/content_builder_layouts/:code' do
          example_request '[error] Try to delete a layout of a project when the project does not exist' do
            expect(status).to eq 404
          end
        end
      end

      context 'when no layout with the given code exists for the given project' do
        let(:layout) { create(:layout) }
        let(:project_id) { layout.content_buildable_id }
        let(:code) { 'unknown' }

        delete 'web_api/v1/projects/:project_id/content_builder_layouts/:code' do
          example_request '[error] Try to delete a layout of a project when the code is unknown' do
            expect(status).to eq 404
          end
        end
      end
    end
  end
end
