/**
 * @format
 * @jest-environment jsdom
 */

/**
 * External dependencies
 */
import assert from 'assert'; // eslint-disable-line import/no-nodejs-modules
import { assign, isEqual } from 'lodash';
import { spy } from 'sinon';

/**
 * Internal dependencies
 */
import Dispatcher from 'dispatcher';

jest.mock( 'lib/user', () => () => {} );

describe( 'post-edit-store', () => {
        let PostEditStore, dispatcherCallback;

        beforeAll( () => {
                spy( Dispatcher, 'register' );
                PostEditStore = require( '../post-edit-store' );
                dispatcherCallback = Dispatcher.register.lastCall.args[ 0 ];
        } );

        afterAll( () => {
                Dispatcher.register.restore();
        } );

        function dispatchReceivePost() {
                dispatcherCallback( {
                        action: {
                                type: 'RECEIVE_POST_TO_EDIT',
                                post: {
                                        ID: 777,
                                        site_ID: 123,
                                        title: 'OMG Unicorns',
                                        categories: {
                                                Unicorns: {
                                                        ID: 199,
                                                        name: 'Unicorns',
                                                },
                                        },
                                },
                        },
                } );
        }

        test( 'initializes new draft post properly', () => {
                const siteId = 1234;

                dispatcherCallback( {
                        action: {
                                type: 'DRAFT_NEW_POST',
                                site: {
                                        ID: siteId,
                                },
                        },
                } );

                assert( PostEditStore.getSavedPost().ID === undefined );
                assert( PostEditStore.getSavedPost().site_ID === siteId );
                const post = PostEditStore.get();
                assert( post.status === 'draft' );
                assert( PostEditStore.isNew() );
        } );

        test( 'initialize existing post', () => {
                const siteId = 12,
                        postId = 345;

                dispatcherCallback( {
                        action: {
                                type: 'START_EDITING_POST',
                                siteId: siteId,
                                postId: postId,
                        },
                } );

                assert( ! PostEditStore.isNew() );
        } );

        test( 'sets parent_id properly', () => {
                dispatchReceivePost();
                const post = PostEditStore.get();
                assert( post.parent_id === null );
        } );

        test( 'decodes entities on received post title', () => {
                dispatcherCallback( {
                        action: {
                                type: 'DRAFT_NEW_POST',
                                title: 'Ribs &amp; Chicken',
                        },
                } );

                assert( PostEditStore.get().title === 'Ribs & Chicken' );
        } );

        test( 'updates parent_id after a set', () => {
                dispatchReceivePost();
                dispatcherCallback( {
                        action: {
                                type: 'EDIT_POST',
                                post: {
                                        parent: 101,
                                },
                        },
                } );

                const post = PostEditStore.get();
                assert( post.parent_id, 101 );
        } );

        test( 'does not decode post title entities on EDIT_POST', () => {
                dispatcherCallback( {
                        action: {
                                type: 'DRAFT_NEW_POST',
                        },
                } );

                dispatcherCallback( {
                        action: {
                                type: 'EDIT_POST',
                                post: {
                                        title: 'Ribs &gt; Chicken',
                                },
                        },
                } );

                assert( PostEditStore.get().title === 'Ribs &gt; Chicken' );
        } );

        test( 'decodes post title entities on RECEIVE_POST_BEING_EDITED', () => {
                dispatcherCallback( {
                        action: {
                                type: 'DRAFT_NEW_POST',
                        action: {
                                type: 'EDIT_POST',
                                post: initialPost,
                        },
                } );
                dispatcherCallback( {
                        action: {
                                type: 'EDIT_POST_SAVE',
                        },
                } );

                dispatcherCallback( {
                        action: {
                                type: 'EDIT_POST',
                                post: updates,
                        },
                } );
                dispatcherCallback( {
                        action: {
                                type: 'RECEIVE_POST_BEING_EDITED',
                                post: initialPost,
                        },
                } );

                assert( PostEditStore.get().content === updates.content );
                assert( PostEditStore.isDirty() );
        } );

        test( 'excludes metadata without an operation on edit', () => {
                const postEdits = {
                                title: 'Super Duper',
                                metadata: [
                                        { key: 'super', value: 'duper', operation: 'update' },
                                        { key: 'foo', value: 'bar', operation: 'delete' },
                                        { key: 'bar', value: 'foo' },
                                ],
                        },
                        expectedMetadata = [
                                { key: 'super', value: 'duper', operation: 'update' },
                                { key: 'foo', value: 'bar', operation: 'delete' },
                        ];

                dispatcherCallback( {
                        action: {
                                type: 'RECEIVE_POST_TO_EDIT',
                                post: {},
                        },
                } );

                dispatcherCallback( {
                        action: {
                                type: 'EDIT_POST',
                                post: postEdits,
                        },
                } );

                assert( PostEditStore.get().metadata === postEdits.metadata );
                assert( PostEditStore.get().title === postEdits.title );
                assert( PostEditStore.getChangedAttributes().title === postEdits.title );
                assert( isEqual( PostEditStore.getChangedAttributes().metadata, expectedMetadata ) );
        } );

        test( 'reset post after saving an edit', () => {
                const siteId = 1234,
                        postEdits = {
                                title: 'hello, world!',
                                content: 'initial edit',
                        };

                dispatcherCallback( {
                        action: {
                                type: 'DRAFT_NEW_POST',
                                site: {
                                        ID: siteId,
                                },
                        },
                } );

                dispatcherCallback( {
                        action: {
                                type: 'EDIT_POST',
                                post: postEdits,
                        },
                } );

                dispatcherCallback( {
                        action: {
                                type: 'RECEIVE_POST_BEING_EDITED',
                                post: assign( { ID: 1234 }, postEdits ),
                        },
                } );

                assert( PostEditStore.isNew() === false );
                assert( PostEditStore.getSavedPost().title === postEdits.title );
                assert( PostEditStore.getSavedPost().content === postEdits.content );
                assert( PostEditStore.get().title === postEdits.title );
                assert( PostEditStore.get().content === postEdits.content );
                assert( PostEditStore.getChangedAttributes().title === undefined );
                assert( PostEditStore.getChangedAttributes().content === undefined );
                assert( PostEditStore.getChangedAttributes().metadata === undefined );
        } );

        test( 'resets raw content when receiving an updated post', () => {
                dispatcherCallback( {
                        action: {
                                type: 'RECEIVE_POST_TO_EDIT',
                                post: { content: 'bar' },
                        },
                } );

                dispatcherCallback( {
                        action: {
                                type: 'EDIT_POST_RAW_CONTENT',
                                content: 'foo',
                        },
                } );

                dispatcherCallback( {
                        action: {
                                type: 'RECEIVE_POST_BEING_EDITED',
                                post: { content: 'bar' },
                        },
                } );

                assert( ! PostEditStore.isDirty() );
        } );

        test( 'resets raw content on RESET_POST_RAW_CONTENT', () => {
                dispatcherCallback( {
                        action: {
                                type: 'EDIT_POST_RAW_CONTENT',
                                content: 'foo',
                        },
                } );

                dispatcherCallback( {
                        action: {
                                type: 'EDIT_POST_RAW_CONTENT',
                                content: 'bar',
                        },
                } );

                dispatcherCallback( {
                        action: {
                                type: 'RESET_POST_RAW_CONTENT',
                        },
                } );

                assert( ! PostEditStore.isDirty() );
        } );

        describe( '#setRawContent', () => {
                test( "should not emit a change event if content hasn't changed", () => {
                        const onChange = spy();

                        dispatcherCallback( {
                                action: {
                                        type: 'RECEIVE_POST_TO_EDIT',
                                        post: {},
                                },
                        } );

                        PostEditStore.on( 'change', onChange );

                        dispatcherCallback( {
                                action: {
                                        type: 'EDIT_POST_RAW_CONTENT',
                                        content: 'foo',
                                },
                        } );

                        dispatcherCallback( {
                                action: {
                                        type: 'EDIT_POST_RAW_CONTENT',
                                        content: 'foo',
                                },
                        } );

                        PostEditStore.off( 'change', onChange );

                        assert( ! PostEditStore.isDirty() );
                        assert( onChange.callCount === 1 );
                } );
        } );

        describe( '#getChangedAttributes()', () => {
                test( 'includes status for a new post', () => {
                        dispatcherCallback( {
                                action: {
                                        type: 'DRAFT_NEW_POST',
                                        site: {
                                        key: 'foo',
                                },
                        } );

                        assert( PostEditStore.isSaveBlocked() === true );
                } );

                test( 'returns false if blocked but not by provided key', () => {
                        dispatcherCallback( {
                                action: {
                                        type: 'DRAFT_NEW_POST',
                                        site: {
                                                ID: 1,
                                        },
                                },
                        } );

                        dispatcherCallback( {
                                action: {
                                        type: 'BLOCK_EDIT_POST_SAVE',
                                        key: 'foo',
                                },
                        } );

                        assert( PostEditStore.isSaveBlocked( 'bar' ) === false );
                } );

                test( 'returns true if blocked by provided key', () => {
                        dispatcherCallback( {
                                action: {
                                        type: 'DRAFT_NEW_POST',
                                        site: {
                                                ID: 1,
                                        },
                                },
                        } );

                        dispatcherCallback( {
                                action: {
                                        type: 'BLOCK_EDIT_POST_SAVE',
                                        key: 'foo',
                                },
                        } );

                        assert( PostEditStore.isSaveBlocked( 'foo' ) === true );
                } );
        } );

        describe( '#hasContent()', () => {
                test( 'returns false for new post', () => {
                        dispatcherCallback( {
                                action: {
                                        type: 'DRAFT_NEW_POST',
                                        site: {
                                                ID: 1,
                                        },
                                },
                        } );

                        assert( PostEditStore.hasContent() === false );
                } );

                test( 'returns true if title is set', () => {
                        dispatcherCallback( {
                                action: {
                                        type: 'DRAFT_NEW_POST',
                                        site: {
                                          <response clipped><NOTE>Due to the max output limit, only part of the full response has been shown to you.</NOTE>                                      841: {
                                                                        parent: 10,
                                                                },
                                                        },
                                                },
                                        },
                                },
                                2916284,
                                841
                        );

                        expect( isDirty ).to.be.true;
                } );

                test( "should return false if saved post parent attr doesn't change", () => {
                        const isDirty = isEditedPostDirty(
                                {
                                        posts: {
                                                queries: {
                                                        2916284: new PostQueryManager( {
                                                                items: {
                                                                        841: {
                                                                                ID: 841,
                                                                                site_ID: 2916284,
                                                                                global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64',
                                                                                parent: {
                                                                                        ID: 10,
                                                                                },
                                                                        },
                                                                },
                                                        } ),
                                                },
                                                edits: {
                                                        2916284: {
                                                                841: {
                                                                        parent: 10,
                                                                },
                                                        },
                                                },
                                        },
                                },
                                2916284,
                                841
                        );

                        expect( isDirty ).to.be.false;
                } );

                test( 'should return true if saved post date changes', () => {
                        const isDirty = isEditedPostDirty(
                                {
                                        posts: {
                                                queries: {
                                                        2916284: new PostQueryManager( {
                                                                items: {
                                                                        841: {
                                                                                ID: 841,
                                                                                site_ID: 2916284,
                                                                                global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64',
                                                                                date: moment( '2016-09-14T15:47:33-04:00' ),
                                                                        },
                                                                },
                                                        } ),
                                                },
                                                edits: {
                                                        2916284: {
                                                                841: {
                                                                        date: moment( '2017-09-14T15:47:33-04:00' ),
                                                                },
                                                        },
                                                },
                                        },
                                },
                                2916284,
                                841
                        );

                        expect( isDirty ).to.be.true;
                } );

                test( "should return false if saved post date doesn't change", () => {
                        const isDirty = isEditedPostDirty(
                                {
                                        posts: {
                                                queries: {
                                                        2916284: new PostQueryManager( {
                                                                items: {
                                                                        841: {
                                                                                ID: 841,
                                                                                site_ID: 2916284,
                                                                                global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64',
                                                                                date: moment( '2016-09-14T15:47:33-04:00' ),
                                                                        },
                                                                },
                                                        } ),
                                                },
                                                edits: {
                                                        2916284: {
                                                                841: {
                                                                        date: moment( '2016-09-14T15:47:33-04:00' ),
                                                                },
                                                        },
                                                },
                                        },
                                },
                                2916284,
                                841
                        );

                        expect( isDirty ).to.be.false;
                } );

                test( 'should return true if discussion options change', () => {
                        const isDirty = isEditedPostDirty(
                                {
                                        posts: {
                                                queries: {
                                                        2916284: new PostQueryManager( {
                                                                items: {
                                                                        841: {
                                                                                ID: 841,
                                                                                site_ID: 2916284,
                                                                                global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64',
                                                                                discussion: {
                                                                                        comment_status: 'open',
                                                                                        comments_open: true,
                                                                                        ping_status: 'open',
                                                                                        pings_open: true,
                                                                                },
                                                                        },
                                                                },
                                                        } ),
                                                },
                                                edits: {
                                                        2916284: {
                                                                841: {
                                                                        discussion: {
                                                                                comment_status: 'closed',
                                                                                ping_status: 'open',
                                                                        },
                                                                },
                                                        },
                                                },
                                        },
                                },
                                2916284,
                                841
                        );

                        expect( isDirty ).to.be.true;
                } );

                test( "should return false if discussion options didn't change", () => {
                        const isDirty = isEditedPostDirty(
                                {
                                        posts: {
                                                queries: {
                                                        2916284: new PostQueryManager( {
                                                                items: {
                                                                        841: {
                                                                                ID: 841,
                                                                                site_ID: 2916284,
                                                                                global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64',
                                                                                discussion: {
                                                                                        comment_status: 'open',
                                                                                        comments_open: true,
                                                                                        ping_status: 'open',
                                                                                        pings_open: true,
                                                                                },
                                                                        },
                                                                },
                                                        } ),
                                                },
                                                edits: {
                                                        2916284: {
                                                                841: {
                                                                        discussion: {
                                                                                comment_status: 'open',
                                                                                ping_status: 'open',
                                                                        },
                                                                },
                                                        },
                                                },
                                        },
                                },
                                2916284,
                                841
                        );

                        expect( isDirty ).to.be.false;
                } );

                test( "should return false if author ID didn't change", () => {
                        const isDirty = isEditedPostDirty(
                                {
                                        posts: {
                                                queries: {
                                                        2916284: new PostQueryManager( {
                                                                items: {
                                                                        841: {
                                                                                ID: 841,
                                                                                site_ID: 2916284,
                                                                                global_ID: '3d097cb7c5473c169bba0eb8e3c6cb64',
                                                                                author: {
                                                                                        ID: 123,
                                                                                        name: 'Robert Trujillo',
                                                                                },
                                                                        },
                                                                },
                                                        } ),
                                                },
                                                edits: {
                                                        2916284: {
                                                                841: {
                                                                        author: {
                                                                                ID: 123,
                                                                                name: 'Bob Trujillo',
                                                                        },
                                                                },
                                                        },
                                                },
                                        },
                                },
                                2916284,
                                841
                        );

                        expect( isDirty ).to.be.false;
                } );
        } );

        describe( 'getPostPreviewUrl()', () => {
                test( 'should return null if the post is not known', () => {
                        const previewUrl = getPostPreviewUrl(
                                {
                                        ...userState,
                                        posts: {
                                                queries: {},
                                        },
                                        sites: {
[The command completed with exit code 0.]
[Current working directory: /workspace/wp-calypso]
[Python interpreter: /usr/bin/python]
[Command finished with exit code 0]