/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import fetchMock from 'fetch-mock';
import { isFeatureEnabled } from '@superset-ui/core';
import {
  render,
  screen,
  act,
  userEvent,
  waitFor,
} from 'spec/helpers/testing-library';
import ShareSqlLabQuery from 'src/SqlLab/components/ShareSqlLabQuery';
import { initialState } from 'src/SqlLab/fixtures';
import { omit } from 'lodash';

const mockStore = configureStore([thunk]);
const defaultProps = {
  queryEditorId: 'qe1',
  addDangerToast: jest.fn(),
};
const mockQueryEditor = {
  id: defaultProps.queryEditorId,
  dbId: 0,
  name: 'query title',
  schema: 'query_schema',
  autorun: false,
  sql: 'SELECT * FROM ...',
  remoteId: 999,
};
const disabled = {
  id: 'disabledEditorId',
  remoteId: undefined,
};

const mockState = {
  ...initialState,
  sqlLab: {
    ...initialState.sqlLab,
    queryEditors: [mockQueryEditor, disabled],
  },
};
const store = mockStore(mockState);

jest.mock('@superset-ui/core', () => ({
  ...jest.requireActual('@superset-ui/core'),
  isFeatureEnabled: jest.fn(),
}));

const mockedIsFeatureEnabled = isFeatureEnabled as jest.Mock;

const unsavedQueryEditor = {
  id: defaultProps.queryEditorId,
  dbId: 9888,
  name: 'query title changed',
  schema: 'query_schema_updated',
  sql: 'SELECT * FROM Updated Limit 100',
  autorun: true,
  templateParams: '{ "my_value": "foo" }',
};

describe('ShareSqlLabQuery', () => {
  const storeQueryUrl = 'glob:*/api/v1/sqllab/permalink';
  const storeQueryMockId = 'ci39c3';

  beforeEach(async () => {
    fetchMock.post(
      storeQueryUrl,
      () => ({ key: storeQueryMockId, url: `/p/${storeQueryMockId}` }),
      {
        overwriteRoutes: true,
      },
    );
    fetchMock.resetHistory();
    jest.clearAllMocks();
  });

  afterAll(() => fetchMock.reset());

  describe('via permalink api', () => {
    beforeAll(() => {
      mockedIsFeatureEnabled.mockImplementation(() => true);
    });

    afterAll(() => {
      mockedIsFeatureEnabled.mockReset();
    });

    it('calls storeQuery() with the query when getCopyUrl() is called', async () => {
      await act(async () => {
        render(<ShareSqlLabQuery {...defaultProps} />, {
          useRedux: true,
          store,
        });
      });
      const button = screen.getByRole('button');
      const expected = omit(mockQueryEditor, ['id', 'remoteId']);
      userEvent.click(button);
      await waitFor(() =>
        expect(fetchMock.calls(storeQueryUrl)).toHaveLength(1),
      );
      expect(
        JSON.parse(fetchMock.calls(storeQueryUrl)[0][1]?.body as string),
      ).toEqual(expected);
    });

    it('calls storeQuery() with unsaved changes', async () => {
      await act(async () => {
        render(<ShareSqlLabQuery {...defaultProps} />, {
          useRedux: true,
          store: mockStore({
            ...initialState,
            sqlLab: {
              ...initialState.sqlLab,
              unsavedQueryEditor,
            },
          }),
        });
      });
      const button = screen.getByRole('button');
      const expected = omit(unsavedQueryEditor, ['id']);
      userEvent.click(button);
      await waitFor(() =>
        expect(fetchMock.calls(storeQueryUrl)).toHaveLength(1),
      );
      expect(
        JSON.parse(fetchMock.calls(storeQueryUrl)[0][1]?.body as string),
      ).toEqual(expected);
    });
  });
});
