/// <reference types="cypress" />

const showSidePanelContent = () => {
  cy.get('[data-testid=profileSidePanel] h4').should('have.text', 'Test User1');
  cy.get('[data-testid=profileSidePanel] .modal-body').first().within(() => {
    cy.contains('Location: Denver, CO, US')
      .and('contain', 'Skill Level: Professional')
      .and('contain', 'Joined JamKazam: 08-26-2021')
      .and('contain', 'Last Active:')
      .and('contain', 'Latency To Me:');
    cy.get('.latency-badge').contains('UNKNOWN');

    cy.get('[data-testid=biography]').contains('Biography of Test User1');

    //instruments
    cy.get('[data-testid=instruments]').contains('Acoustic Guitar: Expert');
    cy.get('[data-testid=instruments]').contains('Keyboard: Expert');

    //genres
    cy.get('[data-testid=genres]').contains('classical, blues');

    //bands
    cy.get('[data-testid=bands]').contains('The Band');

    //performance_samples
    cy.get('[data-testid=performance_samples]').contains('Test Recording1')//.should('have.attr', 'href').and('eq', 'https://www.jamkazam.com/test-recording1');

    //online presence
    cy.get('[data-testid=online_presences]').contains('Youtube').should('have.attr', 'href').and('eq', 'https://www.youtube.com/testuser');
    cy.get('[data-testid=online_presences]').contains('Facebook').should('have.attr', 'href').and('eq', 'https://www.facebook.com/testuser');
    cy.get('[data-testid=online_presences]').contains('Twitter').should('have.attr', 'href').and('eq', 'https://www.twitter.com/testuser');
  });

};

const closeSidePanel = () => {
  cy.get('[data-testid=profileSidePanel] .modal-header button.close').click();
};

describe('Friends page without data', () => {
  beforeEach(() => {
    cy.stubAuthenticate();
    cy.intercept('POST', /\S+\/filter/, {
      musicians: []
    }).as("getPeople_empty");
  });

  //from_location checkbox is hidden for now. so we skip this test for now
  it.skip('from_location is unchecked', () => {
    cy.visit('/friends');

    //default api call with from_location parameter turned off
    cy.wait('@getPeople_empty')
    .then(interception => {
      assert.isNotNull(interception.response.body, '1st API call');
    })
    .its('request.body')
    .should('deep.contain', {
      from_location: false
    });

    //now it automatically turns on from_location parameter and fetches again
    cy.wait('@getPeople_empty')
    .then(interception => {
      assert.isNotNull(interception.response.body, '2nd API call - (prefetched)');
    })
    .its('request.body')
    .should('deep.contain', {
      from_location: true
    });

    cy.contains('No Records!');

    cy.get('[data-testid=btnUpdateSearch]').click();
    cy.get('[data-testid=modalUpdateSearch] input[name=from_location]').check();
    cy.wait(1000);
    cy.get('[data-testid=btnSubmitSearch]').click();

    //default api call with from_location parameter turned on
    cy.wait('@getPeople_empty')
    .then(interception => {
      assert.isNotNull(interception.response.body, '3th API call');
    })
    .its('request.body')
    .should('deep.contain', {
      from_location: true
    });

    cy.contains('No Records!');

  });


});

describe('Friends page with data', () => {
  beforeEach(() => {
    cy.stubAuthenticate({ id: '2' }); //currentUser id is 2 - people.yaml fixture
    cy.intercept('POST', /\S+\/filter\?offset=0/, { fixture: 'people_page1' }).as('getPeople_page1');
    cy.intercept('POST', /\S+\/filter\?offset=10/, { fixture: 'people_page2' }).as('getPeople_page2');
    cy.intercept('POST', /\S+\/filter\?offset=20/, { fixture: 'people_page3' }).as('getPeople_page3');
    cy.intercept('GET', /\S+\/profile/, { fixture: 'person' });
    cy.intercept('GET', /\S+\/my_notifications\S+/, {
      statusCode: 200,
      body: []
    });
  });

  describe('listing users', () => {
    beforeEach(() => {
      cy.visit('/friends');
    });

    describe('in desktop', () => {
      beforeEach(() => {
        cy.viewport('macbook-13');
      });

      it('paginate', () => {
        cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 10);
        cy.wait('@getPeople_page2')
        cy.get('[data-testid=paginate-next-page]').click();
        cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 20);
        cy.get('[data-testid=paginate-next-page]').click();
        cy.get('[data-testid=peopleListTable] > tbody tr').should('have.length', 30);
        cy.get('[data-testid=paginate-next-page]').should('not.exist');
      });

      it('show profiles', () => {
        cy.contains('Find New Friends').should('exist');
        cy.contains('Update Search').should('exist');
        cy.contains('Reset Filters').should('exist');
        cy.get('[data-testid=peopleListTable] > tbody tr')
          .should('have.length', 10)
          .first()
          .contains('Test User1');
      });

      it('click profile name', () => {
        //open side panel by clicking name
        cy.get('[data-testid=peopleListTable]').find('.person-link').first().within(() => {
          cy.contains("Test User1").click()
        })
        //cy.get('[data-testid=peopleListTable]').find('.person-link').first().click()
        showSidePanelContent();
        closeSidePanel();
      });

      it('click more button', () => {
        //open side panel by clicking more button
        cy.get('[data-testid=peopleListTable] > tbody tr')
          .first()
          .find('[data-testid=btnMore]')
          .click();
        showSidePanelContent();
        closeSidePanel();
      });

      it('click more link', () => {
        //open side panel by clicking more link
        cy.get('[data-testid=peopleListTable] > tbody tr')
          .first()
          .find('[data-testid=linkMore]')
          .click();
        showSidePanelContent();
        closeSidePanel();
      });

      it('click description more link', () => {
        cy.get('[data-testid=peopleListTable] > tbody tr')
          .first()
          .find('td[data-testid=biography-col]')
          .within(() => {
            cy.contains('More').click();
          });
        showSidePanelContent();
        closeSidePanel();
      });

      it('click instruments more link', () => {
        cy.get('[data-testid=peopleListTable] > tbody tr')
          .first()
          .find('[data-testid=instrumentList]')
          .within(() => {
            cy.get('[data-testid=instrument]').should('have.length', 4); //show only 4 instruments plus more link
            cy.contains('Acoustic Guitar: Expert');
            cy.contains('Keyboard: Expert');
            cy.contains('Ukulele: Expert');
            cy.contains('Voice: Expert');
            cy.contains('More').click();
          });
        showSidePanelContent();
        closeSidePanel();
      });

      it('click genres more link', () => {
        cy.get('[data-testid=peopleListTable] > tbody tr')
          .first()
          .find('td[data-testid=genres-col]')
          .within(() => {
            cy.contains('More').click();
          });
        showSidePanelContent();
        closeSidePanel();
      });

      
    });

    describe('in mobile', () => {
      beforeEach(() => {
        cy.viewport('iphone-6');
      });

      it('show profile', () => {
        cy.get('[data-testid=peopleSwiper] .swiper-slide').should('have.length', 10);
        cy.get('[data-testid=peopleSwiper] .swiper-slide')
          .eq(0)
          .contains('Test User1');
        cy.get('[data-testid=peopleSwiper] .swiper-slide')
          .eq(0)
          .should('be.visible');
        cy.get('[data-testid=peopleSwiper] .swiper-slide')
          .eq(2)
          .should('not.be.visible');
      });

      it('show all profile description', () => {
        cy.get('[data-testid=peopleSwiper] .swiper-slide')
          .first()
          .find('[data-testid=mobBiography]')
          .should('not.contain', 'More');
      });

      it('show all instruments', () => {
        cy.get('[data-testid=peopleSwiper] .swiper-slide')
          .first()
          .find('[data-testid=instrumentList] div')
          .its('length')
          .should('be.gte', 1);
        cy.get('[data-testid=peopleSwiper] .swiper-slide')
          .first()
          .find('[data-testid=instrumentList]')
          .should('not.contain', 'More');
      });

      it('show all genres', () => {
        cy.get('[data-testid=peopleSwiper] .swiper-slide')
          .first()
          .find('[data-testid=genreList] div')
          .its('length')
          .should('be.gte', 1);
        cy.get('[data-testid=peopleSwiper] .swiper-slide')
          .first()
          .find('[data-testid=genreList]')
          .should('not.contain', 'More');
      });

      //it.skip('click connect button', () => {});

      //it.skip('click message button', () => {});

      it.skip('paginate', () => {
        cy.get('[data-testid=peopleSwiper] .swiper-button-prev').should('have.class', 'swiper-button-disabled');
        for (let i = 0; i < 19; i++) {
          cy.get('[data-testid=peopleSwiper] .swiper-button-next').click();
          cy.wait(500);
        }
        cy.wait(500);
        cy.get('[data-testid=peopleSwiper] .swiper-button-next').should('have.class', 'swiper-button-disabled');
      });

      it('click more button', () => {
        cy.get('[data-testid=peopleSwiper] .swiper-slide')
          .first()
          .find('[data-testid=btnMore]')
          .click();
        showSidePanelContent();
        closeSidePanel();
      });
    });
  });

  describe('making friendship', () => {
    it('add friend', () => {
      cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
      cy.intercept('POST', /\S+\/friend_requests/, { statusCode: 201, body: { ok: true } });

      cy.visit('/friends');
      cy.contains('Test User2').click();

      cy.get('[data-testid=profileSidePanel]')
        .find('[data-testid=connect]')
        .should('not.be.disabled')
        .click();
      // cy.get('[data-testid=confirmFriendRequestModal]').within(() => {
      //   cy.contains('Send a friend request to Test User2');
      //   cy.contains('Yes').click();
      // });

      cy.get('[data-testid=profileSidePanel]')
        .find('[data-testid=connect]')
        .should('be.disabled');
      cy.contains('Success! Your friend request has been sent to Test User2.');
    });

    it('remove friend', () => {
      cy.intercept('GET', /\S+\/profile/, { fixture: 'friend' });
      cy.intercept('DELETE', /\S+\/friends\S+/, { statusCode: 204, body: { ok: true } });

      cy.visit('/friends');
      cy.contains('Test User1').click();

      cy.get('[data-testid=profileSidePanel]')
        .find('[data-testid=disconnect]')
        .should('exist')
        .should('not.be.disabled')
        .click();

      cy.get('[data-testid=profileSidePanel]')
        .find('[data-testid=disconnect]')
        .should('not.exist');

      cy.get('[data-testid=profileSidePanel]')
        .find('[data-testid=connect]')
        .should('be.exist')
        .should('not.be.disabled');
    });
  });

  describe('chat window', () => {
    beforeEach(() => {
      cy.visit('/friends');
    });

    it('is not disabled for friends', () => {
      cy.get('[data-testid=peopleListTable] > tbody tr')
        .eq(0)
        .find('[data-testid=message]')
        .should('not.be.disabled')
        .trigger('mouseover');
      cy.contains('Send a message').should('exist');
    });

    it('is not disabled for non friends', () => {
      cy.get('[data-testid=peopleListTable] > tbody tr')
        .eq(1)
        .find('[data-testid=message]')
        .should('not.be.disabled');
      //cy.contains('You can message this user once you are friends').should('exist')
    });

    it('lists text messages', () => {
      //initially show the most recent messages on openning chat window modal
      let numberOfMessages = 10;
      cy.fixture('text_messages_page1').then(json => {
        cy.intercept('GET', /\S+\/text_messages\S+/, json).as('getTextMessages');
      });
      cy.get('[data-testid=peopleListTable] > tbody tr')
        .eq(0)
        .find('[data-testid=message]')
        .click();
      cy.wait('@getTextMessages');
      cy.get('[data-testid=textMessageModal]')
        .should('be.visible')
        .within(() => {
          cy.get('.text-message-row').should('have.length', numberOfMessages);

          //display previous messages by scrolling up
          const messageFixtures = ['text_messages_page2', 'text_messages_page3'];
          messageFixtures.forEach(fixture => {
            cy.fixture(fixture).then(json => {
              cy.intercept('GET', /\S+\/text_messages\S+/, json);
              cy.get('.modal-body .ScrollbarsCustom-Scroller')
                .trigger('mouseover')
                .scrollTo('bottom');
              cy.get('.modal-body .ScrollbarsCustom-Scroller')
                .trigger('mouseover')
                .scrollTo('top');
              numberOfMessages = numberOfMessages + 10;
              cy.get('.text-message-row').should('have.length', numberOfMessages);
            });
          });

          cy.get('button')
            .contains('Close')
            .should('not.be.disabled')
            .click();
        });
      cy.get('[data-testid=textMessageModal]').should('not.be.visible');
    });

    it('sends message by clicking send button', () => {
      cy.get('[data-testid=peopleListTable] > tbody tr')
        .eq(0)
        .find('[data-testid=message]')
        .click();
      cy.get('[data-testid=textMessageModal]').within(() => {
        cy.get('button')
          .contains('Send')
          .should('be.disabled');
        cy.get('textarea').type('Hello');
        cy.get('button')
          .contains('Send')
          .should('not.be.disabled')
          .click();
        cy.get('textarea').should('have.value', '');
        cy.get('button')
          .contains('Send')
          .should('be.disabled');
      });
    });

    it('sends message by pressing enter key', () => {
      cy.get('[data-testid=peopleListTable] > tbody tr')
        .eq(0)
        .find('[data-testid=message]')
        .click();
      cy.get('[data-testid=textMessageModal]').within(() => {
        cy.get('button')
          .contains('Send')
          .should('be.disabled');
        cy.get('textarea').type('Hello{enter}');
        cy.get('textarea').should('have.value', '');
        cy.get('button')
          .contains('Send')
          .should('be.disabled');
      });
    });

    it('goes away by clicking close button', () => {
      cy.get('[data-testid=peopleListTable] > tbody tr')
        .eq(0)
        .find('[data-testid=message]')
        .click();
      cy.get('[data-testid=textMessageModal]').within(() => {
        cy.get('button')
          .contains('Close')
          .should('not.be.disabled')
          .click();
      });
      cy.get('[data-testid=textMessageModal]').should('not.be.visible');
    });

    it.skip('shows received message by other user', () => {
      //TODO: this should be test in e2e test
    });
  });

  describe('coming from email links', () => { 
    it("opens details sidebar", () => {
      cy.visit('/friends?open=details&id=1');
      showSidePanelContent();
    });
    
    it("opens chat window", () => {
      cy.visit('/friends?open=message&id=1');
      cy.get('[data-testid=textMessageModal]')
        .should('be.visible')
      cy.contains('Send Message to Test User1').should('exist');
    });
    
    it("sends friend request", () => {
      cy.intercept('GET', /\S+\/profile\S+/, { fixture: 'person' });
      cy.intercept('POST', /\S+\/friend_requests/, { statusCode: 201, body: { ok: true } });
      cy.visit('/friends?open=connect&id=1');
      cy.get('[data-testid=profileSidePanel]')
        .find('[data-testid=connect]')
        .should('be.disabled');
      cy.contains('Success! Your friend request has been sent to Test User1.');
    }); 

   })

  describe('filter', () => {
    const fillFilterForm = () => {
      //cy.get('[data-testid=btnUpdateSearch]').click();
      cy.get('[data-testid=modalUpdateSearch] input[name=latency_good]').uncheck();
      cy.get('[data-testid=modalUpdateSearch] input[name=latency_fair]').uncheck();
      cy.get('[data-testid=modalUpdateSearch] input[name=latency_high]').uncheck();
      cy.get('[data-testid=modalUpdateSearch] input[name=proficiency_beginner]').uncheck();
      cy.get('[data-testid=modalUpdateSearch] input[name=proficiency_intermediate]').uncheck();
      cy.get('[data-testid=modalUpdateSearch] input[name=proficiency_expert]').uncheck();
      cy.get('[data-testid=modalUpdateSearch] input[name=proficiency_expert]').uncheck();
      cy.get('[data-testid=modalUpdateSearch] input[name=from_location]').uncheck();
      cy.get('#selInstruments')
        .type('Drums{enter}')
        .click();
      cy.get('#selGenres')
        .type('Pop{enter}')
        .click();
      cy.get('#selLastActive').type('Within last 1 Day{enter}');
      cy.get('#selJoinedWithin').type('Within last 7 Day{enter}');
    };

    beforeEach(() => {
      cy.visit('/friends');
    });

    it('open and close filter modal', () => {
      cy.get('[data-testid=btnUpdateSearch]').click();
      cy.get('[data-testid=modalUpdateSearch]').should('be.visible');
      cy.get('[data-testid=modalUpdateSearch]')
        .contains('Cancel')
        .click();
      cy.get('[data-testid=modalUpdateSearch]').should('not.be.visible');
    });

    it('render filter form', () => {
      cy.get('[data-testid=btnUpdateSearch]').click();
      cy.get('[data-testid=modalUpdateSearch]').within(() => {
        cy.get('input[name=latency_good]')
          .should('be.checked')
          .next()
          .contains('Good (less than 40ms)');
        cy.get('input[name=latency_fair]')
          .should('be.checked')
          .next()
          .contains('Fair (40-60ms)');
        cy.get('input[name=latency_high]')
          .should('not.be.checked')
          .next()
          .contains('Poor (more than 60ms)');
        cy.get('input[name=from_location]')
          .should('not.be.checked')
      });
    });

    it('reset filters', () => {
      cy.get('[data-testid=btnUpdateSearch]').click();
      fillFilterForm();
      cy.get('[data-testid=modalUpdateSearch]')
        .contains('Cancel')
        .click();
      cy.get('[data-testid=btnUpdateSearch]').click();
      cy.get('[data-testid=modalUpdateSearch] input[name=latency_good]').should('not.be.checked');
      cy.get('[data-testid=modalUpdateSearch]')
        .contains('Cancel')
        .click();
      cy.get('[data-testid=btnResetSearch]').click(); //click reset button
      cy.get('[data-testid=btnUpdateSearch]').click();
      cy.get('[data-testid=modalUpdateSearch] input[name=latency_good]').should('be.checked');
    });

    it('submit filter form with params', () => {
      //wait for stubbed request sent to fetch data for initial page load
      cy.wait('@getPeople_page1').then(interception => {
        assert.isNotNull(interception.response.body, '1st API call has data');
      });
      //the subsequent request sent to perfetch data and store in redux prefetched buffer
      cy.wait('@getPeople_page2').then(interception => {
        assert.isNotNull(interception.response.body, '1st API call has data - (prefethed)');
      });

      cy.get('[data-testid=btnUpdateSearch]').click();
      cy.wait(1000);
      cy.get('[data-testid=btnSubmitSearch]').click();
      
      //wait for stubbed request sent by submitting search form without filling any form field
      cy.wait('@getPeople_page1')
        .then(interception => {
          assert.isNotNull(interception.response.body, '3rd API call has data');
        })
        .its('request.body')
        .should('deep.contain', {
          latency_good: true,
          latency_fair: true,
          latency_high: false,
          proficiency_beginner: true,
          proficiency_intermediate: true,
          proficiency_expert: true,
          instruments: [],
          genres: [],
          from_location: false
        });

      cy.wait('@getPeople_page2').then(interception => {
        assert.isNotNull(interception.response.body, '4th API call has data - (prefethed)');
      });

      cy.get('[data-testid=btnUpdateSearch]').click();
      fillFilterForm(); // change filter options
      cy.get('[data-testid=btnSubmitSearch]').click();

      //wait for stubbed request sent by submitting search form again. but this time fill form fields
      cy.wait('@getPeople_page1')
        .then(interception => {
          assert.isNotNull(interception.response.body, '5th API call has data');
        })
        .its('request.body')
        .should('deep.contain', {
          latency_good: false,
          latency_fair: false,
          latency_high: false,
          proficiency_beginner: false,
          proficiency_intermediate: false,
          proficiency_expert: false,
          instruments: [{ value: 'drums', label: 'Drums' }],
          genres: ['pop'],
          from_location: false
        });

      cy.wait('@getPeople_page2').then(interception => {
        assert.isNotNull(interception.response.body, '6th API call has data - (prefethed)');
      });

    });
  });


});
